寻迹小车

一、绪论


1.1 实验背景
1.1.1 问题的情景

长期以来,由于我国是人口大国而且工业基础薄弱,因此早期在我国机器人的发展受到一定的限制。然而随着制造业工人的人力成本的不断上升与社会自动化程度的不断提高,我国也开始着重于发展机器人,并且也取得了较大的进步。在 1995 年,我国沈阳自动化所开始研制HT—100A点焊机器人,是我国较早的机器人了,如图1所示;此后,沈阳新松公司研发出了6 kg弧焊机器人,此机器人不仅实用,而且轻便,如图 2 所示;之后,哈尔滨工业大学机器 人研究所也研发出了便携式机器人,此机器人具有 6 自由度,增强了焊接能力,成为在恶劣环境中实现焊接功能的重要设备。总之,在国家“863 计划”与“十一五”计划的指导下,我国机器人的设计取得了飞速发 展,甚至在机器人的某些关键部件的设计已经接近于世界先进水平,并在世界工业机器人领域已经占有一席之地了。

1

2

1.1.2 实验的目的

目前,机器人的发展趋势非常的迅猛,机器人可以替代人类去从事高危险的工作,减轻了人类的劳动强度。本文通过对机器人的发展史进行简要的介绍,阐明了我国发展机器人的必要性。同时,对于我国的发展而言,我国正处于工业化进程的关键时期,将来的高强度、高危险行业的工人数量将会急剧的下降,机器人将会迎来新的“春天”,所以机器人的发展仍拥有巨大的发展空间。同时,由于我国各机器人的厂商对于机器人的研发能力与金钱投资的不同,在我国的机器人市场上的竞争也会愈演愈烈,最终也将形成我国的机器人研发市场。总之,在未来的几十年里,相信重点发展机器人将会成为社会的发展趋势,不久机器人将会引领未来,加入到我国现代化建设的行列中。小车,也就是轮式机器人,作为以学科交叉、产品创新为特色的明月班同学,切入这个产业不失为优秀的选择,故而选取小车为切入点了解相关知识。

1.2 实验内容
1.2.1 使用51单片机控制及其元器件

STC89C52控制板芯片、1.5V干电池x4、L298N电机驱动板x1、红外循迹模块、直流电机x2以及搭建材料若干;

3

1.2.2使用FPGA开发板控制及其元器件

Cyclonell EP2C5T144控制板芯片1.5V干电池x4、L298N电机驱动板x1、红外循迹模块、直流电机x2以及搭建材料若干;

4


二、实现过程


2.1 总体工作原理简释
2.1.2 红外循迹模块

第一步,位于小车前端的红外模块会释放红外线探测下方是否为黑色区域,并将相应的高低电平信号传递至控制模块(51单片机/FPGA开发板)处理,控制模块随后将发送信息至L298N电机驱动的控制模块,并由此控制左右两轮的转动速度以及转动方向,从而实现对黑线的反应和循迹。

作为电机的驱动模块,该模块对控制小车移动有着重要且直接的作用。

5

利用红外发射器向地面发射红外线,并用传感器接收由地面反射的红外线。当红外接收模块下方为黑色轨迹时,红外线被黑色轨迹吸收,传感器没有接收到红外线,红外循迹模块输出低电平到单片机。反之,传感器接收到红外线,红外循迹模块输出高电平到单片机。可通过红外循迹模块输出的信号来判断小车是否偏离轨迹。可调电阻可以调节传感器的灵敏度,易于调试。使用红外循迹模块方案也易于实现,红外循迹方案相比于摄像循迹成本更加便宜,软件设计更加简单,设计制作周期短,具备一定可靠性。

对于左电机,共有输入ENA、IN1、IN2,输出OUT1(黑线)、OUT2(红线)、其信号与运动对应如下:(0,X,X)停止、(1,0,0)停止、(1,1,0)正传、(1,0,1)反转、(1,1,1)停止;

对于右电机,共有输入ENB、IN3、IN4,输出OUT3(黑线)、OUT4(红线),其信号与运动对应如下:(0,X,X)停止、(1,0,0)停止、(1,1,0)反传、(1,0,1)正转、(1,1,1)停止。

2.1.3 L298N电机驱动模块

6

L298N是ST公司的一款电机驱动芯片,也是集成了双H桥,但与上面两个略有不同。电机驱动电压3~48V;可持续工作的输出电流为2A,峰值可达3A。如上图,L298N模块明显有较多的外接元件,这与L298N的内部结构有关。如上图,由于该芯片在H桥上的损耗严重发热较明显(饱和压降大),需要加装散热片,因此在使用上比前两个芯片复杂,体积也相对较大。其各引脚如下图所示。

7

