Arduino智能小车——循迹篇

悠悠 2022-06-09 10:48 1185阅读 0赞

Arduino智能小车——循迹篇

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

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

文章目录

  • Arduino智能小车——循迹篇
    • 准备材料
      • 黑色电工胶布
      • 循迹模块
        • 模块特色
        • 工作原理
    • 测试代码
    • 代码详解
    • 循迹效果展示

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

SouthEast

准备材料

黑色电工胶布

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

SouthEast 1

循迹模块

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

SouthEast 2

模块特色

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”引脚。

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


测试代码

  1. #include <Servo.h>
  2. #define STOP 0
  3. #define FORWARD 1
  4. #define BACKWARD 2
  5. #define TURNLEFT 3
  6. #define TURNRIGHT 4
  7. int leftMotor1 = 16;
  8. int leftMotor2 = 17;
  9. int rightMotor1 = 18;
  10. int rightMotor2 = 19;
  11. int trac1 = 10; //从车头方向的最右边开始排序
  12. int trac2 = 11;
  13. int trac3 = 12;
  14. int trac4 = 13;
  15. int leftPWM = 5;
  16. int rightPWM = 6;
  17. Servo myServo; //舵机
  18. int inputPin=7; // 定义超声波信号接收接口
  19. int outputPin=8; // 定义超声波信号发出接口
  20. void setup() {
  21. // put your setup code here, to run once:
  22. //串口初始化
  23. Serial.begin(9600);
  24. //舵机引脚初始化
  25. myServo.attach(9);
  26. //测速引脚初始化
  27. pinMode(leftMotor1, OUTPUT);
  28. pinMode(leftMotor2, OUTPUT);
  29. pinMode(rightMotor1, OUTPUT);
  30. pinMode(rightMotor2, OUTPUT);
  31. pinMode(leftPWM, OUTPUT);
  32. pinMode(rightPWM, OUTPUT);
  33. //寻迹模块D0引脚初始化
  34. pinMode(trac1, INPUT);
  35. pinMode(trac2, INPUT);
  36. pinMode(trac3, INPUT);
  37. pinMode(trac4, INPUT);
  38. }
  39. void loop() {
  40. // put your main code here, to run repeatedly:
  41. tracing();
  42. }
  43. void motorRun(int cmd,int value)
  44. {
  45. analogWrite(leftPWM, value); //设置PWM输出,即设置速度
  46. analogWrite(rightPWM, value);
  47. switch(cmd){
  48. case FORWARD:
  49. Serial.println("FORWARD"); //输出状态
  50. digitalWrite(leftMotor1, HIGH);
  51. digitalWrite(leftMotor2, LOW);
  52. digitalWrite(rightMotor1, HIGH);
  53. digitalWrite(rightMotor2, LOW);
  54. break;
  55. case BACKWARD:
  56. Serial.println("BACKWARD"); //输出状态
  57. digitalWrite(leftMotor1, LOW);
  58. digitalWrite(leftMotor2, HIGH);
  59. digitalWrite(rightMotor1, LOW);
  60. digitalWrite(rightMotor2, HIGH);
  61. break;
  62. case TURNLEFT:
  63. Serial.println("TURN LEFT"); //输出状态
  64. digitalWrite(leftMotor1, HIGH);
  65. digitalWrite(leftMotor2, LOW);
  66. digitalWrite(rightMotor1, LOW);
  67. digitalWrite(rightMotor2, HIGH);
  68. break;
  69. case TURNRIGHT:
  70. Serial.println("TURN RIGHT"); //输出状态
  71. digitalWrite(leftMotor1, LOW);
  72. digitalWrite(leftMotor2, HIGH);
  73. digitalWrite(rightMotor1, HIGH);
  74. digitalWrite(rightMotor2, LOW);
  75. break;
  76. default:
  77. Serial.println("STOP"); //输出状态
  78. digitalWrite(leftMotor1, LOW);
  79. digitalWrite(leftMotor2, LOW);
  80. digitalWrite(rightMotor1, LOW);
  81. digitalWrite(rightMotor2, LOW);
  82. }
  83. }
  84. void tracing()
  85. {
  86. int data[4];
  87. data[0] = digitalRead(10);
  88. data[1] = digitalRead(11);
  89. data[2] = digitalRead(12);
  90. data[3] = digitalRead(13);
  91. if(!data[0] && !data[1] && !data[2] && !data[3]) //左右都没有检测到黑线
  92. {
  93. motorRun(FORWARD, 200);
  94. }
  95. if(data[0] || data[1]) //右边检测到黑线
  96. {
  97. motorRun(TURNRIGHT, 150);
  98. }
  99. if(data[2] || data[3]) //左边检测到黑线
  100. {
  101. motorRun(TURNLEFT, 150);
  102. }
  103. if(data[0] && data[3]) //左右都检测到黑线是停止
  104. {
  105. motorRun(STOP, 0);
  106. while(1);
  107. }
  108. Serial.print(data[0]);
  109. Serial.print("---");
  110. Serial.print(data[1]);
  111. Serial.print("---");
  112. Serial.print(data[2]);
  113. Serial.print("---");
  114. Serial.println(data[3]);
  115. }

代码详解

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

  1. data[0] = digitalRead(10);
  2. data[1] = digitalRead(11);
  3. data[2] = digitalRead(12);
  4. 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 直行

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

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

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

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

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

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

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

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

循迹效果展示

在起点出准备出发

SouthEast 5

弯道中

SouthEast 6 识别到终点后停止 SouthEast 7

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

发表评论

表情:
评论列表 (有 0 条评论,1185人围观)

还没有评论,来说两句吧...

相关阅读