一、绪论
1.1 实验背景 1.1.1 问题的情景 长期以来,由于我国是人口大国而且工业基础薄弱,因此早期在我国机器人的发展受到一定的限制。然而随着制造业工人的人力成本的不断上升与社会自动化程度的不断提高,我国也开始着重于发展机器人,并且也取得了较大的进步。在 1995 年,我国沈阳自动化所开始研制HT—100A点焊机器人,是我国较早的机器人了,如图1所示;此后,沈阳新松公司研发出了6 kg弧焊机器人,此机器人不仅实用,而且轻便,如图 2 所示;之后,哈尔滨工业大学机器 人研究所也研发出了便携式机器人,此机器人具有 6 自由度,增强了焊接能力,成为在恶劣环境中实现焊接功能的重要设备。总之,在国家“863 计划”与“十一五”计划的指导下,我国机器人的设计取得了飞速发 展,甚至在机器人的某些关键部件的设计已经接近于世界先进水平,并在世界工业机器人领域已经占有一席之地了。
1.1.2 实验的目的 目前,机器人的发展趋势非常的迅猛,机器人可以替代人类去从事高危险的工作,减轻了人类的劳动强度。本文通过对机器人的发展史进行简要的介绍,阐明了我国发展机器人的必要性。同时,对于我国的发展而言,我国正处于工业化进程的关键时期,将来的高强度、高危险行业的工人数量将会急剧的下降,机器人将会迎来新的“春天”,所以机器人的发展仍拥有巨大的发展空间。同时,由于我国各机器人的厂商对于机器人的研发能力与金钱投资的不同,在我国的机器人市场上的竞争也会愈演愈烈,最终也将形成我国的机器人研发市场。总之,在未来的几十年里,相信重点发展机器人将会成为社会的发展趋势,不久机器人将会引领未来,加入到我国现代化建设的行列中。小车,也就是轮式机器人,作为以学科交叉、产品创新为特色的明月班同学,切入这个产业不失为优秀的选择,故而选取小车为切入点了解相关知识。
1.2 实验内容 1.2.1 使用51单片机控制及其元器件 STC89C52控制板芯片、1.5V干电池x4、L298N电机驱动板x1、红外循迹模块、直流电机x2以及搭建材料若干;
1.2.2使用FPGA开发板控制及其元器件 Cyclonell EP2C5T144控制板芯片1.5V干电池x4、L298N电机驱动板x1、红外循迹模块、直流电机x2以及搭建材料若干;
二、实现过程
2.1 总体工作原理简释 2.1.2 红外循迹模块 第一步,位于小车前端的红外模块会释放红外线探测下方是否为黑色区域,并将相应的高低电平信号传递至控制模块(51单片机/FPGA开发板)处理,控制模块随后将发送信息至L298N电机驱动的控制模块,并由此控制左右两轮的转动速度以及转动方向,从而实现对黑线的反应和循迹。
作为电机的驱动模块,该模块对控制小车移动有着重要且直接的作用。
利用红外发射器向地面发射红外线,并用传感器接收由地面反射的红外线。当红外接收模块下方为黑色轨迹时,红外线被黑色轨迹吸收,传感器没有接收到红外线,红外循迹模块输出低电平到单片机。反之,传感器接收到红外线,红外循迹模块输出高电平到单片机。可通过红外循迹模块输出的信号来判断小车是否偏离轨迹。可调电阻可以调节传感器的灵敏度,易于调试。使用红外循迹模块方案也易于实现,红外循迹方案相比于摄像循迹成本更加便宜,软件设计更加简单,设计制作周期短,具备一定可靠性。
对于左电机,共有输入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电机驱动模块
L298N是ST公司的一款电机驱动芯片,也是集成了双H桥,但与上面两个略有不同。电机驱动电压3~48V;可持续工作的输出电流为2A,峰值可达3A。如上图,L298N模块明显有较多的外接元件,这与L298N的内部结构有关。如上图,由于该芯片在H桥上的损耗严重发热较明显(饱和压降大),需要加装散热片,因此在使用上比前两个芯片复杂,体积也相对较大。其各引脚如下图所示。
2.2 使用51单片机部分 2.2.1 硬件接线
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> unsigned char pwm\_val\_left, pwm\_val\_right; unsigned char pwm\_left, pwm\_right; #define PWM\_DUTY 100 #define PWM\_HIGH\_MIN 35 #define PWM\_HIGH\_MAX PWM\_DUTY /\*电机驱动IO定义\*/ sbit leftMotorPwm = P1^5 ; sbit IN1 = P1^4 ; sbit IN2 = P1^3 ; sbit IN3 = P1^2 ; sbit IN4 = P1^1 ; sbit rightMotorPwm = P1^0 ; sbit leftSensor = P3^4 ; sbit rightSensor = P3^5 ; void Timer0\_Init(void ); void LoadPWM (void ) ;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 () { char data1, data2 = leftSensor,data3 = rightSensor;data1 = data2\*10 +data3; if (data1 == 11 ){ forward(70 ,70 ); } else { if (data1 == 10 ){ left\_run(70 ,70 ); } if (data1 == 1 ){ right\_run(70 ,70 ); } if (data1 == 0 ){ back(); } } } /\*主函数\*/ void main (void ) { Timer0\_Init(); 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 ; TH0 = 164 ; TL0 = 164 ; TR0 = 1 ; ET0 = 1 ; 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 ; else leftMotorPwm = 0 ; if (pwm\_val\_left>=PWM\_DUTY) pwm\_val\_left = 0 ; if (pwm\_val\_right<=pwm\_right) rightMotorPwm = 1 ; else rightMotorPwm = 0 ; if (pwm\_val\_right>=PWM\_DUTY) pwm\_val\_right = 0 ; }
2.3 使用FPGA开发板部分 2.3.1 硬件接线 系统时钟和复位信号必须为PIN17和PIN_90,不过这两个引脚在开发板上已经连接上了,无须手动连接。其它的引脚可以在下表中“FPGA引出I/O”部分选择即可,然后参照之间的51单片机进行连接。
此处附上接线实物图,需要注意的是,FPGA需要独立的接线供电,如充电宝等等。
2.3.2程序设计 逻辑上大体与51相同,此处附上代码部分以及引脚的设置图。
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 ( --时钟为50 MHz,为了产生100 Hz的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' ) THENduty\_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' ) THENcnt <= 0 ; ELSIF (sys\_clk' EVENT AND sys\_clk = '1' ) THEN IF (cnt = cnt\_meta) THENcnt <= 0 ; ELSE cnt <= cnt + 1 ; END IF; END IF; END PROCESS; PROCESS (sys\_clk, sys\_rst\_n) BEGIN IF (sys\_rst\_n = '0' ) THENpwm\_left <= '0' ; pwm\_right <= '0' ; ELSIF (sys\_clk' EVENT AND sys\_clk = '1' ) THEN IF (cnt >= (cnt\_meta / 100 )\* duty\_left) THENpwm\_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占空比与转速。具体在调试之后所得到的合适参数已经在上面的代码中有所体现,在此不过多赘述。
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.
致谢
感谢老师们在本课程中的精心准备与付出。在数电和模电部分得到了曾正教授和袁刚教授的悉心教诲,在后续的项目部分得到了李敏教授和凌睿教授的认真指导,最终得以基本实现预定目标,特此鸣谢!