2.2 使用51单片机部分
2.2.1 硬件接线

8

9

1为电源输入,与电池盒的输出线相连;2为电源输出,3为驱动板输入,两者需要相连,注意红线为VCC,黑线为GND;4 为单片机IO口引脚,5为驱动板的IN1到 IN4以及ENA和ENB,按照器件上的标注对应连接即可。 6 为与循迹模块的对应接口,按照器件上的标注对应连接即可。 7 和 8 为驱动板与两个电机之间的连线,按照上图所示连接即可。 到这里,基本完成了小车的硬件组装与线路连接,小车要完成循迹进行这些连线就够了,不过在烧录程序到单片机中时还需要 额外的连线,这个将在后面进行说明。

供电上使用四节5号电池。

2.2.2 程序设计

首先是如何处理红外模块的探测结果。我们需要先对结果进行编码。我们记没有识别到黑线为0,识别到为1,则我们需要一个算式来囊括左右传感器结果并能对不同情况进行表示。在这里,我们记data2为左边的结果,data3为右边的结果,现给出算式data1=data2*10+data3,data1即检测结果。根据data2、data3不同组合:(1,1)在黑线上;(1,0)略向右偏离;(0,1)略向左偏离;(0,0)完全偏离轨道,分别对应了data1的四个取值,即11、10、1、0,亦即四种情况。相应的,我们需要做出四种反馈,即“前进”、“左转”、“右转”、“停下”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <reg52.h>//51头文件
unsigned char pwm\_val\_left, pwm\_val\_right; //中间变量
unsigned char pwm\_left, pwm\_right; //定义PWM输出高电平的时间的变量(用户操作PWM的变量)
#define PWM\_DUTY 100 //定义PWM的周期,数值为定时器0溢出周期,假如定时器溢出时间为100us,则PWM周期为10ms。
#define PWM\_HIGH\_MIN 35 //限制PWM输出的最小占空比
#define PWM\_HIGH\_MAX PWM\_DUTY //限制PWM输出的最大占空比

/\*电机驱动IO定义\*/
sbit leftMotorPwm = P1^5; //为1 左电机使能
sbit IN1 = P1^4; //为1 左电机正转
sbit IN2 = P1^3; //为1 左电机反转
sbit IN3 = P1^2; //为1 右电机反转
sbit IN4 = P1^1; //为1 右电机正转
sbit rightMotorPwm = P1^0; //为1 右电机使能

sbit leftSensor = P3^4;//左传感器:为0没有识别到黑线,为1识别到黑线
sbit rightSensor = P3^5;//右传感器:为0没有识别到黑线,为1识别到黑线

void Timer0\_Init(void); //定时器初始化
void LoadPWM(void);//装入PWM输出值
void forward(unsigned char LeftSpeed, unsigned char RightSpeed);//前进
void left\_run(unsigned char LeftSpeed, unsigned char RightSpeed);//左转
void right\_run(unsigned char LeftSpeed, unsigned char RightSpeed);//右转
void back(void);//后退修正

void Tracking()
{
//为0 没有识别到黑线 为1识别到黑线
char data1, data2 = leftSensor,data3 = rightSensor;
data1 = data2\*10+data3;
if(data1 == 11)//在黑线上,前进
{
//forward(120,120);//前进
forward(70,70);//前进
}
else
{
if(data1 == 10)//小幅偏右,左转
{
//left\_run(80,160);//左转
left\_run(70,70);//左转
}
if(data1 == 1)//小幅偏左,右转
{
//right\_run(160,80);//右转
right\_run(70,70);//右转
}
if(data1 == 0)//大幅偏左或偏右,已脱离轨道
{
back();//后退校正
}
}
}

/\*主函数\*/
void main(void)
{
Timer0\_Init();//定时0初始化
while(1)
{
Tracking();
}
}

void forward(unsigned char LeftSpeed,unsigned char RightSpeed)
{
pwm\_left = LeftSpeed,pwm\_right = RightSpeed;//设置速度
IN1 = 1;
IN2 = 0;
IN3 = 0;
IN4 = 1;
}

void left\_run(unsigned char LeftSpeed, unsigned char RightSpeed)
{
pwm\_left = LeftSpeed,pwm\_right = RightSpeed;//设置速度
IN1 = 1;
IN2 = 0;
IN3 = 1;
IN4 = 0;
}

void right\_run(unsigned char LeftSpeed, unsigned char RightSpeed)
{
pwm\_left = LeftSpeed,pwm\_right = RightSpeed;//设置速度
IN1 = 0;
IN2 = 1;
IN3 = 0;
IN4 = 1;
}

