智能小车 订阅
智能小车作为现代的新发明,是以后的发展方向,他可以按照预先设定的模式在一个环境里自动的运作,不需要人为的管理,可应用于科学勘探等等的用途。智能小车能够实时显示时间、速度、里程,具有自动寻迹、寻光、避障功能,可程控行驶速度、准确定位停车,远程传输图像等功能。智能小车可以分为三部分——传感器部分、控制器部分、执行器部分。控制器部分:接收传感器部分传递过来的信号,并根据事前写入的决策系统(软件程序),来决定机器人对外部信号的反应,将控制信号发给执行器部分。好比人的大脑。执行器部分:驱动机器人做出各种行为,包括发出各种信号(点亮发光二极管、发出声音)的部分,并且可以根据控制器部分的信号调整自己的状态。对机器人小车来说,最基本的就是轮子。这部分就好比人的四肢一样。 传感器部分:机器人用来读取各种外部信号的传感器,以及控制机器人行动的各种开关。好比人的眼睛、耳朵等感觉器官。 展开全文
智能小车作为现代的新发明,是以后的发展方向,他可以按照预先设定的模式在一个环境里自动的运作,不需要人为的管理,可应用于科学勘探等等的用途。智能小车能够实时显示时间、速度、里程,具有自动寻迹、寻光、避障功能,可程控行驶速度、准确定位停车,远程传输图像等功能。智能小车可以分为三部分——传感器部分、控制器部分、执行器部分。控制器部分:接收传感器部分传递过来的信号,并根据事前写入的决策系统(软件程序),来决定机器人对外部信号的反应,将控制信号发给执行器部分。好比人的大脑。执行器部分:驱动机器人做出各种行为,包括发出各种信号(点亮发光二极管、发出声音)的部分,并且可以根据控制器部分的信号调整自己的状态。对机器人小车来说,最基本的就是轮子。这部分就好比人的四肢一样。 传感器部分:机器人用来读取各种外部信号的传感器,以及控制机器人行动的各种开关。好比人的眼睛、耳朵等感觉器官。
信息
发展背景
汽车工业的迅速发展
外文名
intelligent car
组成部分
传感器部分、控制器部分等
中文名
智能小车
特    色
显示时间、速度、里程等
智能小车发展背景简介
51智能小车 智能小车 随着汽车工业的迅速发展,关于汽车的研究也就越来越受人关注。全国电子大赛和省内电子大赛几乎每次都有智能小车这方面的题目,全国各高校也都很重视该题目的研究。可见其研究意义很大。在智能小车现今发展最好的当是 飞思卡尔 举行的比赛,采用先进的摄像头采集黑线线路,此时要求芯片的运算速度是非常高的。
收起全文
精华内容
参与话题
问答
  • Arduino智能小车——小车测速

    万次阅读 多人点赞 2019-05-20 10:25:04
    Arduino智能小车——小车测速  可以用于测速的模块很多,比如加速度计、激光、超声波、编码器等等,由于我们对小车速度的测量精度要求不高,因此我们可以借助小车套件里面的码盘配上测速模块对其速度进行测量。...

    Arduino智能小车——小车测速

    Arduino智能小车系列教程时空门:

    1. Arduino智能小车——拼装篇 点击跳转
    2. Arduino智能小车——测试篇 点击跳转
    3. Arduino智能小车——调速篇 点击跳转
    4. Arduino智能小车——超声波避障 点击跳转
    5. Arduino智能小车——蓝牙小车 点击跳转
    6. Arduino智能小车——循迹篇 点击跳转
    7. Arduino智能小车——小车测速 点击跳转

      可以用于测速的模块很多,比如加速度计、激光、超声波、编码器等等,由于我们对小车速度的测量精度要求不高,因此我们可以借助小车套件里面的码盘配上测速模块对其速度进行测量。
    ##准备材料
    测速模块
      网上的测速模块有很多种外观,但是其工作原理类似,下面列出来了几种常见的测速模块,这些测速模块接线类似。

    SouthEast
    SouthEast

      以上两种模块只能对一路电机的速度进行测量,下面这个可以同时测量两路电机,但是由于其间距固定,在安装时可能不兼容不同小车底盘,因此为了安装方便,在此篇教程中使用第一种模块。

    SouthEast

    固定铜柱

      建议铜柱长度30CM,大小为M3

    SouthEast

      由于铜柱导电,有些电路板如果固定孔设计不当的话很容易导致电路板烧坏,尤其是在以后的项目中可能会用到更高的电压,因此在这里我建议大家可以准备一些尼龙柱来固定电路板。尼龙柱的尺寸跟铜柱尺寸相同M3,30CM。大家也可以顺便买一点尼龙螺丝。

    SouthEast

      除此之外还需要准备杜邦线

    测速模块的安装

      驱动模块的安装需要由尼龙柱支撑

    SouthEast

      驱动模块安装时需要注意,不能影响轮子的正常工作,不能触碰到轮轴上的码盘。
      编码器上有三个引脚分别是“VCC”,“GND”,“OUT”。左右两边两个测速模块的“VCC”引脚接电源或开发板的“5V”或“3.3V”引脚,“GND”接电源或开发板的“GND”引脚,左边测速模块“OUT”接开发板的“3”引脚,右边测速模块“OUT”接开发板的“2”引脚。引脚接错的话可以再随后调试过程中换过来,也可以在代码里更改。
      最终接线图如下:

    SouthEast

    测速模块讲解

      测速模块的工作原理比较简单,如下图所示,在于电机同轴的码盘上有很多开孔(光栅),编码器相当于光敏元件。码盘随着小车轮子的运动转动时,码盘(光栅)会不断遮挡光敏元件发出的光波,这时候编码器就会根据光栅的遮挡不断的产生方波信号,方波信号会从“OUT”引脚输出,我们只需不断检测“OUT”引脚的输出,根据方波信号的周期简介计算出小车运行的速度。小车上使用的码盘(光栅)精度不高,在某些高精度的编码器上光栅会更加密集,测量效果会更好。

    SouthEast
      由于要不断检测编码器输出端的输出,因此我们需要借助Arduino的外部中断来读取编码器的输出。Arduino开发板外部中断对应的引脚如下:
    型号 int0 int1 int2 int3 int4 int5
    UNO\Ethernet 2 3
    Mega2560 2 3 21 20 19 18
    Leonardo 3 2 0 1
    Due All All All All All All

      由表中可以知道在此我们使用的Arduino UNO只有“2”,“3”引脚可以触发外部中断,因此在接线的时候我们便将左右两边的输出“OUT”引脚分别接在“2”“3”引脚上。
      在程序初始化阶段中调用函数attachInterrupt(interrupt, function, mode)可以对中断引脚初始化,其中
    interrupt: 要初始化的外部中断编号,由上表可知我们Arduino UNO只能使用外部中断0和外部中断1;
    function: 中断服务函数的名字,即当外部中断被触发时,将会自动调用这个函数;
    mode: 中断触发的方式,可选方式如下

    mode 含义
    LOW 低电平触发
    CHANGE 电平变化,高电平变低电平、低电平变高电平
    RISING 上升沿触发
    FALLING 下降沿触发
    HIGH 高电平触发(该中断模式仅适用于Arduino due)

    测试代码如下

    int leftCounter=0,  rightCounter=0;
    unsigned long time = 0, old_time = 0; // 时间标记
    unsigned long time1 = 0; // 时间标记
    float lv,rv;//左、右轮速度
    
    #define STOP      0
    #define FORWARD   1
    #define BACKWARD  2
    #define TURNLEFT  3
    #define TURNRIGHT 4
    
    int leftMotor1 = 4;
    int leftMotor2 = 5;
    int rightMotor1 = 6;
    int rightMotor2 = 7;
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600); 
      attachInterrupt(0,RightCount_CallBack, FALLING);
      attachInterrupt(1,LeftCount_CallBack, FALLING);
    
      pinMode(leftMotor1, OUTPUT);
      pinMode(leftMotor2, OUTPUT);
      pinMode(rightMotor1, OUTPUT);
      pinMode(rightMotor2, OUTPUT);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      SpeedDetection();
      if(Serial.available()>0)
      {
        char cmd = Serial.read();
      
        Serial.print(cmd);
        motorRun(cmd);
          
      }  
    }
    /*
     * *速度计算
     */
    bool SpeedDetection()
    {
      time = millis();//以毫秒为单位,计算当前时间 
      if(abs(time - old_time) >= 1000) // 如果计时时间已达1秒
      {  
        detachInterrupt(0); // 关闭外部中断0
        detachInterrupt(1); // 关闭外部中断1
        //把每一秒钟编码器码盘计得的脉冲数,换算为当前转速值
        //转速单位是每分钟多少转,即r/min。这个编码器码盘为20个空洞。
        lv =(float)leftCounter*60/20;//小车车轮电机转速
        rv =(float)rightCounter*60/20;//小车车轮电机转速
        Serial.print("left:");
        Serial.print(lv);//向上位计算机上传左车轮电机当前转速的高、低字节
        Serial.print("     right:");
        Serial.println(rv);//向上位计算机上传左车轮电机当前转速的高、低字节
        //恢复到编码器测速的初始状态
        leftCounter = 0;   //把脉冲计数值清零,以便计算下一秒的脉冲计数
        rightCounter = 0;
        old_time=  millis();     // 记录每秒测速时的时间节点   
        attachInterrupt(0, RightCount_CallBack,FALLING); // 重新开放外部中断0
        attachInterrupt(1, LeftCount_CallBack,FALLING); // 重新开放外部中断0
        return 1;
      }
      else
        return 0;
    }
    /*
     * *右轮编码器中断服务函数
     */
    void RightCount_CallBack()
    {
      rightCounter++;
    }
    /*
     * *左轮编码器中断服务函数
     */
    void LeftCount_CallBack()
    {
      leftCounter++;
    }
    /*
     * *小车运动控制函数
     */
    void motorRun(int cmd)
    {
      switch(cmd){
        case FORWARD:
          Serial.println("FORWARD"); //输出状态
          digitalWrite(leftMotor1, HIGH);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, HIGH);
          digitalWrite(rightMotor2, LOW);
          break;
         case BACKWARD:
          Serial.println("BACKWARD"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, HIGH);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, HIGH);
          break;
         case TURNLEFT:
          Serial.println("TURN  LEFT"); //输出状态
          digitalWrite(leftMotor1, HIGH);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, HIGH);
          break;
         case TURNRIGHT:
          Serial.println("TURN  RIGHT"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, HIGH);
          digitalWrite(rightMotor1, HIGH);
          digitalWrite(rightMotor2, LOW);
          break;
         default:
          Serial.println("STOP"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, LOW);
      }
    }
    

      看了这个代码大家应该就明白为什么之前我建议大家将每个功能都封装成函数了,封装成函数很利于程序的移植。

    测速效果

      借助于蓝牙串口助手我们可以清楚的看到小车左右轮的转速如图,由于电机自身的误差和摩擦力的作用,因此两个轮子的转速不相等,但是差别不是很大。

    SouthEast

    欢迎各位有兴趣的朋友加入Q群1:789127261点评、交流

    展开全文
  • Arduino智能小车——蓝牙小车

    万次阅读 多人点赞 2019-05-20 10:25:11
    Arduino智能小车——蓝牙小车  上一章我们完成了小车的运动控制,虽然小车已经可以运动,但是不能远程遥控,不够高大上。在这一篇,我们将尝试用手机蓝牙遥控小车。蓝牙模块  蓝牙( Bluetooth® ):是一种无线...

    Arduino智能小车——蓝牙小车

    Arduino智能小车系列教程时空门:

    1. Arduino智能小车——拼装篇 点击跳转
    2. Arduino智能小车——测试篇 点击跳转
    3. Arduino智能小车——调速篇 点击跳转
    4. Arduino智能小车——超声波避障 点击跳转
    5. Arduino智能小车——蓝牙小车 点击跳转
    6. Arduino智能小车——循迹篇 点击跳转
    7. Arduino智能小车——小车测速 点击跳转

      上一章我们完成了小车的运动控制,虽然小车已经可以运动,但是不能远程遥控,不够高大上。在这一篇,我们将尝试用手机蓝牙遥控小车。

    蓝牙模块

      蓝牙( Bluetooth® ):是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换(使用2.4—2.485GHz的ISM波段的UHF无线电波)。

      我们在此使用的蓝牙模块(HC-05)已经在内部实现了蓝牙协议,不用我们再去自己开发调试协议。这类模块一般都是借助于串口协议通信,因此我们只需借助串口将我们需要发送的数据发送给蓝牙模块,蓝牙模块会自动将数据通过蓝牙协议发送给配对好的蓝牙设备。

    SouthEast

    串口通信

      由于要借助串口实现蓝牙通信功能,所以我们在此要先了解下Arduino的串口通信。

      Arduino UNO开发板上的串口为0->RX,1->TX,在开发板内部也已经配置好了串口的功能,我们只需调用函数借口即可。以下列出串口通信里面常用的函数,并加以简单解释,详细用法可在用到时自行查询。

    开启串行通信接口并设置通信波特率

    Serial.begin(speed); 
    

    关闭串口通信

    Serial.end();    
    

    判断串口缓冲器是否有数据写入

    Serial.available();
    

    读取串口数据

    Serial.read();    
    

    返回下一字节(字符)输入数据,但不删除它

    Serial.peek();   
    

    清空串口缓存

    Serial.flush();    
    

    写入字符串数据到串口

    Serial.print();    
    

    写入字符串数据+换行到串口

    Serial.println(); 
    

    写入二进制数据到串口

    Serial.write();     
    

    read时触发的事件函数

    Serial.SerialEvent();
    

    读取固定长度的二进制流

    Serial.readBytes(buffer,length);
    

    打印接到数据十进制表示的ascii码

    Serial.println(incomingByte, DEC);
    

    蓝牙模块连接

    SouthEast

    TX: 接Arduino UNO开发板"RX"引脚
    RX: 接Arduino UNO开发板"TX"引脚
    GND: 接Arduino UNO开发板"GND"引脚
    VCC: 接Arduino UNO开发板"5V"或"3.3V"引脚

    SouthEast

    手机蓝牙助手

      想实现手机蓝牙遥控小车,手机APP是必不可少的,目前网上有很多蓝牙串口助手,省去了我们自己写APP的时间,当然如果朋友你有能力或者想自己DIY的话也可以尝试自己写APP,在这里我推荐大家用这款手机蓝牙助手(百度上搜手机蓝牙串口助手就可以搜到,挺好用的)

    SouthEast
      如果不想自己去找的话可以到我的百度网盘下载 [点击这里下载](http://pan.baidu.com/s/1pKClRTL)

      下载并安装后打开APP,在这里可能会提示你有新版本请求更新,建议点击以后再说(暂时不更新),以我的经验,一般点击立即更新都会更新失败。

    SouthEast
      进入主界面,左上角会提示"蓝牙未连接",这个时候我们可以先对蓝牙助手的界面进行自定义设置。点击右下角的三个点(在我这里是这样的,其他手机可能不同,如果没有这三个点可以试着点击手机的功能键),选择“更多”。
    SouthEast
      然后选择“地面站设置”进入自定义界面,往下拖动,找到“自定义按键[x]”,在此我们对按键[1][2][3][4][6]进行自定义设置。
    SouthEast
    **  点击自定义按键[1],将其“显示名称”属性改为“停止”,“点击发送”属性改为“00”,并点击“确定”保存**
    SouthEast
    同理更改其他按键:

    点击自定义按键[2],将其“显示名称”属性改为“前进”,“点击发送”属性改为“01”,并点击“确定”保存
    点击自定义按键[4],将其“显示名称”属性改为“左转”,“点击发送”属性改为“03”,并点击“确定”保存
    点击自定义按键[5],将其“显示名称”属性改为“后退”,“点击发送”属性改为“02”,并点击“确定”保存
    点击自定义按键[6],将其“显示名称”属性改为“右转”,“点击发送”属性改为“04”,并点击“确定”保存

      以上修改的属性值即为我们点击对应按键之后,蓝牙串口助手自动通过蓝牙发送的数据,与上一篇所定义的小车的几个状态一致,这样方便在Arduino在接收到蓝牙模块的数据后对小车的状态进行控制。

    #define STOP      0
    #define FORWARD   1
    #define BACKWARD  2
    #define TURNLEFT  3
    #define TURNRIGHT 4
    

    修改后属性如下图

    SouthEast

    下面就来看看我们修改的效果吧,点击“模式切换”

    SouthEast
    这时候你就可以看到我们自定义的按键咯,看看修改前后的对比吧。
    SouthEastSouthEast
      接下来我们将连接蓝牙,仍然点击右下角的三个点,然后点击“连接”
    SouthEast
      一般没有连接过蓝牙模块的时候“已配对的设备”下面没有可选择的设备名称,因此我们要点击“扫描新设备”来检测我们的蓝牙模块,扫描成功后蓝牙模块的名称将显示在“已配对的设备”一栏中
    SouthEast
      点击我们的蓝牙模块的名称,输入密码进行配对。配对成功后在蓝牙串口助手的左上角会显示“蓝牙已连接”字样,恭喜你,这时候你已经连接成功。
    SouthEast

    小科普:
      蓝牙模块上电(只简单连接"VCC"和"GND"引脚)之后,其他蓝牙设备即可与其连接,一般蓝牙模块默认初始连接密码为"0000"或"1234",如果连接不上蓝牙,请尽快与厂商或者店家联系。蓝牙模块上电后LED指示灯不断闪亮,当有设备连接预期连接之后会隔一段闪两下,蓝牙串口助手也会有相应已连接的提示。

    ##Arduino代码编写
    新建一个工程,将下面代码复制到工程内

    #define STOP      0
    #define FORWARD   1
    #define BACKWARD  2
    #define TURNLEFT  3
    #define TURNRIGHT 4
    
    int leftMotor1 = 4;
    int leftMotor2 = 5;
    int rightMotor1 = 6;
    int rightMotor2 = 7;
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      pinMode(leftMotor1, OUTPUT);
      pinMode(leftMotor2, OUTPUT);
      pinMode(rightMotor1, OUTPUT);
      pinMode(rightMotor2, OUTPUT);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      //usart read
      if(Serial.available()>0)
      {
        char cmd = Serial.read();//读取蓝牙模块发送到串口的数据
      
        Serial.print(cmd);
        motorRun(cmd);
          
      }  
    }
    void motorRun(int cmd)
    {
      switch(cmd){
        case FORWARD:
          Serial.println("FORWARD"); //输出状态
          digitalWrite(leftMotor1, HIGH);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, HIGH);
          digitalWrite(rightMotor2, LOW);
          break;
         case BACKWARD:
          Serial.println("BACKWARD"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, HIGH);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, HIGH);
          break;
         case TURNLEFT:
          Serial.println("TURN  LEFT"); //输出状态
          digitalWrite(leftMotor1, HIGH);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, HIGH);
          break;
         case TURNRIGHT:
          Serial.println("TURN  RIGHT"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, HIGH);
          digitalWrite(rightMotor1, HIGH);
          digitalWrite(rightMotor2, LOW);
          break;
         default:
          Serial.println("STOP"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, LOW);
      }
    }
    

      朋友们大概也发现了,这个代码和上一篇的代码基本上相同,只不过增加了串口的内容。

    ##代码详解
      串口初始化函数,想要通过串口的库函数对串口进行操作,必须在void set_up()函数中对其进行初始化。

    Serial.begin(9600);
    

      在void loop()函数内,加入了检测串口接收内容的函数,并将接收到的命令输入到 void motorRun(int cmd)函数中控制小车运动。

    if(Serial.available()>0)
      {
        char cmd = Serial.read();
      
        Serial.print(cmd);
        motorRun(cmd);
      }  
    

    蓝牙小车测试

      下载程序之后,重新连接蓝牙模块,切换到我们自定义的按键界面,快试试蓝牙遥控小车吧。

    附件

    安卓手机蓝牙串口点击下载,也可以复制链接 https://download.csdn.net/download/qq_16775293/11165678 到浏览器下载。

    欢迎各位有兴趣的朋友加入Q群1:789127261点评、交流

    展开全文
  • Arduino智能小车——循迹篇

    万次阅读 多人点赞 2017-09-04 11:57:11
    Arduino智能小车——循迹篇   相信大家都在网上看到过类似下图这样的餐厅服务机器人,或者仓库搬运机器人,但是你们有没有注意到图片中地上的那条黑线?没错,他们都是沿着这条黑线来行进的,在这一篇将教大家...

    Arduino智能小车——循迹篇

    Arduino智能小车系列教程时空门:

    1. Arduino智能小车——拼装篇 点击跳转
    2. Arduino智能小车——测试篇 点击跳转
    3. Arduino智能小车——调速篇 点击跳转
    4. Arduino智能小车——超声波避障 点击跳转
    5. Arduino智能小车——蓝牙小车 点击跳转
    6. Arduino智能小车——循迹篇 点击跳转
    7. Arduino智能小车——小车测速 点击跳转

      相信大家都在网上看到过类似下图这样的餐厅服务机器人,或者仓库搬运机器人,但是你们有没有注意到图片中地上的那条黑线?没错,他们都是沿着这条黑线来行进的,在这一篇将教大家怎么用小车实现类似的循迹功能。

    准备材料

    黑色电工胶布

      黑色胶布用于搭建小车运行的“轨道”,选用黑色宽度18mm左右的即可。

    循迹模块

      在此我们使用循迹模块TCRT5000,该模块体积小,灵敏度较高,还可以通过转动上面的电位器来调节检测范围。

    模块特色

    1、采用TCRT5000红外反射传感器
    2、检测距离:1mm~8mm适用,焦点距离为2.5mm
    3、比较器输出,信号干净,波形好,驱动能力强,超过15mA。
    4、配多圈可调精密电位器调节灵敏度
    5、工作电压3.3V-5V
    6、输出形式 :数字开关量输出(0和1)
    7、设有固定螺栓孔,方便安装
    8、小板PCB尺寸:3.2cm x 1.4cm
    9、使用宽电压LM393比较器

    工作原理

      TCRT5000传感器的红外发射二极管不断发射红外线,当发射出的红外线没有被反射回来或被反射回来但强度不够大时,光敏三极管一直处于关断状态,此时模块的输出端为低电平,指示二极管一直处于熄灭状态;被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,光敏三极管饱和,此时模块的输出端为高电平,指示二极管被点亮。

      由于黑色具有较强的吸收能力,当循迹模块发射的红外线照射到黑线时,红外线将会被黑线吸收,导致循迹模块上光敏三极管处于关闭状态,此时模块上一个LED熄灭。在没有检测到黑线时,模块上两个LED常量。
    ##循迹模块安装
      循迹模块的工作一般要求距离待检测的黑线距离1-2cm,因此我建议大家可以将循迹模块向下延伸。我自己是在硬纸板上面打了几个孔,固定循迹模块,每个模块之间可以留1cm左右的距离。传感器在接收到反射不同的距离的时候“AO”引脚电压会不同,是模拟信号,“DO”是数字信号输出。因为在这里我们只用判断是否检测到黑线,因此使用“DO”数字信号即可。按照车头为正方向,从右到左循迹模块的“DO”依次接到开发板“10”、“11”、“12”、“13”引脚。

    ## 跑道的搭建   找一块干净的地面,贴上准备好的黑色电工胶布。由于小车自身结构的原因,转弯的时候尽可能增大转弯半径,在跑道尽头如图中那样拉一条黑色横线,用于小车识别终点。

    测试代码

    #include <Servo.h>
    
    #define STOP      0
    #define FORWARD   1
    #define BACKWARD  2
    #define TURNLEFT  3
    #define TURNRIGHT 4
    
    int leftMotor1 = 16;
    int leftMotor2 = 17;
    int rightMotor1 = 18;
    int rightMotor2 = 19;
    
    int trac1 = 10; //从车头方向的最右边开始排序
    int trac2 = 11; 
    int trac3 = 12; 
    int trac4 = 13; 
    
    int leftPWM = 5;
    int rightPWM = 6;
    
    Servo myServo;  //舵机
    
    int inputPin=7;   // 定义超声波信号接收接口
    int outputPin=8;  // 定义超声波信号发出接口
    
    void setup() {
      // put your setup code here, to run once:
      //串口初始化
      Serial.begin(9600); 
      //舵机引脚初始化
      myServo.attach(9);
      //测速引脚初始化
      pinMode(leftMotor1, OUTPUT);
      pinMode(leftMotor2, OUTPUT);
      pinMode(rightMotor1, OUTPUT);
      pinMode(rightMotor2, OUTPUT);
      pinMode(leftPWM, OUTPUT);
      pinMode(rightPWM, OUTPUT);
      //寻迹模块D0引脚初始化
      pinMode(trac1, INPUT);
      pinMode(trac2, INPUT);
      pinMode(trac3, INPUT);
      pinMode(trac4, INPUT);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
     
      tracing();
          
      
    }
    void motorRun(int cmd,int value)
    {
      analogWrite(leftPWM, value);  //设置PWM输出,即设置速度
      analogWrite(rightPWM, value);
      switch(cmd){
        case FORWARD:
          Serial.println("FORWARD"); //输出状态
          digitalWrite(leftMotor1, HIGH);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, HIGH);
          digitalWrite(rightMotor2, LOW);
          break;
         case BACKWARD:
          Serial.println("BACKWARD"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, HIGH);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, HIGH);
          break;
         case TURNLEFT:
          Serial.println("TURN  LEFT"); //输出状态
          digitalWrite(leftMotor1, HIGH);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, HIGH);
          break;
         case TURNRIGHT:
          Serial.println("TURN  RIGHT"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, HIGH);
          digitalWrite(rightMotor1, HIGH);
          digitalWrite(rightMotor2, LOW);
          break;
         default:
          Serial.println("STOP"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, LOW);
      }
    }
    void tracing()
    {
      int data[4];
      data[0] = digitalRead(10);
      data[1] = digitalRead(11);
      data[2] = digitalRead(12);
      data[3] = digitalRead(13);
    
      if(!data[0] && !data[1] && !data[2] && !data[3])  //左右都没有检测到黑线
      {
        motorRun(FORWARD, 200);
      }
    
      if(data[0] || data[1])  //右边检测到黑线
      {
        motorRun(TURNRIGHT, 150);
      }
    
      if(data[2] || data[3])  //左边检测到黑线
      {
        motorRun(TURNLEFT, 150);
      }
    
      if(data[0] && data[3])  //左右都检测到黑线是停止
      {
        motorRun(STOP, 0);
        while(1);
      }
      
      Serial.print(data[0]);
      Serial.print("---");
      Serial.print(data[1]);
      Serial.print("---");
      Serial.print(data[2]);
      Serial.print("---");
      Serial.println(data[3]);
    }
    

    代码详解

    小车装有4个TCRT5000,从最右边模块开始读入数据,放入data[]数组中

    data[0] = digitalRead(10);
    data[1] = digitalRead(11);
    data[2] = digitalRead(12);
    data[3] = digitalRead(13);
    

    4个模块可能存在的检测状态如下,其中“1”表示检测到黑线,“0”代表没有检测到黑线:

    data[0] data[1] data[2] data[3] 小车运动状态
    1 1 1 1 停止
    0 0 1 1 左转
    0 0 0 1 左转
    0 0 1 0 左转
    1 1 0 0 右转
    1 0 0 0 右转
    0 1 0 0 右转
    0 0 0 0 直行

    第一种情况,四个模块都没有检测到黑线时,直行:

    if(!data[0] && !data[1] && !data[2] && !data[3])  //左右都没有检测到黑线
    {
    	motorRun(FORWARD, 200);
    }
    

    右边任意一个模块检测到黑线时,右转:

    if(data[0] || data[1])  //右边检测到黑线
    {
      motorRun(TURNRIGHT, 150);
    }
    

    左边任意一个模块检测到黑线时,左转:

    if(data[2] || data[3])  //左边检测到黑线
    {
      motorRun(TURNLEFT, 150);
    }
    

    当四个模块都检测到黑线时,说明已经运动到轨道终点,此时停止运动:

    if(data[0] && data[3])  //左右都检测到黑线是停止
    {
      motorRun(STOP, 0);
      while(1);
    }
    

    循迹效果展示

    在起点出准备出发

    弯道中

    识别到终点后停止

    欢迎各位有兴趣的朋友加入Q群1:789127261点评、交流

    展开全文
  • Arduino智能小车——超声波避障

    万次阅读 多人点赞 2017-09-01 21:17:36
    Arduino智能小车——超声波避障  经过这几篇的测试大家应该对小车有一定的认识了,在实际的操作过程中经常会由于操作不当各种碰壁吧?那这次我们将给小车装上一只“眼睛”,让小车看到障碍,躲避障碍。准备材料...

    Arduino智能小车——超声波避障

    Arduino智能小车系列教程时空门:

    1. Arduino智能小车——拼装篇 点击跳转
    2. Arduino智能小车——测试篇 点击跳转
    3. Arduino智能小车——调速篇 点击跳转
    4. Arduino智能小车——超声波避障 点击跳转
    5. Arduino智能小车——蓝牙小车 点击跳转
    6. Arduino智能小车——循迹篇 点击跳转
    7. Arduino智能小车——小车测速 点击跳转

      经过前几篇的测试大家应该对小车有一定的认识了,在实际的操作过程中经常会由于操作不当各种碰壁吧?那这次我们将给小车装上一只“眼睛”,让小车看到障碍,躲避障碍。

    准备材料

    超声波模块HC-SR04

      在这里简单说下超声波测距的原理,相信大家也都知道。超声波发射装置发出超声波,它的根据是接收器接到超声波时的时间差,与雷达测距原理相似。 超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时。

    1. 采用Trig引脚触发,给至少10us的高电平脉冲信号
    2. 模块自动发送8个40kHz的方波,自动检测是否有信号返回
    3. 有信号返回,通过Echo引脚输出一个高电平脉冲,高电平脉冲持续的时间就是超声波从发射到反射返回的时间。距离=(高电平脉冲时间*340)/2。(声音在空气中传播速度为340m/s)
    主要技术参数
    工作电压 DC5V
    静态电流 <2mA
    输出电平 0-5V
    感应角度 ≤15度
    探测距离 2cm-450cm
    最高精度 0.3cm

    ###舵机
      在这里推荐9G舵机SG90,或者其他类似的舵机,这种舵机体积比较小,扭矩虽然不是大, 但是足够带动简易云台,很方便在小车上使用,大家购买时注意舵机的转动角度,有55度的,180度的等等,大家可以根据需要购买。

    舵机固定架

      舵机固定架的购买一定要配合舵机,所以大家购买的时候注意尺寸哦!!~

    舵机安装

      舵机在安装之前大家一定要记得校准,为什么要校准那,这个跟舵机的工作原理有关。控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。
      舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。以180度角度伺服为例,那么对应的控制关系是这样的:

    高电平时间 对应位置
    0.5ms 0度
    1.0ms 45度
    1.5ms 90度
    2.0ms 135度
    2.5ms 180度

      也就是说当对舵机输入相同控制信号时,舵机会运动到固定位置,他的动作不是做圆周运动,而是在运动范围内,每一个位置对应一个控制信号。

      因此我们需要在将舵机安装在固定架上之前,需要先将舵机初始化好,舵机一般为三根线:棕色——GND,红色——VCC,橙色——控制信号。因此我们将棕色线接到GND,红色线接到“+5V”引脚,橙色线接到“10”引脚,初始化程序如下:

    #include <Servo.h>  //加入含有舵机控制库的头文件
    
    #define PIN_SERVO 10  //舵机信号控制引脚
    Servo myservo;  
      
    void setup()  
    {  
      myservo.attach(PIN_SERVO);  //舵机初始化
    }  
      
    void loop()  
    {  
      myservo.write(90);  //PWM输出
    } 
    

      在舵机初始化好之后将其安装在固定架上,然后装配在小车上,此时保证超声波模块超前。

    超声波接线

      估计不少朋友早已经发现板子上的“+5V”和“GND”引脚已经不够用了,这个时候你们可以向我这样焊一个扩展板出来,上面固定两排排针,一排用来扩展“+5V”,一边用来扩展“GND”引脚。

      超声波模块有四个引脚,“VCC”接到Arduino UNO开发板的“+5V”引脚,“GND”接到开发板“GND”引脚,“Trig”引脚接到开发板“8”引脚,“Echo”引脚接到开发板“7”引脚

      线太乱了,真的没办法整理,我自己都没眼看。

    代码测试

    #include <Servo.h>
    
    #define STOP      0
    #define FORWARD   1
    #define BACKWARD  2
    #define TURNLEFT  3
    #define TURNRIGHT 4
    
    int leftMotor1 = 16;
    int leftMotor2 = 17;
    int rightMotor1 = 18;
    int rightMotor2 = 19;
    
    int leftPWM = 5;
    int rightPWM = 6;
    
    Servo myServo;  //舵机
    
    int inputPin=7;   // 定义超声波信号接收接口
    int outputPin=8;  // 定义超声波信号发出接口
    
    void setup() {
      // put your setup code here, to run once:
      //串口初始化
      Serial.begin(9600); 
      //舵机引脚初始化
      myServo.attach(9);
      //测速引脚初始化
      pinMode(leftMotor1, OUTPUT);
      pinMode(leftMotor2, OUTPUT);
      pinMode(rightMotor1, OUTPUT);
      pinMode(rightMotor2, OUTPUT);
      pinMode(leftPWM, OUTPUT);
      pinMode(rightPWM, OUTPUT);
      //超声波控制引脚初始化
      pinMode(inputPin, INPUT);
      pinMode(outputPin, OUTPUT);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      avoidance();
    }
    void motorRun(int cmd,int value)
    {
      analogWrite(leftPWM, value);  //设置PWM输出,即设置速度
      analogWrite(rightPWM, value);
      switch(cmd){
        case FORWARD:
          Serial.println("FORWARD"); //输出状态
          digitalWrite(leftMotor1, HIGH);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, HIGH);
          digitalWrite(rightMotor2, LOW);
          break;
         case BACKWARD:
          Serial.println("BACKWARD"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, HIGH);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, HIGH);
          break;
         case TURNLEFT:
          Serial.println("TURN  LEFT"); //输出状态
          digitalWrite(leftMotor1, HIGH);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, HIGH);
          break;
         case TURNRIGHT:
          Serial.println("TURN  RIGHT"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, HIGH);
          digitalWrite(rightMotor1, HIGH);
          digitalWrite(rightMotor2, LOW);
          break;
         default:
          Serial.println("STOP"); //输出状态
          digitalWrite(leftMotor1, LOW);
          digitalWrite(leftMotor2, LOW);
          digitalWrite(rightMotor1, LOW);
          digitalWrite(rightMotor2, LOW);
      }
    }
    void avoidance()
    {
      int pos;
      int dis[3];//距离
      motorRun(FORWARD,200);
      myServo.write(90);
      dis[1]=getDistance(); //中间
      
      if(dis[1]<30)
      {
        motorRun(STOP,0);
        for (pos = 90; pos <= 150; pos += 1) 
        {
          myServo.write(pos);              // tell servo to go to position in variable 'pos'
          delay(15);                       // waits 15ms for the servo to reach the position
        }
        dis[2]=getDistance(); //左边
        for (pos = 150; pos >= 30; pos -= 1) 
        {
          myServo.write(pos);              // tell servo to go to position in variable 'pos'
          delay(15);                       // waits 15ms for the servo to reach the position
          if(pos==90)
            dis[1]=getDistance(); //中间
        }
        dis[0]=getDistance();  //右边
        for (pos = 30; pos <= 90; pos += 1) 
        {
          myServo.write(pos);              // tell servo to go to position in variable 'pos'
          delay(15);                       // waits 15ms for the servo to reach the position
        }
        if(dis[0]<dis[2]) //右边距离障碍的距离比左边近
        {
          //左转
          motorRun(TURNLEFT,250);
          delay(500);
        }
        else  //右边距离障碍的距离比左边远
        {
          //右转
          motorRun(TURNRIGHT,250);
          delay(500);
        } 
      }
    }
    int getDistance()
    {
      digitalWrite(outputPin, LOW); // 使发出发出超声波信号接口低电平2μs
      delayMicroseconds(2);
      digitalWrite(outputPin, HIGH); // 使发出发出超声波信号接口高电平10μs,这里是至少10μs
      delayMicroseconds(10);
      digitalWrite(outputPin, LOW); // 保持发出超声波信号接口低电平
      int distance = pulseIn(inputPin, HIGH); // 读出脉冲时间
      distance= distance/58; // 将脉冲时间转化为距离(单位:厘米)
      Serial.println(distance); //输出距离值
     
      if (distance >=50)
      {
        //如果距离小于50厘米返回数据
        return 50;
      }//如果距离小于50厘米小灯熄灭
      else
        return distance;
    }
    

    代码详解

    “Trig”引脚控制超声波发出声波,对应int outputPin=8;
    “Echo”引脚反应接收到返回声波,对应int inputPin=7;

    int inputPin=7;   // 定义超声波信号接收接口
    int outputPin=8;  // 定义超声波信号发出接口
    

    int getDistance()函数解析

    超声波发出引脚“Trig”为高时对外发出超声波,为保证发出10μs声波,因此在发送之前需要将该引脚拉低,并给他一定反应时间。

    digitalWrite(outputPin, LOW); // 使发出发出超声波信号接口低电平2μs
    delayMicroseconds(2);
    

    之后发送10μs超声波

    digitalWrite(outputPin, HIGH); // 使发出发出超声波信号接口高电平10μs,这里是至少10μs
    

    声波发送之后禁止其继续发送,同时开始检测是否反射回来的声波

    digitalWrite(outputPin, LOW); // 保持发出超声波信号接口低电平
      int distance = pulseIn(inputPin, HIGH); // 读出脉冲时间
    

    pulseIn()单位为微秒,声速344m/s,所以距离cm=344100/1000000pulseIn()/2约等于pulseIn()/58.0distance= distance/58; // 将脉冲时间转化为距离(单位:厘米)
    超声波模块工作受物体表面反射程度影响,并且在传播过程中信号强度容易衰减,因此该模块适用的检测距离有限,一般在50cm以内相对正确,而且我们在避障时不需要检测太远的距离,因此超过50cm以上的都按50cm计算

    if (distance >=50)
      {
        //如果距离小于50厘米返回数据
        return 50;
      }//如果距离小于50厘米小灯熄灭
      else
        return distance;
    

    void avoidance()函数解析

    小车前进过程中只检测前方距离障碍的距离,并且控制舵机,保持超声波模块位于正前方。

    motorRun(FORWARD,200);
      myServo.write(90);
      dis[1]=getDistance(); //中间
    

    当检测到小车前方距离障碍距离小于30cm时停车,检测两边距离。

    motorRun(STOP,0);
    

    控制舵机每次运动一个周期后都返回正前方位置。由于舵机运动需要一定的时间,因此在每转过一个角度的时候都延时delay(15),供其运动。

    for (pos = 90; pos <= 150; pos += 1) 
    {
          myServo.write(pos);              // tell servo to go to position in variable 'pos'
          delay(15);                       // waits 15ms for the servo to reach the position
    }
    

    当运动到最左边时检测小车左边距离障碍的距离

    dis[2]=getDistance(); //左边
    

    向右边运动,检测右边距离

    for (pos = 150; pos >= 30; pos -= 1) 
    {
      myServo.write(pos);              // tell servo to go to position in variable 'pos'
      delay(15);                       // waits 15ms for the servo to reach the position
      if(pos==90)
        dis[1]=getDistance(); //中间
    }
    dis[0]=getDistance();  //右边
    

    将前边、左边、右边距离障碍的距离都检测结束之后,舵机回到最初位置。

    for (pos = 30; pos <= 90; pos += 1) 
    {
      myServo.write(pos);              // tell servo to go to position in variable 'pos'
      delay(15);                       // waits 15ms for the servo to reach the position
    }
    

    注意事项

    1.舵机使用时要防止其堵转,因为点击堵转时电流会增大,很容易烧坏舵机。
    2.舵机的红色电源线接入电压一般要大于等于其工作电压,供电不足会导致舵机不停自传。
    3.Arduino 《Servo.h》库里提供的write()函数输出的PWM即为舵机专用的20ms为周期的PWM波,如果使用其他开发板或者函数的话,请务必保证输出方波周期为20ms,否则舵机不会受控制

    总结

      这一篇讲解了舵机和超声波模块的使用方法,舵机在大家以后的开发生涯中应该会经常用到,因此舵机的使用规则(控制周期为20ms)请大家一定要记清楚,在舵机不受控制的时候建议大家可以购买一个舵机测试仪来测试舵机。

    欢迎各位有兴趣的朋友加入Q群1:789127261 点评、交流

    展开全文
  • 智能小车资料源码大全

    万次阅读 多人点赞 2018-10-22 11:06:50
    今天给大家分享一下智能小车的资料,包括制作流程、原理图设计和源码等,不下于60辆智能小车的制作经验。其中历届智能小车的开发资料就有90个文件了。 分享的智能小车类型包括:Bluetooth控制两轮小车;智能小车...
  • Arduino智能小车——拼装篇

    万次阅读 多人点赞 2019-05-20 10:24:35
    Arduino智能小车——拼装篇简介Arduino是一款便捷灵活、方便上手的开源电子原型平台,比较适合刚接触硬件的入门级开发者学习。在我身边有很多初学者都陷入了这么一种困境,已经将Arduino官网的教程全部跑完,然而...
  • 亚博智能小车避障实验,arduino,嵌入式,当前方有障碍物时判断左边,若左边无障碍物直接左转。
  • Arduino智能小车——调速篇

    万次阅读 多人点赞 2017-08-31 12:13:26
    Arduino小车——调速篇  在这一篇我们将对小车的行进速度进行调整,将驱动模块的作用发挥出来。首先大家要了解PWM这个概念。PWM  脉宽调制(PWM)基本原理:控制方式就是对逆变电路开关器件的通断进行控制,使输出...
  • Arduino智能小车——测试篇

    万次阅读 多人点赞 2017-08-21 00:53:45
    Arduino智能小车——测试篇 上一章讲解了智能小车的拼装,但是还没有让小车动起来,这章我们将继续拼装,使得小车可以动起来。 驱动模块安装 可能有些朋友会问到,驱动是干嘛的,为什么要驱动,小时候玩四...

空空如也

1 2 3 4 5 ... 20
收藏数 27,078
精华内容 10,831
关键字:

智能小车