Arduino智能小车——循迹篇

Arduino智能小车——循迹篇Arduino智能小车——循迹篇  相信大家都在网上看到过类似下图这样的餐厅服务机器人,或者仓库搬运机器人,但是你们有没有注意到图片中地上的那条黑线?没错,他们都是沿着这条黑线来行进的,在这一篇将教大家怎么用小车实现类似的循迹功能。准备材料循迹模块  在此我们使用循迹模块TCRT5000,该模块体积小,灵敏度较高,还可以通过转动上面的电位器来调节检测范围。

大家好,又见面了,我是你们的朋友全栈君。

Arduino智能小车——循迹篇

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

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

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


Arduino智能小车——循迹篇

准备材料

黑色电工胶布

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


Arduino智能小车——循迹篇

循迹模块

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


Arduino智能小车——循迹篇

模块特色

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


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

Arduino智能小车——循迹篇


测试代码

#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);
}

循迹效果展示

在起点出准备出发


Arduino智能小车——循迹篇

弯道中


Arduino智能小车——循迹篇
识别到终点后停止

Arduino智能小车——循迹篇

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/136381.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java安全之JBoss反序列化漏洞分析

    Java安全之JBoss反序列化漏洞分析0x00前言看到网上的Jboss分析文章较少,从而激发起了兴趣。前段时间一直沉迷于工具开发这块,所以打算将jboss系列反序列化漏洞进行分析并打造成GUI

    2021年12月13日
    41
  • 普通大一学生的自我反思[通俗易懂]

    普通大一学生的自我反思[通俗易懂]​ 暑假高考完,得知自己被计科(普通本科)录取,便开始在知乎等地方搜索相关知识,以此来提高自己的认识。​ 先是在b站上跟着比特鹏哥学完了c语言(基础),这里又要有一大段故事了,我家在江苏扬州,大概是9月份突然爆发了疫情,就被关在家里不让出去,(在家里坐牢,核酸检测,基本隔一天就要做一次)就在B站上天天看鹏哥学c语言,一开始有新鲜劲,学起来还是很有动力的,后来学到指针,很是痛苦,就又专门去B站听了其他的指针教程,学着学着慢慢就明白了,当时每天的生活节奏基本就是,起床打开电脑学习c语言,学饿了,吃点饭(由于疫

    2022年7月15日
    13
  • laravel查询构造器DB还是ORM,这两者有什么区别,各该用在什么场景中

    laravel查询构造器DB还是ORM,这两者有什么区别,各该用在什么场景中

    2021年11月9日
    42
  • Random的nextInt()用法「建议收藏」

    Random的nextInt()用法「建议收藏」Random的nextInt()用法一、先看这样一个有趣的题目:1、设计一个密码的自动生成器:密码由大写字母/小写字母/数字组成,生成六位随机密码。2、分别以1、2、3作为种子数创建Random对象,生成六位随机密码进行测试。问题答案核心代码如下:importjava.util.Random;importjava.util.Scanner;publicclassRandomT…

    2022年7月23日
    9
  • creating server tcp listening socket 127.0.0.1:6379: bind No error

    creating server tcp listening socket 127.0.0.1:6379: bind No errorwindow下启动redis服务报错:creatingservertcplisteningsocket127.0.0.1:6379:bindNoerror的解决方案如下按顺序输入如下命令就可以连接成功redis-cli.exeshutdownexitredis-server.exeredis.windows.conf参考连接:https://blog.csdn….

    2022年5月2日
    47
  • BD和DVD区域划分

    BD和DVD区域划分BD和DVD区域划分BD:A区:只能是在美国、日本以及香港、台湾等东南亚地区正常播放;B区:只能在欧洲和澳洲等国家正常播放;C区:是在中国大陆、俄罗斯和印度三国才能正常播放。DVD:第一区为:美国、加拿大;第二区为:日本、欧洲、埃及、南非、中东;第三区为:中国台湾、中国香港特别行政区、南韩、东南亚;第四区为:澳洲、新西兰、中南美洲、南太平洋岛屿;第五区为:俄罗斯、蒙古、印度

    2022年7月11日
    34

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号