void back(void)
{
pwm\_left = LeftSpeed,pwm\_right = RightSpeed;//设置速度
IN1 = 0;
IN2 = 1;
IN3 = 1;
IN4 = 0;
}

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* Timer0初始化\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void Timer0\_Init(void)
{
TMOD |= 0x02;//定时器0,8位自动重装模块
TH0 = 164;
TL0 = 164;//11.0592M晶振,12T溢出时间约等于100微秒
TR0 = 1;//启动定时器0
ET0 = 1;//允许定时器0中断
EA = 1;//总中断允许
}

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* Timer0中断函数\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
void timer0\_int (void) interrupt 1
{
pwm\_val\_left++;
pwm\_val\_right++;
if(pwm\_left > PWM\_HIGH\_MAX) pwm\_left = PWM\_HIGH\_MAX; //如果左输出写入大于最大占空比数据,则强制为最大占空比。
if(pwm\_left < PWM\_HIGH\_MIN) pwm\_left = PWM\_HIGH\_MIN; //如果左输出写入小于最小占空比数据,则强制为最小占空比。
if(pwm\_right > PWM\_HIGH\_MAX) pwm\_right = PWM\_HIGH\_MAX; //如果右输出写入大于最大占空比数据,则强制为最大占空比。
if(pwm\_right < PWM\_HIGH\_MIN) pwm\_right = PWM\_HIGH\_MIN; //如果右输出写入小于最小占空比数据,则强制为最小占空比。
if(pwm\_val\_left<=pwm\_left) leftMotorPwm = 1; //装载左PWM输出高电平时间
else leftMotorPwm = 0; //装载左PWM输出低电平时间
if(pwm\_val\_left>=PWM\_DUTY) pwm\_val\_left = 0; //如果左对比值大于等于最大占空比数据,则为零
if(pwm\_val\_right<=pwm\_right) rightMotorPwm = 1; //装载右PWM输出高电平时间
else rightMotorPwm = 0; //装载右PWM输出低电平时间
if(pwm\_val\_right>=PWM\_DUTY) pwm\_val\_right = 0; //如果右对比值大于等于最大占空比数据,则为零
}
2.3 使用FPGA开发板部分
2.3.1 硬件接线

系统时钟和复位信号必须为PIN17和PIN_90,不过这两个引脚在开发板上已经连接上了,无须手动连接。其它的引脚可以在下表中“FPGA引出I/O”部分选择即可,然后参照之间的51单片机进行连接。

此处附上接线实物图,需要注意的是,FPGA需要独立的接线供电,如充电宝等等。

10

2.3.2程序设计

逻辑上大体与51相同,此处附上代码部分以及引脚的设置图。

11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
LIBRARY ieee;
USE ieee.std\_logic\_1164.all;
ENTITY cartracking IS
GENERIC (
--时钟为50MHz,为了产生100Hz的PWM波,设置计数值为500000
cnt\_meta : INTEGER := 500000;
--对应了停止、前进、左转、右转状态IN4到IN1的输出
Back : STD\_LOGIC\_VECTOR(3 DOWNTO 0) := "0110";
Forward : STD\_LOGIC\_VECTOR(3 DOWNTO 0) := "1001";
Left\_Go : STD\_LOGIC\_VECTOR(3 DOWNTO 0) := "0101";
Right\_Go : STD\_LOGIC\_VECTOR(3 DOWNTO 0) := "1010"
);

--\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*输入输出端口\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
PORT (
sys\_clk : IN STD\_LOGIC;
sys\_rst\_n : IN STD\_LOGIC;
infrared : IN STD\_LOGIC\_VECTOR(1 DOWNTO 0);
pwm\_left : OUT STD\_LOGIC;
pwm\_right : OUT STD\_LOGIC;
in\_motor : OUT STD\_LOGIC\_VECTOR(3 DOWNTO 0)
);
END cartracking;

ARCHITECTURE trans OF cartracking IS
SIGNAL cnt : INTEGER;
SIGNAL duty\_left : INTEGER;
SIGNAL duty\_right : INTEGER;
BEGIN
PROCESS (sys\_rst\_n, infrared)
BEGIN
IF (sys\_rst\_n = '0') THEN
duty\_right <= 60;
duty\_left <= 60;
ELSE
CASE infrared IS
WHEN "00" =>
in\_motor <= Back;--后退
WHEN "01" =>
in\_motor <= Right\_Go;--右转
--PWM波的占空比,应设置合适的值来控制小车的转速,为了在仿真时可以对比,特将左右轮设置了不同的占空比。
duty\_left <= 35;
duty\_right <= 55;
WHEN "10" =>
in\_motor <= Left\_Go;--左转
duty\_left <= 55;
duty\_right <= 35;
WHEN OTHERS =>
in\_motor <= Forward;--前进
duty\_left <= 50;
duty\_right <= 50;
END CASE;
END IF;
END PROCESS;

