极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 36568|回复: 6

我的红外传感器避障小车&&改进的过程

[复制链接]
发表于 2013-9-22 22:27:42 | 显示全部楼层 |阅读模式
本帖最后由 tom 于 2013-9-22 22:34 编辑

我的红外传感器避障小车&&改进的过程

简单的避障小车程序
使用材料
小车套件1
3MM铜螺柱若干
Microduino core 8M 3.3V (相当于Arduino uno)
自制的L298N全光耦隔离驱动板
(每个电机用两个端口控制)
三个红外感应传感器
连接线若干
两节18650的电池盒
锂电池一块3.7V向arduino供电
18650电池两个向L298N驱动板供电。
安装螺丝 螺母
小车套件图片


L298N图片

在使能端那里,再用相同结构的光耦隔离,由于使能端只有两个接两组光耦就够了。

在使能端那里连接好光耦的另一端


Microduino core 8M 3.3V


红外避障传感器


已经测试通过。

本程序根据OPENJumper的程序改编
通过环境Arduino IDE V1.02
以下是Arduino代码:
  1. /*
  2. 这是自制电机驱动,的避障小车的测试电机的程序
  3. */
  4. /*由于使用能端用了光耦隔离,使能端的取值范围是-255~255。但输出那一端,却造成的效果是相反的。
  5. //相当于使能端的0对应255 ,它本应对应速度为0,实际是速度的0最大值。使能端255却对应速度为0的效果。
  6. //为了减小电机的速度 motosp(250,250)比较合适。

  7. */
  8. int IN1=4;
  9. int IN2=5;
  10. int IN3=6;
  11. int IN4=7;

  12. int PWMA=10;//使能端口1
  13. int PWMB=11;//使能端口2
  14. //数字端口4与5为一组,6与7为另一组
  15. //数字端口10 11 作为直流电机的使能端

  16. //定义三个红外传感器接口
  17. //左边的在第13号,中间的在12号,右边的3号数字端口
  18. int snum[3];//三个红外传感器

  19. void stopMotor(boolean r)//电机停转
  20. {
  21.   if (r)
  22.   {
  23.     analogWrite(PWMA,255);
  24.     analogWrite(PWMB,255);
  25.   }
  26.   else
  27.   {
  28.     analogWrite(PWMA,0);
  29.     analogWrite(PWMB,0);
  30.   }
  31. }

  32. void setup()
  33. {
  34.   int i;


  35.   for (i=4;i<=7;i++) //为Ardunio 电机驱动板
  36.     pinMode(i,OUTPUT); //设置数字端口4,5,6,7为输出模式

  37.   for (i=4;i<=7;i++)
  38.     digitalWrite(i,OUTPUT); //设置数字端口4,5,6,7为HIGH,电机保持不动


  39.   pinMode(10,OUTPUT);//设置数字端口10  11为输出模式
  40.   pinMode(11,OUTPUT);

  41.   //设置三个红外传感器端口为输入模式
  42.   pinMode(3,INPUT);
  43.   pinMode(12,INPUT);
  44.   pinMode(13,INPUT);

  45.   Serial.begin(9600);

  46. }

  47. void loop()
  48. {
  49.   dd();//避障过程函数
  50. }



  51. void motosp(int sp1, int sp2)
  52. //声明电机速度控制函数。
  53. //括号内定义的变量分别为左右电机速度值,范围-255~+255,正值为正转,负值 为反转
  54. {

  55.   if (sp1>=0)
  56.   {
  57.     digitalWrite(IN1,HIGH);
  58.     digitalWrite(IN2,LOW);
  59.   }
  60.   else
  61.   {
  62.     digitalWrite(IN1,LOW);
  63.     digitalWrite(IN2,HIGH);
  64.   }

  65.   if (sp2>=0)
  66.   {
  67.     digitalWrite(IN3,HIGH);
  68.     digitalWrite(IN4,LOW);
  69.   }
  70.   else
  71.   {
  72.     digitalWrite(IN3,LOW);
  73.     digitalWrite(IN4,HIGH);
  74.   }
  75.   analogWrite(PWMA,abs(sp1));
  76.   analogWrite(PWMB,abs(sp2));
  77. }

  78. void dd(void) //避障过程
  79. {
  80.   snum[0]=digitalRead(13); //这三个依次为右中左红外传感器
  81.   snum[1]=digitalRead(3);
  82.   snum[2]=digitalRead(12);


  83.   if ((snum[0]==1) && snum[1]==1 && snum[2]==1) //所有传感器都没有检测到障碍物

  84.   {
  85.     motosp(100,100);//直行
  86.   }


  87.   if (snum[0]==0 && (snum[1]==1) && snum[2]==1) //右边传感器检测到障碍物
  88.   {
  89.     motosp(0,255);//向左转
  90.   }

  91.   if (snum[0]==1 && snum[1]==1 && (snum[2]==0))   //左边传感器检测到障碍物
  92.   {
  93.     motosp(255,0  );//小车向右转
  94.   }
  95.   if (( snum[0]==1 && snum[1]==0 && (snum[2])==1) )//如果中间传感检测到障碍物
  96.   {
  97.     motosp(0,255);   //向左转 默认
  98.     //由于不管如何设置一个轮子的最小速度和另一个轮子的最大速度,它的拐弯太小,而且还要向前走很长距离
  99.     //所以设置一个轮子不转,另一个轮子转。
  100.   }
  101.   delay(50);
  102. }

  103. void aa(void) //拐弯小程序
  104. {
  105.   int i,j;
  106.   i=250,j=254;
  107.   motosp(250,254);//向左拐弯

  108.   //经测试这个拐弯很小,不顶事
  109. }
