找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 12360|回复: 4
收起左侧

超声波避障小车Arduino源码

[复制链接]
ID:389885 发表于 2018-8-25 12:09 | 显示全部楼层 |阅读模式
硬件电路配置有Arduino、L293D驱动模块、PCA9685驱动模块各一个,四个直流电机(由L293D驱动模块驱动),3个舵机(PCA9685驱动模块驱动),三个超声波探测器。代码有很多的多余注释,还有想要用定时器2的草稿,大家看着做个参考。
//四轮独立驱动小车,注意程序已经舵机角度改为不是0-60之间变化,范围有所缩小。

  1. #include <AFMotor.h>
  2. //#include <MsTimer2.h>


  3.     #define PCA9685_adrr 0x80//  1+A5+A4+A3+A2+A1+A0+w/r
  4.                         //片选地址,将焊接点置1可改变地址,
  5.                         // 当IIC总 呱嫌 多片PCA9685或相同地址时才需焊接
  6.     #define PCA9685_SUBADR1 0x2
  7.     #define PCA9685_SUBADR2 0x3
  8.     #define PCA9685_SUBADR3 0x4

  9.     #define PCA9685_MODE1 0x0//PCA9685模式复位设置
  10.     #define PCA9685_PRESCALE 0xFE//控制周期的寄存器

  11.     #define LED0_ON_L 0x6
  12.     #define LED0_ON_H 0x7
  13.     #define LED0_OFF_L 0x8
  14.     #define LED0_OFF_H 0x9

  15.     #define ALLLED_ON_L 0xFA
  16.     #define ALLLED_ON_H 0xFB
  17.     #define ALLLED_OFF_L 0xFC
  18.     #define ALLLED_OFF_H 0xFD   

  19.     #define SERVOMIN  115 // this is the 'minimum' pulse length count (out of 4096)
  20.     #define SERVOMAX  590 // this is the 'maximum' pulse length count (out of 4096)
  21.     //#define SERVO000  130 //0度对应4096的脉宽计数值
  22.     #define SERVO000  145 //0度对应4096的脉宽计数值
  23.     #define SERVO180  520 //180度对应4096的脉宽计算值,四个值可根据不同舵机修改

  24. AF_DCMotor LF_motor(1);//定义四个车轮电机对应的内存单元
  25. AF_DCMotor RF_motor(3);
  26. AF_DCMotor LB_motor(2);
  27. AF_DCMotor RB_motor(4);
  28. // 设定SR04连接的Arduino引脚
  29.     const int TrigPin = A0;//超声波测距使能控制信号
  30.     const int EchoPin = A1;//超声波测距模块输出,通过测得高电平持续时间获得障碍物距离
  31.     //unsigned long distance;
  32.     const int IIC_SDA = A5;//串行数据线信号
  33.     const int IIC_SCL = A4;//串行时钟线信号
  34.     const int EchoPin_L = A2;//左舵机超声波探测器接收信号
  35.     const int EchoPin_R = A3;//右舵机超声波探测器接收信号

  36. boolean stage1_ctrl=false;//前端超声波云台控制信号,true表示当前从60度转到0度;
  37. boolean stage23_ctrl=false;//左右端超声波云台控制信号,true表示当前从60度转到0度;
  38. boolean direction_ctrl_r=true;
  39. boolean direction_ctrl_l=true;


  40. int l=0;
  41. int m=0;
  42. int stage1_dis;
  43. int stage2_dis;
  44. int stage3_dis;


  45. void setup()
  46. {   // 初始化串口通信及连接SR04的引脚
  47. //Serial.begin(9600);
  48. pinMode(TrigPin, OUTPUT);
  49. // 要检测引脚上输入的脉冲宽度,需要先设置为输入状态
  50. pinMode(EchoPin, INPUT);
  51. //Serial.println("开始");
  52. LF_motor.setSpeed(150);
  53. RF_motor.setSpeed(150);
  54. LB_motor.setSpeed(150);
  55. RB_motor.setSpeed(150);
  56. LF_motor.run(FORWARD);
  57. RF_motor.run(FORWARD);
  58. LB_motor.run(FORWARD);
  59. RB_motor.run(FORWARD);
  60.   pinMode(IIC_SDA,OUTPUT);
  61.   pinMode(IIC_SCL,OUTPUT);
  62. //Serial.println("SDA,SCL引脚初始化");
  63. IIC_init();
  64. // Serial.println("IIC初始化");
  65. reset();
  66.   // Serial.println("初始化结束");
  67.   setPWMFreq(50);
  68.   // Serial.println("初始化结束");
  69. //MsTimer2::set(500, stage1); // 500ms period定时器2初始化;
  70. // Serial.println("初始化结束");
  71. // MsTimer2::start();
  72. //Serial.println("初始化结束");
  73. }

  74. void loop()
  75. {//  Serial.println("主程序");
  76.   if(stage1_ctrl==true)
  77.    {
  78.     stage1_ctrl=false;
  79.     setPWM(0, 0, SERVO000);//第0路舵机从60度转到0角度   0.12-0.13秒/60度
  80.    }
  81.    else
  82.    {
  83.     stage1_ctrl=true;
  84.     setPWM(0, 0,224);  //第0路舵机从0度转到60角度   
  85.    }   
  86. for(l=0;l<=100;l++)   
  87. {
  88.     // 产生一个1。、0us的高脉冲去触发TrigPin,即开启超声波测距
  89. digitalWrite(TrigPin, LOW);
  90. delayMicroseconds(2);
  91. digitalWrite(TrigPin, HIGH);
  92. delayMicroseconds(10);
  93. digitalWrite(TrigPin, LOW);

  94.     // 检测脉冲宽度,并计算出距离
  95. delayMicroseconds(2);
  96. int stage1_dis=pulseIn(EchoPin, HIGH,2000);
  97. //Serial.println(stage1_dis);
  98. //distance = pulseIn(EchoPin, HIGH) / 58.00;
  99. if(stage1_dis>0)//stage1_dis=0表示超过超声波等待回收信号范围,即距离超过(1300/58)cm;
  100.   {
  101.     if(stage23_ctrl==true)
  102.      {
  103.     stage23_ctrl=false;
  104.     setPWM(1, 0, SERVO000);//第1路舵机从60度转到0角度   
  105.     setPWM(2, 0,224);//第2路舵机从0度转到60角度   
  106.    }
  107.    else
  108.    {
  109.     stage23_ctrl=true;
  110.     setPWM(1, 0,224);  //第1路舵机从0度转到60角度
  111.     setPWM(2, 0, SERVO000);  //第1路舵机从60度转到0角度     
  112.    }   
  113.   // Serial.println("外循环");
  114.    for(m=0;m<=40;m++)
  115.    {
  116. //Serial.println("前端超声波探测循环");
  117.    //delay(1);
  118.    digitalWrite(TrigPin, LOW); // 产生一个10us的高脉冲去触发TrigPin,即开启超声波测距
  119.    delayMicroseconds(2);
  120.    digitalWrite(TrigPin, HIGH);
  121.    delayMicroseconds(10);
  122.    digitalWrite(TrigPin, LOW);
  123.    delayMicroseconds(2);
  124.    stage2_dis=pulseIn(EchoPin_L, HIGH,1500);
  125.    delay(1);//如果不延时处理,stage3_dis测得距离会有问题;
  126.    digitalWrite(TrigPin, LOW);
  127.    delayMicroseconds(2);
  128.    digitalWrite(TrigPin, HIGH);
  129.    delayMicroseconds(10);
  130.    digitalWrite(TrigPin, LOW);
  131.    delayMicroseconds(2);
  132.    stage3_dis=pulseIn(EchoPin_R, HIGH,1500);
  133. //Serial.println(stage1_dis);
  134. //Serial.println(stage2_dis);
  135. // Serial.println(stage3_dis);
  136. //delay(500);
  137.    if(stage2_dis>0)
  138.    {
  139.    direction_ctrl_l=false;
  140.    }
  141.    else
  142.    {
  143.    direction_ctrl_l=true;
  144.    }
  145.    if(stage3_dis>0)
  146.    {
  147.    direction_ctrl_r=false;
  148.    }
  149.    else
  150.    {
  151.    direction_ctrl_r=true;
  152.    }
  153.    }
  154. // Serial.println(direction_ctrl_l);
  155. //Serial.println(direction_ctrl_r);
  156.   if(direction_ctrl_l==true)
  157.   {
  158.   // Serial.println("左转");
  159.    LF_motor.run(BACKWARD);
  160.    LB_motor.run(BACKWARD);
  161.   // RF_motor.run(FORWARD);
  162.   // RB_motor.run(FORWARD);
  163.    delay(1000);
  164. //  LF_motor.run(FORWARD);
  165.   // LB_motor.run(FORWARD);

  166.   }
  167.   else if(direction_ctrl_r==true)
  168.   {
  169.    // Serial.println("右转");  
  170.    RF_motor.run(BACKWARD); //如果之前左转,发现左端忽然有障碍物出现,则机器人实际变成后退动作;
  171.    RB_motor.run(BACKWARD);
  172.    //LF_motor.run(FORWARD);
  173.    //LB_motor.run(FORWARD);
  174.    delay(1000);
  175.   // RF_motor.run(FORWARD);
  176.   // RB_motor.run(FORWARD);

  177.   }
  178.   else
  179.   {
  180.    // Serial.println("后退");
  181.    RF_motor.run(BACKWARD);
  182.    RB_motor.run(BACKWARD);
  183.    LF_motor.run(BACKWARD);
  184.    LB_motor.run(BACKWARD);
  185.    delay(1000);
  186.   // RF_motor.run(FORWARD);
  187. //  RB_motor.run(FORWARD);
  188.   // LF_motor.run(FORWARD);
  189.   // LB_motor.run(FORWARD);


  190.   }

  191.   break;//注意内层的break只能跳出内层的for循环,两个,三个break,也都只能跳出本层循环,及第二个Break根本不会执行;

  192.    //digitalWrite(LF, HIGH);
  193.    //digitalWrite(LB, HIGH);

  194. }
  195. else
  196. {
  197.    RF_motor.run(FORWARD);
  198.    RB_motor.run(FORWARD);
  199.    LF_motor.run(FORWARD);
  200.    LB_motor.run(FORWARD);
  201. }

  202. }  
  203. //Serial.print(distance);
  204. //Serial.print("cm");
  205. //Serial.println();
  206. //delay(500);
  207. }
  208.   //IIC初始化
  209.     void IIC_init()
  210.     {
  211.     digitalWrite(IIC_SDA,HIGH); //IIC_SDA IIC_SCL使用前被拉高
  212.     delayMicroseconds(4);
  213.     digitalWrite(IIC_SCL,HIGH);
  214.     delayMicroseconds(4);
  215.     }


  216.   void start()//基于IIC总线的物理结构,总线上的START和IIC_stop信号必定是唯一的。
  217.                 //另外,IIC总线标准规定IIC_SDA线的数据转换必须在IIC_SCL线的低电平期,
  218.                 //在IIC_SCL线的高电平期,IIC_SDA线的上数据是稳定的。所以,start(),IIC_stop()的
  219.                 //特殊情况可以作为指示的起止信号。
  220.     {
  221.    //   Serial.println("start开始");
  222.     digitalWrite(IIC_SDA,HIGH);
  223.     delayMicroseconds(4);
  224.     digitalWrite(IIC_SCL,HIGH); //IIC_SCL高 IIC_SDA拉低表示可以IIC启动
  225.     delayMicroseconds(4);
  226.     digitalWrite(IIC_SDA,LOW);
  227.     delayMicroseconds(4);
  228.     digitalWrite(IIC_SCL,LOW);
  229.     delayMicroseconds(4);
  230.   //  Serial.println("start结束");
  231.     }

  232.     //IIC停止
  233.     void IIC_stop()
  234.     {
  235.     digitalWrite(IIC_SDA,LOW);
  236.     delayMicroseconds(4);
  237.     digitalWrite(IIC_SCL,HIGH);
  238.     delayMicroseconds(4);
  239.     digitalWrite(IIC_SDA,HIGH);
  240.     delayMicroseconds(4);
  241.     }

  242.     //IIC应答
  243.     void ACK()//IIC_SDA应答信号为0表示正常收发数据,为1表示停止,
  244.     {
  245.     unsigned char i;
  246.     digitalWrite(IIC_SCL,HIGH);
  247.     delayMicroseconds(2);
  248.     pinMode(IIC_SDA,INPUT);
  249.     while((digitalRead(IIC_SDA))&&(i<=255))   
  250.     {
  251.     i++;
  252.     }
  253.     pinMode(IIC_SDA,OUTPUT);
  254.     digitalWrite(IIC_SCL,LOW);
  255.     delayMicroseconds(4);
  256.     }

  257.     //写字节
  258.     void write_byte(unsigned char byte)
  259.     {
  260.     //Serial.println("地址写入SDL开始");调试用
  261.     unsigned char i,temp;
  262.     temp=byte;
  263.     for(i=7;i<=7;i--)
  264.     {//unsigned char x;//调试用
  265.     //x=0;//调试用
  266.     //const int test = 2;//调试用
  267.     //pinMode(test,INPUT);//调试用
  268.     digitalWrite(IIC_SCL,LOW);
  269.     delayMicroseconds(4);
  270.     //Serial.println(temp);//调试用
  271.     //Serial.println(bitRead(temp,i));//调试用
  272.     digitalWrite(IIC_SDA,bitRead(temp,i));
  273.    //Serial.println(digitalRead(test));
  274.    // x=(digitalRead(test))|(x<<1);//调试用
  275.    //Serial.println(x);//调试用
  276.    //Serial.println(i);//调试用
  277.     delayMicroseconds(4);
  278.     digitalWrite(IIC_SCL,HIGH);
  279.     delayMicroseconds(4);
  280.     }
  281.     digitalWrite(IIC_SCL,LOW);
  282.     delayMicroseconds(4);
  283.     digitalWrite(IIC_SDA,HIGH);
  284.     delayMicroseconds(4);
  285.     }
  286.     unsigned char read_byte()
  287.     {
  288.     unsigned char i,j,k;
  289.     digitalWrite(IIC_SCL,LOW);
  290.     delayMicroseconds(4);
  291.     digitalWrite(IIC_SDA,HIGH);
  292.     delayMicroseconds(4);
  293.     for(i=0;i<8;i++)
  294.     {
  295.     delayMicroseconds(4);
  296.     digitalWrite(IIC_SCL,HIGH);
  297.     delayMicroseconds(4);
  298.     pinMode(IIC_SDA,INPUT);
  299.     if(digitalRead(IIC_SDA))
  300.     {
  301.       j=1;
  302.     }
  303.     else
  304.     {
  305.       j=0;
  306.     }
  307.     pinMode(IIC_SDA,OUTPUT);
  308.     k=(k<<1)|j;
  309.     digitalWrite(IIC_SCL,LOW);
  310.     }
  311.     delayMicroseconds(4);
  312.     return k;
  313.     }

  314.     void PCA9685_write(unsigned char address,unsigned char date)
  315.     {
  316.    //Serial.println("PCA9685_write开始");
  317.     start();
  318.     write_byte(PCA9685_adrr); //PCA9685
  319.     ACK();
  320.     write_byte(address); //PCA9685对应内部哪个地址
  321.     ACK();
  322.     write_byte(date); //所写入的数据
  323.     //Serial.println("所写入的数据:");
  324.     //Serial.println(date);
  325.     ACK();
  326.     IIC_stop();
  327.     //Serial.println("PCA9685_write结束");
  328.     }

  329.     //从PCA9685读数据有返回值
  330.     unsigned char PCA9685_read(unsigned char address)
  331.     {
  332.     unsigned char date;
  333.     start();
  334.     write_byte(PCA9685_adrr); //PCA9685
  335.     ACK();
  336.     write_byte(address);//PCA9685对应内部哪个地址
  337.     ACK();
  338.     start();
  339.     write_byte(PCA9685_adrr|0x01); //表示此时状态为从PCA9685读取数据
  340.     ACK();
  341.     date=read_byte();
  342.    // Serial.println("date");
  343.     //Serial.println(date);
  344.     return date;
  345.     }

  346. //PCA9685复位
  347.     void reset(void)
  348.     {//Serial.println("RESET开始");
  349.     PCA9685_write(PCA9685_MODE1,0x0);
  350.      //Serial.println("RESET结束");
  351.     }

  352. //PCA9685修改频率
  353. /*---------------------------------------------------------------
  354.                                 PCA9685修改角度函数
  355. num:舵机PWM输出引脚0~15,on:PWM上升计数值0~4096,off:PWM下降计数值0~4096
  356. 一个PWM周期分成4096份,由0开始+1计数,计到on时跳变为高电平,继续计数到off时
  357. 跳变为低电平,直到计满4096重新开始。所以当on不等于0时可作延时,当on等于0时,
  358. off/4096的值就是PWM的占空比。
  359. ----------------------------------------------------------------*/



  360.     void setPWMFreq(float freq)
  361.      { //Serial.print("设置PWM周期:");
  362.                 unsigned int prescale,oldmode,newmode;
  363.                 float prescaleval;
  364.                 freq *= 0.915;
  365.                 prescaleval = 25000000;
  366.                 prescaleval /= 4096;
  367.                 prescaleval /= freq;
  368.                 prescaleval -= 1;
  369.                 prescale = floor(prescaleval + 0.5);

  370.                 oldmode = PCA9685_read(PCA9685_MODE1);
  371.                 newmode = (oldmode&0x7F) | 0x10; // sleep
  372.                 //Serial.println("新模式:");
  373.                 PCA9685_write(PCA9685_MODE1,newmode); // go to sleep
  374.                // Serial.println("新模式:");
  375.                 // Serial.println(newmode);
  376.                 PCA9685_write(PCA9685_PRESCALE,prescale); // set the prescaler
  377.                 // Serial.println("周期频率设置值:");
  378.                 // Serial.println(prescale);
  379.                 PCA9685_write(PCA9685_MODE1,oldmode);
  380.                // Serial.println("旧模式:");
  381.                 // Serial.println(oldmode);
  382.                 delay(2);
  383.                 PCA9685_write(PCA9685_MODE1,oldmode | 0xa1);
  384.      }
  385.           void setPWM(unsigned int num, unsigned int on, unsigned int off)
  386.         {
  387.                //Serial.print("当前通道:");
  388.                //Serial.print(num);
  389.                 PCA9685_write(LED0_ON_L+4*num,on);
  390.                 PCA9685_write(LED0_ON_H+4*num,on>>8);
  391.                 PCA9685_write(LED0_OFF_L+4*num,off);
  392.                 PCA9685_write(LED0_OFF_H+4*num,off>>8);
  393.         }

  394. /*void stage1()
  395. {
  396.   Serial.print("timer");

  397. if(stage1_ctrl==true)
  398.    {
  399.     stage1_ctrl=false;
  400.     setPWM(0, 0, SERVO000);//第0路舵机从60度转到0角度   
  401.    }
  402.    else
  403.    {
  404.     stage1_ctrl=true;
  405.     setPWM(0, 0,224);  //第0路舵机从0度转到60角度   
  406.    }            
  407.                    //setPWM(0, 0, SERVO180);//第0路舵机转到0角度     
  408.                    //setPWM(1, 0, SERVO000);//第1路舵机转到0角度
  409. }
  410. */
复制代码



评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:1 发表于 2018-8-25 17:02 | 显示全部楼层
原理图能分享下吗?
回复

使用道具 举报

ID:389885 发表于 2018-8-26 11:55 | 显示全部楼层
admin 发表于 2018-8-25 17:02
原理图能分享下吗?

额,没有画原理图,直接接线的。我等下简单手画一下吧
回复

使用道具 举报

ID:389885 发表于 2018-8-26 12:48 | 显示全部楼层
不懂得怎么发图片啊。。。那样成功了没
回复

使用道具 举报

ID:390585 发表于 2018-11-8 19:18 | 显示全部楼层
Riton 发表于 2018-8-26 12:48
不懂得怎么发图片啊。。。那样成功了没

没有看到图片
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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