第十六届全国大学生智能汽车竞赛-创意组-百度赛道-西南交通大学参赛队开源代码及分析
大家好,很高兴与大家在智能车西部赛场上相见,我是西南交通大学参赛队-"交大人均替身使者"队的队员,主要负责程序的编写。虽然我们队在线上和线下都取得了不错的成绩,可惜因为规则问题没能顺利进入国赛,但我相信和大家在赛场的相见即是缘分,为了帮助大家能在国赛中取得更加优异的成绩,将我组的代码全部开源出来,以供大家学习参考。无论如何,祝大家能在智能车的赛场上收获多多,提升自我!
前言
决定参加智能车竞赛纯属偶然,只因本校有竞赛替代的规则,可以用国家A类竞赛来替代暑期实习,因此在室友的邀约下参与了对我来说最具诱惑力的创意组,说不定还能获得百度的面试机会,直接进入大厂呢,笑~ 毕竟创意组看起来更具挑战性,也可以锻炼我的代码能力。
在期末考试后摸了一段时间鱼,在机械部分和电路部分都准备妥当后便投入了代码的编写中,如果没记错的话恰好是东部赛出成绩的那两天。说实话,在看到东部赛最终成绩的时候就觉得没戏了,分数都很高,而我们的时间因为前期的硬摸鱼而显得非常不足,能否完赛都说不准。而且本组原本有两位专职程序员,但另一位在负责完线上赛后就跑去美团做实习了,只留下了EdgeBoard相关的代码,因此剩下的代码部分几乎都是我一人完成的,这也为我们后面被取消资格埋下了伏笔。
我们小组的方案在很久前就确定下来了,而在紧锣密鼓的做车和调车阶段,多亏了我们导师的帮助,解决了几个麻烦的部分,这才让我们得以完赛。具体而言,我大概花了4天编写完绝大部分的代码,接下来的3天主要对整车进行调试和代码修修补补,也就是大约一周的时间做完了这辆车。再加上最终我们线下赛的实际成绩,就我个人而言,应该是没有辜负队友对我的期望,尤其是拿到了线上赛第一的大佬~
总体方案
前言中提过,方案在很久前就已经确定下来了,在查看了比赛的具体规则后确定下全部使用传统算法的方案,同时针对规则中的一些疏忽简化部分过程,最终成型。毕竟针对比赛而言,规则无禁止即可为,更不用说这是创意组了,不是吗?部分介绍可以在我队友的博文中找到,我在这里只谈谈和我关系比较密切的部分。
百度赛道主要分为三个部分:
- 在保证不出界的情况下巡线
- 行驶到对应区域后执行对应动作
- 三座可能会更换旗帜城池的识别和举棋
而规则和东部赛的实际情况下告诉我们,在最终发车前将会有1分钟的时间进行发车准备,虽然不允许更换或者更改代码,但在先前的直播答疑中也提及过,可以采用换旗的方案,现场更换旗帜。经过我们的认真考虑,我们准备使用树莓派+GPIO按键的方式,通过屏幕显示的方法来在1分钟内更换旗帜的顺序,算下来一共需要按5次按钮,远比机械换旗划算得多,这样第三点就解决了。
巡线部分是三个内最难做的一个,倒不是说代码有多么难写,而是后期的调试非常麻烦。我们的车因为设计问题又大又重,放在赛道上非常大,几乎占据15/17个灰色赛道,这让它在弯道上转弯非常笨拙。也感谢组委会允许压黄线的规则,不然我们小组就彻彻底底成为重庆旅游团了。我又是第一次接触图像处理和道路巡线,尤其是双线巡线,完全没有相关经验,只能用直觉来编写代码。当时考虑的是,巡线有两种做法,一种是判断两侧黄线,取中点作为道路中线,并借此完成巡线; 一种是判断中心灰色道路部分,取灰色部分的中线作为道路中线。最终选择是双黄线方案,但这也为造成了后续一个问题,具体将会在后文中提及。至于灰色道路方案理论上也是可行的,但没有实际实现过,有兴趣的小组也可以试一试。
执行动作相比之下就显得简单许多了,由于道路上任务执行顺序和道具位置都是固定的,因此只需要记录下执行到哪里了,调整好车辆姿态后直接执行即可。但这里又多出几个问题:如何知道应该执行任务了?如何在执行任务时调整好车辆的姿态?如何打中靶心?具体实现留至后文吧。
巡线
设计
巡线部分几乎完全由车辆前方的一个广角摄像头实现,为了能在U型弯转弯时看到双侧黄线,必须使用角度足够大的广角摄像头,毕竟这个方案非常依赖视野,丢失视野会十分麻烦。流程是这样的:
摄像头传回图像数据-->压缩图像-->二值化处理-->算法计算出中心线-->压入队列-->巡线线程取出中心线数据-->计算出车辆偏移-->计算出电机速度-->车辆行驶
图像处理
由于赛道自身的设计和赛道四周无大型遮拦的情况,在使用广角摄像头情况下图像中的干扰会非常大,需要谨慎对待。一开始仍然是考虑的传统RGB二值化,但考虑到光线影响问题,最终采用了HSV颜色空间,让光线影响要小一些。要注意赛道上某些颜色虽然看着不像是黄色,但色调其实非常接近,需要通过饱和度来筛选。此外,抓取部分的黄色方块也很容易误判,图像处理这块做的非常小心。最终由于广角摄像头看的距离太远还裁掉了部分靠前的画面。
中心线处理
中心线算法非常简单:按行扫描-->找出左线-->找出右线-->取中值-->得到中心线。但实际上要考虑的地方非常多:
- 赛道是不会突变的,要考虑上一帧和这一帧的关系,行与行之间的关系,最大程度去掉干扰
- 如果在两个赛道中间出现了干扰该如何处理
- 如果图像中存在多条赛道该如何处理
赛道是不会突变的
保存Left, Right, Center几个变量,遵循以下规则:
- 上一帧和下一帧,靠近车辆的中心点应该大致差不多
- 上一行和下一行搜索到的Left和Right赛道坐标差距应该较小
总而言之避免搜索到错误的坐标
赛道中间干扰
赛道在画面中是较大的,就算存在干扰也应该较小。采取两个策略:
- 摄像头分辨率取1280x720,利用OpenCV转为80x45,消去较小的干扰,也能避免错误的突变值
- 在确定了一个坐标区间后,采取遇到色块+1,没遇到色块-2的方式,既避免了赛道中断,也可以很好的去掉干扰
多条赛道
画面中出现多条赛道是很可能的情况,解决方法也很简单:寻找距离上次中心点最近的两条赛道
车辆偏移计算
有了中心线后,显然还需要确认车辆行进方向和速度。流程是这样的:
针对有效的中心点进行线性回归-->计算得出的线性回归线的斜率/角度-->计算得出的线性回归线在x轴的投影作为车辆目前在赛道的中点
有了车辆现在距离中心线的距离和角度,就可以送给下一步计算电机速度了。
电机速度计算
电机速度其实就是麦克纳姆轮的转速,在上一步得出的距离和角度,配合上提前设置好的前进速度,纠偏速度,以及转向速度,即可得到电机转速,这里不再赘述,相信能看到这里的朋友应该都有经验。
不过,由于车辆和摄像头的限制,为了能更好的转向,我增加了一个基倍,角倍的设置,为的是在计算得出角度超过一定阈值后,降低前进速度,提高角速度,让车辆更加贴近弯道行驶。
大弯道处理
相信百度赛道中的多处弯道都给大家留下了比较深刻的印象,在我的方案内并没有做什么特殊的处理,凭借电机速度计算即可通过
十字路口处理
十字路口的处理花费了我相当长的时间,主要还是视野丢失带来的影响太大,按我的算法,车辆极其容易在丢失视野的时候丢失姿态,从而识别其他道路,甚至把一个弯道的一条线当作两条线。当初为了处理这个问题采用了多种方案,最终采取的是判断车辆到达十字路口后,降低车辆在十字路口的纠正,同时抬高视野,在恢复大半视野后再进行大幅度纠正。
巡线总结
总的而言,这个赛道的巡线虽然看着难度很大,但实则采用传统算法只需要特殊处理十字路口情况。从最终西部赛清一色红色车的情况来看,最终使用传统算法巡线的小组应该并不是很多,这一部分大家图一乐吧。
任务执行
任务执行部分主要的难点就在于如何调整车辆姿态,我们采取的是底部白块识别的方案,用了一块OpenMV,将摄像头部署在车辆中部,而车辆底部完全掏空,并加上灯带补光,用USB线连接到树莓派,采用串口通信,返回识别的白色块的中心点。
OpenMV靠谱吗
最终在西部赛调车的时候,发挥最不稳定的就是这块底部OpenMV了,倒不是程序写的有什么问题,而是实验室用的赛道时间长了已经很脏了,而西部赛的由于是新赛道因此反光极其严重,白色块周围全是反射的白色光晕,非常容易误识别。硬件的问题硬件处理,最终找了纸把灯带蒙住降低反射......
底部识别姿态调整
在这个赛道上,能精准对齐底部白色方块比什么都重要,甚至如果车辆能对的很齐且姿态较正,甚至打靶都无需辅助瞄准,盲打也可以是靶心。当然这点我们最终实现的是车辆前进后退的对其,因为我们发现在直道上车辆的姿态非常端正,而大部分任务区都在直道,最终决定(其实是时间不够了)只让车辆前后进行调整。而车辆在赛道上的左右对齐可以交给EdgeBoard处理,这块会放在后文中。
打靶
其实这块是我们比较放心的地方,因为我们又上了一块OpenMV识别红色,找到红色块的中心,将车辆上炮孔对准到红色块中心后打靶就行,没想到最终丢分是在这部分,而这部分先前几乎没出过错,笑~ 不过硬件的挑战性不就在于将不稳定的变成稳定的不是吗?最终我们第一天丢分,直到第二天比赛也没能复现出当时的情况(靶子被划了长长的一横)。总而言之,当这块调整完毕后基本上次次都是靶心,非常非常准~感谢队友稳定发挥的机械设计!
其他部分
其他任务无非就是举旗,平移,抓取和放球,除了放球由于球框没四个球塞一起大总是容易自己滚出来外,都没啥大问题,举旗的放到下面说吧。
城池任务
我们为了调试方便和城池任务,负责电路部分的队长整了个有着5个按钮,一个5向摇杆,一块屏幕的小板子,接上了树莓派的GPIO接口,我的一个任务就是负责编写这个的UI界面和相应的逻辑,倒也没啥好说的,和比赛相关的就是城池选择了,按5次就能确认好城池的顺序然后依次举旗就行了。
举旗需要注意的一点是,从亮灯开始计算,到第三次灯灭需要有5s时间,这个在比赛规则和附加规则中都没说,只在直播答疑的时候提过,甚至附加规则中说的是亮灭间隔明显即可,但我们组在第二天的比赛中,裁判进行了现场数秒,这是我们这个场地其他组都没有的"待遇",而我们的亮灯时间是7s,举旗的时间是8s。我想,这可能是因为对我们组要求高,精益求精吧!总而言之,这部分的时间尽量不要节省,避免和我们组一样被高标准要求。
EdgeBoard
在前面章节中并未提及EdgeBoard,其实是因为在我们的方案中它是作为下位机存在的。具体而言,EdgeBoard连接一块被固定在后车轮上的摄像头,通过OpenCV判断车辆距离边线的距离,并启动Flask进行可视化网页输出以及接口输出。EdgeBoard通过网线和树莓派连接,树莓派在需要的时候通过轮询的方式请求EdgeBoard返回距离边线的距离,借此调整车辆的姿态。
而为什么我们没有采用这块EdgeBoard跑模型?只因没能达到我们要求而已,相比参赛的各位因为这块EdgeBoard所做出的妥协应该不少,毕竟算力有限。
这同样也是我们队被判罚的具体问题点,争议点在于EdgeBoard是否必须使用,以及EdgeBoard上是否必须部署模型跑学习。毕竟在我们反复研读的规则文件包括补充规则文件中都对此没有相关说明,我们确实没有想到还有某个人微信公众号这一层,只能说这一次我们在第一层,而组委会已经在火星了。当然,论这些方面,我们确实是自叹不如,只能说资历太浅,还得多吃两年盐。
题外话和总结
其实这一部分就只是闲聊而已了,毕竟国赛已经与我们无关了。想说的话考虑到我们学校无法说出口,只能说懂得都懂吧,毕竟也是有相当一部分人了解我们小组遇到的问题,甚至回去问问自家学长就直到我们学校已经不是第一次因为这种原因被判罚了,这可能也是我校传统吧。毕竟这比赛的创意组到如今,完全的自制车已经非常少见了,正如上文所说,西部赛是清一色的红色车,我想东部赛也应该差不多吧。至于创意二字体现在了何处,我想能看到这里的人应该都对此有自家的看法想法,毕竟商赛就是商赛。换句话说,我们这辆自制车,硬件部分除了电路,用的都是实验室现成的东西,整辆车造价不超过2k,做完这次比赛还可以拆下给接下来的其他比赛发光发热,按库克话来说,可谓是非常环保了。至于我们小组的判罚原因,竟是违反了某个人微信公众号上每日没完没了发的水文中对比赛介绍的一条,而且还非常牵强。前后ICPC银川事件,在铁证如山的情况下仍然纠缠许久,最终的公告也只字未提原因,只谈及取消成绩,我想和我们情况下也差不多罢了,只是结局还是不太一样而已。只能说,智能车作为国家级A类竞赛,名副其实。孰是孰非,各位都有自己的判断,不再多言。
总而言之,国赛在即,在目前的情况下,我个人考虑的话,应该只有四种可能性:
- 大幅更改赛道:在如今疫情的大环境下,考虑到剩余的时间,那影响是极其巨大的,不用多说,就这剩下的半个多月,只能是自求多福。
- 大幅增加规则上的限制:增加一系列限制规则,完全取缔类如赛前换旗的这种行为,影响虽然有但不至于非常大,最终结果也是大家继续国赛拼速度
- 增加更多的变数,例如封车后随机调换任务顺序,甚至每个参赛队都需要抽签调换。如果真遇上了,那也只能硬改了
- 啥也不做:那也只能祝你们好运,经过初赛到国赛,这种情况下满分几乎每队都能做到,比拼的就是各位的稳定性,速度,以及运气了,要是比赛的时候黑了点,有个小失误那国一肯定是无缘了。
正如开头所说,智能车竞赛的初衷即是以车会友,突破自我。祝大家能在智能车的赛场上收获多多,提升自我!
代码开源地址
EdgeBoard及主控代码: https://github.com/Erope/BaiduSmartCar
OpenMV代码: 见队友CSDN
我相信规则或者某人的个人微信公众号应该没有写不允许开源代码吧?