复制代码
后记:作为一个简单的避障小车是成功的。但也有一些缺点,比如障碍物的高度必须与红外传感器相同,否则探测不到。还有如果小车被想挡住,它仍然会按照默认的向左转。小车不知道它被挡住了。如果能有变量或传感器判断它是否会挡住了,就能避开这个问题。


改进之一:
由于小车拐弯后还有可能会和前方的障碍物靠在一起,小车的力距比较小,可能无法摆脱前方的障碍物。因此将前面的红外传感器探测到障碍时,先后退再向左拐弯。

为了方便阅读将这些功能代码定义为backleft();
代码如下:
void backleft(void) //退后,再向左拐弯
{
  //为解决振动问题,需要引入一个变量判断这个退后向左拐弯过程未结束,不能再次接受其它信号

  //先退后一段距离,再拐弯
  motosp(-10,-10); //退后
  delay(50);

  motosp(250,250);
  delay(5);

  motosp(0,255);//向左拐弯
  delay(50);
}


完整的Arduino代码
  1. /*
  2. 这是自制电机驱动板,三个红外传感器的避障小车的测试电机的程序
  3. */
  4. /*由于使用能端用了光耦隔离,使能端的取值范围是-255~255。但输出那一端,却造成的效果是相反的。
  5. //相当于使能端的0对应255 ,它本应对应速度为0,实际是速度的0最大值。使能端255却对应速度为0的效果。
  6. //为了减小电机的速度 motosp(250,250)比较合适。
  7. //已经测试通过
  8. */

  9. //为了减少避障可能撞到墙壁,在中间的探测到障碍物时先后退,再向左拐弯。但有个缺点,右边的轮子同时向前和向后,引起的震动。


  10. int IN1=4;
  11. int IN2=5;
  12. int IN3=6;
  13. int IN4=7;

  14. int PWMA=10;//使能端口1
  15. int PWMB=11;//使能端口2
  16. //数字端口4与5为一组,6与7为另一组
  17. //数字端口10 11 作为直流电机的使能端

  18. //定义三个红外传感器接口
  19. //左边的在第13号,中间的在12号,右边的3号数字端口
  20. int snum[3];//三个红外传感器

  21. void stopMotor(boolean r)//电机停转
  22. {
  23.   if (r)
  24.   {
  25.     analogWrite(PWMA,255);
  26.     analogWrite(PWMB,255);
  27.   }
  28.   else
  29.   {
  30.     analogWrite(PWMA,0);
  31.     analogWrite(PWMB,0);
  32.   }
  33. }

  34. void setup()
  35. {
  36.   int i;


  37.   for (i=4;i<=7;i++) //为Ardunio 电机驱动板
  38.     pinMode(i,OUTPUT); //设置数字端口4,5,6,7为输出模式

  39.   for (i=4;i<=7;i++)
  40.     digitalWrite(i,OUTPUT); //设置数字端口4,5,6,7为HIGH,电机保持不动


  41.   pinMode(10,OUTPUT);//设置数字端口10  11为输出模式
  42.   pinMode(11,OUTPUT);

  43.   //设置三个红外传感器端口为输入模式
  44.   pinMode(3,INPUT);
  45.   pinMode(12,INPUT);
  46.   pinMode(13,INPUT);

  47.   Serial.begin(9600);

  48. }

  49. void loop()
  50. {
  51.   dd();//避障过程函数

  52. }



  53. void motosp(int sp1, int sp2)
  54. //声明电机速度控制函数。
  55. //括号内定义的变量分别为左右电机速度值,范围-255~+255,正值为正转,负值 为反转
  56. {

  57.   if (sp1>=0)
  58.   {
  59.     digitalWrite(IN1,HIGH);
  60.     digitalWrite(IN2,LOW);
  61.   }
  62.   else
  63.   {
  64.     digitalWrite(IN1,LOW);
  65.     digitalWrite(IN2,HIGH);
  66.   }

  67.   if (sp2>=0)
  68.   {
  69.     digitalWrite(IN3,HIGH);
  70.     digitalWrite(IN4,LOW);
  71.   }
  72.   else
  73.   {
  74.     digitalWrite(IN3,LOW);
  75.     digitalWrite(IN4,HIGH);
  76.   }
  77.   analogWrite(PWMA,abs(sp1));
  78.   analogWrite(PWMB,abs(sp2));
  79. }

  80. void dd(void) //避障过程
  81. {
  82.   snum[0]=digitalRead(13); //这三个依次为右中左红外传感器
  83.   snum[1]=digitalRead(3);
  84.   snum[2]=digitalRead(12);


  85.   if ((snum[0]==1) && snum[1]==1 && snum[2]==1) //所有传感器都没有检测到障碍物

  86.   {
  87.     motosp(100,100);//直行
  88.   }


  89.   if (snum[0]==0 && (snum[1]==1) && snum[2]==1) //右边传感器检测到障碍物
  90.   {
  91.     motosp(0,255);//向左转
  92.   }

  93.   if (snum[0]==1 && snum[1]==1 && (snum[2]==0))   //左边传感器检测到障碍物
  94.   {
  95.     motosp(255,0  );//小车向右转
  96.   }
  97.   if (( snum[0]==1 && snum[1]==0 && (snum[2])==1) )//如果中间传感检测到障碍物
  98.   {
  99.     //  motosp(0,255);   //向左转 默认
  100.     //由于不管如何设置一个轮子的最小速度和另一个轮子的最大速度,它的拐弯太小,而且还要向前走很长距离
  101.     //所以设置一个轮子不转,另一个轮子转。
  102.     backleft() ;//退后,再向左拐弯  

  103.   }
  104.   delay(50);
  105. }

  106. void aa(void) //拐弯小程序
  107. {
  108.   int i,j;
  109.   i=250,j=254;
  110.   motosp(-10,-10);//向左拐弯

  111.   //经测试这个拐弯很小,不顶事
  112. }

  113. void backleft(void) //退后,再向左拐弯
  114. {
  115.   //为解决振动问题,需要引入一个变量判断这个退后向左拐弯过程未结束,不能再次接受其它信号

  116.   //先退后一段距离,再拐弯
  117.   motosp(-10,-10); //退后
  118.   delay(50);

  119.   motosp(250,250);
  120.   delay(5);

  121.   motosp(0,255);//向左拐弯
  122.   delay(50);
  123. }
