Arduino智能小车系列教程6——循迹小车
Arduino智能小车系列教程
- Arduino智能小车系列教程1——拼装篇
- Arduino智能小车系列教程2——测试篇
- Arduino智能小车系列教程3——调速篇
- Arduino智能小车系列教程4——超声波避障
- Arduino智能小车系列教程5——蓝牙小车
- Arduino智能小车系列教程6——循迹小车
- Arduino智能小车系列教程7——小车测速
文章目录
- 准备材料
- 黑色电工胶布
- 循迹模块
- 模块特色
- 工作原理
- 测试代码
- 代码详解
- 循迹效果展示
相信大家都在网上看到过类似下图这样的餐厅服务机器人,或者仓库搬运机器人,但是你们有没有注意到图片中地上的那条黑线?没错,他们都是沿着这条黑线来行进的,在这一篇将教大家怎么用小车实现类似的循迹功能。
准备材料
黑色电工胶布
黑色胶布用于搭建小车运行的“轨道”,选用黑色宽度18mm左右的即可。
循迹模块
在此我们使用循迹模块TCRT5000,该模块体积小,灵敏度较高,还可以通过转动上面的电位器来调节检测范围。
模块特色
- 采用TCRT5000红外反射传感器
- 检测距离:1mm~8mm适用,焦点距离为2.5mm
- 比较器输出,信号干净,波形好,驱动能力强,超过15mA。
- 配多圈可调精密电位器调节灵敏度
- 工作电压3.3V-5V
- 输出形式 :数字开关量输出(0和1)
- 设有固定螺栓孔,方便安装
- 小板PCB尺寸:3.2cm x 1.4cm
- 使用宽电压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);
}
循迹效果展示
在起点出准备出发