PROCESS (sys\_clk, sys\_rst\_n)
BEGIN
IF (sys\_rst\_n = '0') THEN
cnt <= 0;
ELSIF (sys\_clk'EVENT AND sys\_clk = '1') THEN
IF (cnt = cnt\_meta) THEN
cnt <= 0;
ELSE
cnt <= cnt + 1;
END IF;
END IF;
END PROCESS;

PROCESS (sys\_clk, sys\_rst\_n)
BEGIN
IF (sys\_rst\_n = '0') THEN
pwm\_left <= '0';
pwm\_right <= '0';
ELSIF (sys\_clk'EVENT AND sys\_clk = '1') THEN
IF (cnt >= (cnt\_meta / 100)\* duty\_left) THEN
pwm\_left <= '0';
ELSE
pwm\_left <= '1';
END IF;
IF (cnt >= (cnt\_meta / 100) \* duty\_right) THEN
pwm\_right <= '0';
ELSE
pwm\_right <= '1';
END IF;
END IF;
END PROCESS;
END trans;

3调试及优化


3.1简单优化

由于在测试时需要在保证小车前进速度的同时兼顾其转弯的效率和稳定性,特别是如果直行时转速过快会导致小车在转弯时直接冲出赛道而无法循迹。在原本的设计中,我们将未识别到黑线的反应设置为电机停转而使得小车停止,而这会使得小车无法在冲出赛道后进行自我校正。因此,我们将未识别到黑线时的输出信号由“0000”改为“0110”,即使得左右电机均由原本的停转改为反转,从而实现循迹过程中对于轨道循迹的自我修正。

在 PWM 频率设置的时候, PWM 的频率太低可能导致电机转动不稳定,不 是匀速转动,而 PWM 频率过高可能导致电机反应不过来或者超过电路的上限截止频率。事实上,考虑到转弯过程的稳定性与速度问题,包括与直行过程的速度以及传感器的灵敏度调节配合,我们需要通过实际测试来进一步确定在直行、左转、右转和倒退过程中设定的PWM占空比与转速。具体在调试之后所得到的合适参数已经在上面的代码中有所体现,在此不过多赘述。

12

13

3.2调试过程

考虑到验收时的重要评判标准是小车循迹一周的时间,且小车本身运动缓慢,我们首先将目光放在了转速的提高上。修改参数大幅提高了轮子的转速后,我们进行了一次实验:结果出乎意料,小车非但没有预想的那样,反而在行进的过程中持续摇摆。分析原因是行进角度不平行于轨道时容易冲出轨道,后续针对此原因,在红外灵敏度以及直行、左转、右转和倒退过程中设定的PWM占空比与转速多次调试与测试。中途红外模块损坏,经过排查确定后更换了新的。此外,我们注意到行进中的不稳定性还来自于万向轮的松散,我们尝试了不限于胶带、缠绳等各种方式加以限制,效果均不理想,虽然直道可以稳定快速行进,转弯却尤为吃力。

最后51的部分取得了第二名的不错成绩。但是FPGA部分却难遂人意。我们一直将注意力放在数据的调试上却忽略了时间的把控,以至于直到最后快结束才仓促进行测试,测试时还发生了接线断开等突发状况。我们本着希望更加灵活的愿望想别的同学借来充电宝供电,没想到这成为了测试失败的最大缘由——充电宝供电严重不足,导致小车行进乏力,但等到我们重新接上电脑供电确认可以正常运行时,却被告知时间已到,不允许再次测试以保证公平。最后无奈接受这个最慢的成绩。


参考文献


[1] 默默无闻小菜鸡. 电机驱动芯片(H桥、直流电机驱动方式)——DRV8833、TB6612、A4950、L298N的详解与比较[EB/OL]. https://blog.csdn.net/qq_44897194/article/details/105524808, 2020-5-11.

[2] 周海,叶兵. 机器人的发展现状及应用前景[J]. https://kns.cnki.net/kcms2/article/abstract?v=3uoqIhG8C44YLTlOAiTRKibYlV5Vjs7iAEhECQAQ9aTiC5BjCgn0Rn5ykE3W8_mbbrKtMuQk3r9gP-p4derKJErhs1XrNO9Y&uniplatform=NZKPT, 2017-6-18.


致谢


感谢老师们在本课程中的精心准备与付出。在数电和模电部分得到了曾正教授和袁刚教授的悉心教诲,在后续的项目部分得到了李敏教授和凌睿教授的认真指导,最终得以基本实现预定目标,特此鸣谢!

作者

明诚

发布于

2023-03-05

更新于

2023-08-03

许可协议

评论