复制代码
执行程序。
小车遇到前方的障碍物,会后退,但右轮在抖动,在抖动中慢慢转动方向。这不符合预订的目标。原因猜测在于,遇到前方的障碍物,小车没有先执行后退一段时间,再转弯一段时间.
受到了其它的干扰。

我的想法是让它暂时不受其它的干扰,这就需要用到中断了。参照迷你强的中断教程。

使用的中断的代码,改变的部分如下:
在程序中增加定义
  int pbIn=1;//定义叫断引脚为1,也就是D3引脚
在void setup()中增加
  //设置中断输入引脚的变化
  attachInterrupt(pbIn,backleft,LOW);//低电平时,触发中断

那个backleft()修改如下:
void backleft(void) //中断函数
{
  //在小车后退前,先暂停一段时间,希望能避免小车跷的问题
       for (int i=0 ;i<=1000;i++)
     {
      motosp(255,255);  
     }  
   

   //由于中断中不能使用延时函数,只有将电机转动函数放在循环中才能使电机转若干时间
   for (int i=0 ;i<=10000;i++)
     {
      motosp(-10,-10); //后退   
     }
     
/*     for (int i=0 ;i<=1000;i++)
     {
      motosp(255,255);  
     }  
*/   
     
   motosp(0,255); //向左拐弯
   for (int i=0 ;i<=10000;i++)
     {
         motosp(0,255);//向左拐弯
     }
     
    //测试一下,能不能解决小车跷起的问题
    //事实上仅能缓解一下
         for (int i=0 ;i<=1000;i++)
     {
      motosp(255,255);  //停止电机转动
     }  
         
}
运行程序测试,达到了预期的目标,只是小车还是会跷起,但跷起的幅度小了些。也就这样了。

