TCRT5000
TCRT5000传感器的红外发射二级管可以不断发射红外线。
模块输出端为高电平:当发射出的红外线没有或反射强度不够大时,红外线接收管就会一直处于关断状态,指示二级管一直处于熄灭状态。
模块输出端为低电平:而当被检测物体出现再检测范围内导致红外线被反射回来且强度足够大,此时红外接收管饱和,指示二级管被点亮。
说人话就是: 反射的强度不够时,DO为高,开关指示灯不亮;反之DO为低,开关指示灯亮
接线方式:
VCC -> 电源正
GND -> 电源负
DO -> TTL开关信号输出0或1
AO -> 模拟信号输出(不同距离输出不同的电压,此脚可以不接)
循迹小车的原理
根据刚刚的模块讲解可知,TCRT5000的DO和灯会根据红外线的反射强度而变化,而查阅资料可知:黑色具有较强的吸收能力,当循迹模块发射的红外线照射到黑色时,大部分红外线会被吸收从而导致DO输出高电平且开关指示灯灭。
所以这就实现了对于黑色的判断,如果在智能小车的左右侧各装上一枚TCRT5000,并在地面上铺设黑色的线,那么就可以由TCR5000的DO和灯的状态判断是否行驶在黑线上的判断,而当判断快要离开黑线时,通过上节学习的知识控制小车回到轨迹,这就是寻迹小车的实现。
循迹小车接线
关于两个TCRT5000传感器的正负极接线:
注意:不能将传感器的正负极直接接在面包板的正负极,这样会导致电压过大烧坏传感器!
安装完两个传感器之后如图:(两个传感器的DO分别接在单片机的P2.6和P2.7)
循迹小车的编程实现
根据之前的逻辑,封装一个route_sensor.c:
#include "reg52.h"
#include "motor.h"
#include "timer0.h"
sbit sensor_left = P2^7;
sbit sensor_right = P2^6;
void sensor_react()
{
if(sensor_left == 0 && sensor_right == 0){ //此时左右都没有检测到黑线,说明在轨迹上,直走, 两个灯都亮
move_forward();
}
if(sensor_left == 1 && sensor_right == 0){ //此时左模块检测到黑线,说明车身偏右即将离开轨道,此时需要左转修正,只有右灯亮
move_leftturn();
}
if(sensor_left == 0 && sensor_right == 1){ //此时右模块检测到黑线,说明车身偏左即将离开轨道,此时需要右转修正,只有左灯亮
move_rightturn();
}
if(sensor_left == 1 && sensor_right == 1){ //此时左右都检测到黑线,说明不在轨迹上了,停止,两个灯都灭
move_stop();
}
}
main.c:
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include "motor.h"
#include "delay.h"
#include "UART.h"
#include "433M.h"
#include "timer0.h"
#include "route_sensor.h"
void main()
{
while(1){
sensor_react();
}
}
实现效果:
1. 由于我的桌面是黑色的,所以如果不用白纸,那么就模拟了不在轨道上,轮子不会动;
2. 当白纸遮挡了左边传感器,就相当于右侧检测到黑线,模拟了小车向左偏离了轨道,需要右转修正,因此只有左轮动;
3. 当白纸遮挡了右边传感器,就相当于左侧检测到黑线,模拟了小车向右偏离了轨道,需要左转修正,因此只有右轮动;
4. 当白纸同时遮挡了两个传感器,就相当于黑线在传感器之间,模拟了小车正常行驶,需要直行,所以左右轮一起转动;
实际循迹中的问题
这样乍一看似乎已经成功实现了,然而其实有些问题:当我实际搭建轨道试运行的时候,小车还是会经常性的跑离轨道,这就是小车的速度和灵敏度的配合问题了:用螺丝刀调整传感器的灵敏度(顺时针变灵敏逆时针变迟钝),并使用之前两轮分别进行调速的代码对左右轮进行微调,我修改了代码让小车的直行速度慢一些,(且由于我的小车的右电机似乎更强大一点,所以右电机的速度略慢于左电机达到平衡)
修改后的route_sensor.c:
#include "reg52.h"
#include "motor.h"
#include "timer0.h"
sbit sensor_left = P2^7;
sbit sensor_right = P2^6;
extern char speed_left;
extern char speed_right;
void sensor_react()
{
if(sensor_left == 0 && sensor_right == 0){ //此时左右都没有检测到黑线,说明在轨迹上,直走, 两个灯都亮
//move_forward();
speed_left = 22; // 22/40 的时间在全速前进
speed_right = 20; // 20/40 的时间在全速前进,所以会略慢于左轮,实际表现中就恰好是直行
}
if(sensor_left == 1 && sensor_right == 0){ //此时左模块检测到黑线,说明车身偏右即将离开轨道,此时需要左转修正,只有右灯亮
move_leftturn();
}
if(sensor_left == 0 && sensor_right == 1){ //此时右模块检测到黑线,说明车身偏左即将离开轨道,此时需要右转修正,只有左灯亮
move_rightturn();
}
if(sensor_left == 1 && sensor_right == 1){ //此时左右都检测到黑线,说明不在轨迹上了,停止,两个灯都灭
//move_stop();//此处用STOP函数也不好,因为stop命令发送时,可能定时器还在计时发送PWM波,指令会有微小的冲突从而发出电流声
speed_left = 0;
speed_right = 0;
}
}
实现的效果:
PS:可以看到,小车行驶过程中其实还是不太平滑,那么其实平滑的方法也不难,现在不平滑的原因是转弯的时候一只轮子其实是不动的,那其实如果像我调整直线行驶一样,对两个轮子分别调速,只是确保左轮的speed_left 小于 speed_right就可以实现比较平滑的行驶了(例如speed_left = 10;speed_right = 40 ),但是我认为平滑的代价就是转弯的灵敏度会下降,比如我铺设的道理的弯道比较密集,采用这种方法虽然可以平滑,但是也会导致小车更容易发生“还没转好就冲出轨道”的问题,所以我暂时没有修改这个平滑转弯的代码。
那有没有办法把以上的平滑代码更加细化呢,方法之一就是细化PWM波,现在调整PWM波的最小单位是0.5ms,如果减小这个时间,理论上就可以更加细化的调整速度。