完整的Arduino代码如下:
  1. /*
  2. 这是自制电机驱动板,三个红外传感器的避障小车的测试电机的程序
  3. */
  4. /*由于使用能端用了光耦隔离,使能端的取值范围是-255~255。但输出那一端,却造成的效果是相反的。
  5. //相当于使能端的0对应255 ,它本应对应速度为0,实际是速度的0最大值。使能端255却对应速度为0的效果。
  6. //为了减小电机的速度 motosp(250,250)比较合适。
  7. //已经测试通过
  8. */

  9. //为了减少避障可能撞到墙壁,在中间的探测到障碍物时先后退,再向左拐弯。但有个缺点,右边的轮子同时向前和向后,引起的震动。

  10. //为清除这个震动,打算将它放在中断中试一试
  11. /*
  12. 将那个后退并拐弯(向左)的子程序作为中断函数,中断口定义在数字端口3上
  13. 本程序已经成功消除了震动问题,但小车后退过程中却会出现小车的前端向下,后端向上跷起来的现象

  14. 也算是一种缺点吧。

  15. 注:如果小车单独后退并不会跷起。
  16. ???会不会是由于中断前是向前运动,中断后突然向后,引起的。如果是的话,在转方向前先暂停一下应该可以解决
  17. */


  18. int IN1=4;
  19. int IN2=5;
  20. int IN3=6;
  21. int IN4=7;

  22. int PWMA=10;//使能端口1
  23. int PWMB=11;//使能端口2
  24. //数字端口4与5为一组,6与7为另一组
  25. //数字端口10 11 作为直流电机的使能端

  26. //定义三个红外传感器接口
  27. //左边的在第13号,中间的在12号,右边的3号数字端口
  28. int snum[3];//三个红外传感器

  29. int pbIn=1;//定义叫断引脚为1,也就是D3引脚

  30. void stopMotor(boolean r)//电机停转
  31. {
  32.   if (r)
  33.   {
  34.     analogWrite(PWMA,255);
  35.     analogWrite(PWMB,255);
  36.   }
  37.   else
  38.   {
  39.     analogWrite(PWMA,0);
  40.     analogWrite(PWMB,0);
  41.   }
  42. }

  43. void setup()
  44. {
  45.   int i;


  46.   for (i=4;i<=7;i++) //为Ardunio 电机驱动板
  47.     pinMode(i,OUTPUT); //设置数字端口4,5,6,7为输出模式

  48.   for (i=4;i<=7;i++)
  49.     digitalWrite(i,OUTPUT); //设置数字端口4,5,6,7为HIGH,电机保持不动


  50.   pinMode(10,OUTPUT);//设置数字端口10  11为输出模式
  51.   pinMode(11,OUTPUT);

  52.   //设置三个红外传感器端口为输入模式
  53. //  pinMode(3,INPUT);
  54.   pinMode(12,INPUT);
  55.   pinMode(13,INPUT);

  56.   
  57.   //设置中断输入引脚的变化
  58.   attachInterrupt(pbIn,backleft,LOW);//低电平时,触发中断
  59.   Serial.begin(9600);


  60. }

  61. void loop()
  62. {
  63.   dd();//避障过程函数

  64. }



  65. void motosp(int sp1, int sp2)
  66. //声明电机速度控制函数。
  67. //括号内定义的变量分别为左右电机速度值,范围-255~+255,正值为正转,负值 为反转
  68. {

  69.   if (sp1>=0)
  70.   {
  71.     digitalWrite(IN1,HIGH);
  72.     digitalWrite(IN2,LOW);
  73.   }
  74.   else
  75.   {
  76.     digitalWrite(IN1,LOW);
  77.     digitalWrite(IN2,HIGH);
  78.   }

  79.   if (sp2>=0)
  80.   {
  81.     digitalWrite(IN3,HIGH);
  82.     digitalWrite(IN4,LOW);
  83.   }
  84.   else
  85.   {
  86.     digitalWrite(IN3,LOW);
  87.     digitalWrite(IN4,HIGH);
  88.   }
  89.   analogWrite(PWMA,abs(sp1));
  90.   analogWrite(PWMB,abs(sp2));
  91. }

  92. void dd(void) //避障过程
  93. {
  94.   snum[0]=digitalRead(13); //这三个依次为右中左红外传感器
  95.   snum[1]=digitalRead(3);
  96.   snum[2]=digitalRead(12);


  97.   if ((snum[0]==1) && snum[1]==1 && snum[2]==1) //所有传感器都没有检测到障碍物

  98.   {
  99.     motosp(100,100);//直行
  100.   }


  101.   if (snum[0]==0 && (snum[1]==1) && snum[2]==1) //右边传感器检测到障碍物
  102.   {
  103.     motosp(0,255);//向左转
  104.   }

  105.   if (snum[0]==1 && snum[1]==1 && (snum[2]==0))   //左边传感器检测到障碍物
  106.   {
  107.     motosp(255,0  );//小车向右转
  108.   }
  109.   
  110. if (( snum[0]==1 && snum[1]==0 && (snum[2])==1) )//如果中间传感检测到障碍物
  111.   {
  112.      
  113.   }

  114.   delay(50);
  115. }

  116. void aa(void) //拐弯小程序
  117. {
  118.   int i,j;
  119.   i=250,j=254;
  120.   motosp(-10,-10);//向左拐弯

  121.   //经测试这个拐弯很小,不顶事
  122. }

  123. void old_backleft(void) //退后,再向左拐弯
  124. {
  125.   //为解决振动问题,需要引入一个变量判断这个退后向左拐弯过程未结束,不能再次接受其它信号

  126.   //先退后一段距离,再拐弯
  127.   motosp(-10,-10); //退后
  128.   delay(50);
  129.   
  130.   motosp(250,250);
  131.    delay(5);
  132.   
  133.   motosp(0,255);//向左拐弯
  134.   delay(50);
  135.   //这里就不延时了,用公用的延时代码
  136.   
  137.   
  138. }

  139.   
  140. void backleft(void) //中断函数
  141. {
  142.   //在小车后退前,先暂停一段时间,希望能避免小车跷的问题
  143.        for (int i=0 ;i<=1000;i++)
  144.      {
  145.       motosp(255,255);  
  146.      }  
  147.    

  148.    //由于中断中不能使用延时函数,只有将电机转动函数放在循环中才能使电机转若干时间
  149.    for (int i=0 ;i<=10000;i++)
  150.      {
  151.       motosp(-10,-10); //后退   
  152.      }
  153.      
  154. /*     for (int i=0 ;i<=1000;i++)
  155.      {
  156.       motosp(255,255);  
  157.      }  
  158. */   
  159.      
  160.    motosp(0,255); //向左拐弯
  161.    for (int i=0 ;i<=10000;i++)
  162.      {
  163.          motosp(0,255);//向左拐弯
  164.      }
  165.      
  166.     //测试一下,能不能解决小车跷起的问题
  167.     //事实上仅能缓解一下
  168.          for (int i=0 ;i<=1000;i++)
  169.      {
  170.       motosp(255,255);  
  171.      }  
  172.          
  173. }
复制代码
经过这番改进,小车避障性能达到了目标。不过还是有些缺点,比如,如果障碍物很低,挡住了小车,小车不知道,还在向前开,但又不能前进。
或是还需要增加防跌落,

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2013-9-23 13:51:25 | 显示全部楼层
不如把光电管 上下布两层    还可以斜向下 放置
回复 支持 反对

使用道具 举报

发表于 2013-9-23 17:09:28 | 显示全部楼层
Microduino core是楼主设计的吗?看起来挺小巧的啊
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-9-23 19:26:25 | 显示全部楼层
likunyang 发表于 2013-9-23 17:09
Microduino core是楼主设计的吗?看起来挺小巧的啊

不是,我只是使用者。
回复 支持 反对

使用道具 举报

发表于 2013-12-7 02:07:51 | 显示全部楼层
有点意思!
回复 支持 反对

使用道具 举报

发表于 2013-12-7 17:53:47 | 显示全部楼层
加上电机测速,就能知道是否被障碍卡住而自行脱困了。
回复 支持 反对

使用道具 举报

发表于 2013-12-16 15:55:20 | 显示全部楼层
[ 本帖最后由 新月 于 2013-12-26 16:38 编辑 ]\n\n我复制了你的代码,谢谢!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-10 11:16 , Processed in 0.039398 second(s), 23 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表