自动驾驶入门练习指南

10年前还是学校机房学生管理员的时候,带着大家把智能车竞赛的实验室从0搭起来了,搭完电路写完基础算法就跑去当交换生了,也算是陪伴了童鞋们一个暑假,参加竞赛还是交给后生力量吧;而同时火起来的新一代人工智能也把自动驾驶推向接近实用。那么如何掌握自动驾驶的入门知识呢?市面上给出的框架都很大,比如练习控制算法,比如机器学习;但是这些要么笼统模糊,要么都是人工智能大后期的内容了; 在这里我们还是希望能画出一个平滑的学习曲线,抛砖引玉,给出一些在这个领域入门的成长思路和经验。

自动驾驶的入门内容大纲

思考一下自动驾驶需要学习的内容:

  • 首先自动驾驶的目标应该是驾驶汽车,但是汽车的复杂程度还是比较高的;而且自动驾驶是关乎生命的项目,人坐在里面,还是需要很多安全考量的。为了完成初学入门,我们可以降低一下要求,比如把目标设为自动驾驶四驱车。四驱车大家可能有些人小时候玩过,两节电池一个马达带动齿轮转动就能自己跑了,其实那不就已经是一种自动驾驶了么?是呀,只是它之单纯向前行驶并且开始和结束需要手动去打开开关和强制脱离跑道。也就是说我们要动手组装一下四驱车,并且能够将它改装成可控的四驱车,这是硬件部分。
  • 第二就是软件部分,如何去控制车的行动。这里当然是要动手去查资料或者打草稿去建立一个有效的四驱车运动的物理模型,然后根据这个模型再设计相应的控制算法。假设我们只有高中毕业的知识,我觉那就够了,高等数学里大部分都是用新的符号将一些现象极度压缩成精炼的表示,其实是一种数据压缩;当放到计算机里,要进行数值分析的时候,还是得拆解成高中甚初中至小学的算式给计算机进行处理;比如以前有幸参与过高铁铁路设计辅助软件的编写,和铁路部门的工程师沟通交流,他们就是建立模型,然后将模型简化,一堆堆泰勒展开还是很酸爽的。

我们下面就是要动手从硬件和软件两部分完成这样的工程。

硬件:改装四驱车

四驱车有一个马达,接电后,电机转动带动齿轮,车轮在地面上向前带动整体向前移动。
在这里插入图片描述
有了四驱车这个模型,我们就从它作为切入点,看看改装需要什么。

  • 为了能控制四驱车的速度,我们首先要提到一个叫PWM的东西——脉冲宽度调制。四驱车开关一开连上电路,马达在电压电流驱动下100%的时间都在转动,基本就是最大速度往前冲。为了能控制速度,我们需要让它能在(0, max)范围内甚至(-max, max)调节。通俗易懂得说,也就是在一个窗口时间比如在一秒钟内马达本来100%接在电路上,现在我们控制它90%连着电路10%断开,这样平稳后车速就可以保持在0.9max。另一个角度来说PWM,就相当于你写了一个死循环占用一个CPU100%的使用,你在死循环里加了sleep让它放空一会,CPU的使用率就会下降是一个道理。所以这里是需要改连接马达的电路。这里我们要注意的就是(-max, max),为何可以有-max?因为这样我们可以用这样的设计去控制四驱车刹车了。
  • 四驱车是只能向前跑的,那么如果我们想要转弯怎么办呢?这个实际上要进行一些机械改变,而且如果想控制转大弯还是转小弯,就需要诸如步进电机的东西。这里就是对前轮轴进行大改了,为了简化我们其实可以把四驱车的前后传动轴去掉变成后驱车,然后前轮轴单独制作连上步进电机。
    在这里插入图片描述
  • 当然为了控制步进电机的状态,我们需要设计一个控制电路;当然我们可以将这个电路也并入控制马达的电路里,这样只要一个主控芯片C51也好ARM也罢。
  • 为了上手开始练习,一开始还是别搞什么人工智能了,用简单的车道进行试验。在实验室或者家里就能做的就是硬纸板上面设计上车道。车道最好像托马斯小火车一样闭合起来;最初的练习还是建议就是一条红色线目标就是让小车能按照红色线路跑,然后再改成蓝线,然后再逐渐增加难度比如之后某个阶段直接到空旷的地段选自行车道跑。
    请添加图片描述
  • 最后就是如何收集路况信息了。这个当然是靠传感器啦。先搞点便宜的摄像头比如只能显示灰度分辨率较低刚开始就够用了。这个摄像头呢肯定是要用一个电路连入主控芯片的。

最后我们得到了一个诸如下图的自动驾驶小车模型。控制电路我就说一些注意事项好了,网上应该还是不少可以抄作业的,实在不行找万能的淘宝买现成的也行…

  • 散热始终是一个需要考虑的问题。即便是一个小车模型,运行起来电路可以烫得惊人。想要减少发热,这个是个硬骨头只能慢慢实践慢慢啃,去和焦耳好好聊聊吧,I2R;最直接的方法是散热片,更近一步的傻瓜方法是复制电路板比如复制3个一样的电路板,然后接到马达上,3个电路板层叠架起来隔开,靠调度算法(比如roundrobin)保证一个板在运行另外两个在散热…
  • 防撞保护设施也最好有,不然失控的小车可是能冲出跑道装在墙上…
  • 两个步进电机最好还是接同一个电路保证同步转向;当然玩熟了肯定是随便怎么设计,分开接滑雪式刹车都可以…
  • 摄像头一开始就直接和主控芯片对话比较简单,中断加IO数据就好了;后期可以考虑加入硬件buffer…
  • 为了方便Debug,还可以额外增加一个可插拔的蓝牙模块,将行车数据随时发送到远端进行分析。
    在这里插入图片描述

软件:数学模型

我们知道迭代的方法就是先从0到1,再慢慢去优化这个已有的1。软件开发写代码如此,建模也如此。所以太复杂的模型我们暂时摒弃,先用高中知识去解决一些问题。我们假设已经可以随心所欲控制小车的速度了,那么在这个状况下直线行驶应该不用废话,我们只要建立一个简单的转弯的数学模型就好了。这里我们只给出分析的例子,我们只采用车子单边前后轮进行转弯分析。如果车身长L,车速为v,一瞬间后前轮打方向转了θ的角度,那么在经过Δt以后,很容易用勾股定理算出之后的状态就是深灰色的车身长L'大于L;可以车身应该算是刚体不能被拉伸,换句话说转弯的时候前轮的速度最终在稳定时期会降速;这样其实我们将后轮速度从v假设为定值v0,还是用刚才的勾股定律就能算出稳定后前轮车速v。至于如何消除最后v里有的Δt,这个还是有点超过高中知识了,但是可能也可以勉强计算,需要算一个极限让Δt -> 0 。当然四个轮子都考虑还会更复杂。其实有了这个模型我们就可以用计算机写一个模拟器了,如果对硬件不感兴趣,可以专心研究软件…记得清华原来有过这样的模拟软件可以下载,年代有点久远,已经不知道url了,有兴趣可以自己搜索引擎搜搜看…
在这里插入图片描述

软件:控制算法

在算法上我们需要提的就是PID框架。控制算法书籍里基本都会说这个,PID其实很好理解,P就是当前状态,I就是积分状态总结整合历史数据(比如算个历史平均速度),D就是微分状态靠数据进行提前预测展望(比如算个加速度)。我们假设有一个跑道,跑道只有一条红色中间线,车子的摄像头是灰度值的,那么摄像头得到的数据很可能画成下面的图像:在这里插入图片描述
这是一条直线由近到远,当然还会因为环境光线问题产生其他噪声。我们的第一步就是要能够想办法处理单张这样的图片。处理图片,大部分初学者被填塞的条件反射是OpenCV,但是要知道如果只是一个很简单的片上系统,硬件上支持OpenCV是不可能的,这要逼着人从原理入手去实现,而不是简单调用调用OpenCV API看看别人的例子就好…

首先我们假设了摄像头得到的是灰度图像,这就把灰度化免去了。灰度化呢,就是如果是彩色图像,一般至少会有RGB种颜色,每个颜色通道一个[0, 255]的整数,灰度化就是把它们变成就套[0, 255],比如三种颜色的RGB每3个数值加权平均就是一种灰度化了(比如第一个点 RGB=(1,2,3) --> Grey=(2);第二个点 RGB=(4,5,6) --> Grey=(5),…)。接着我们就要设置一个数字叫阈值,我们把小于这个数字的灰度值都变成0,这是一种简单的简单噪声的办法;这样可以去除一些除了图中路线以外的其他噪声。当然还有更多方法比如傅立叶变换来构造滤波器等等,可以慢慢摸索,最终结果就是尽量让上图只剩中间的路线。当然值得一提的是,灰度化其实就是消减数据的办法,如果是彩色的图像,本来有等价的3组灰度数据RGB现在就合并成一组真的灰度数据了,再有阈值甚至可以把图像变成0/1数据,这样后面处理起来就更简单了。

有了清晰的路线图像,我们要开始思考如何控制车子运行了。如果这个路线一直就是直线那就完美了,我们啥都不用做,直接让它跑就可以了。但是要知道即使是直线,如果我们的车子在机械上不完美比如轮子的轴有一点歪,那么行驶时间长了还是会偏离直线轨道的;所以我们要想办法修正车子的运行。是了,我们已经进入了自动驾驶的一个核心部分。在这里初学者也容易被各种奇怪的东西带偏,比如上来就Mask-RCNN用彩色图像识别出周围的环境对象,后面就开始抓瞎了。首先我们说Tensorflow抑或Pytorch在我们现在这篇文章里的片上系统是运行不了的,其次是作为刚开始别一下整得太高级,要训练自动驾驶的思路还是从low-level做起。

上面我们画出来的图在机器里在内存里类似于这样(这里1代表[0, 255]的数值,都用1表示方便讨论):

- 1234567890123456789012
1 0000000000110000000000
2 0000000001111000000000
3 0000000001111000000000
4 0000000011111000000000
5 0000000011111100000000
6 0000000011111110000000
7 0000000111111111000000
8 0000001111111111100000

那么如何判断小车是不是沿着路线行驶的呢?我们用一个最简单的方法:在案例里,一行总共22个点,就是中间点在位置11;现在我们取第八行的图像数据,然后计算1开始的位置是7和结束的位置16,那么7和16的中间就是11.5;那么我们可以判断,这辆车目前基本还是沿着路线行驶的。对,你可能发现这种判断太简单;那就是大家自己摸索的事了。比如取第一行和第八行的数据计算中间点,然后连成一条直线看看偏差是多少,这是不是更精确一丢丢的判断方法了呢?

有了判断行车偏差的方法,下面就是要去处理各种情况了。这里我们以偏离中间点为例,介绍一个非常简单的控制方法。我们上面计算了当前车子探测的路线中心是x(比如11.5),然后摄像头视觉范围内中间点位置应该是x0(比如11),我们用|x0 - x|就可以简单得到小车偏移中间的量。那么有了这个值我们可以做什么?对,当有偏移量的时候,我们可以改变前轮方向控制车子尽量往中间靠。比如我们看x0 - x如果是大于0,那么车子偏左我们可以让前轮稍微右转;小于0当然是稍微左转。那么转多少呢?这里确实是个很坑的地方,在刚开始的时候,我曾经给参加竞赛的童鞋们一个init的思路就是一个常量列表,|x0 - x|为0 1 2 3 4 5 6 7 8 9 10 11,那就先定12个常量,0的时候车子沿着路线行驶不转弯,值是11的时候车子大概率遇到了一个转弯快冲出跑道了我们就转大弯给个44度;然后随着值的变小,转弯的度数也逐渐变小。这样一个最初的控制方案就有了。那时候写过了一个模拟器,在实现这个方案之前我们其实就能预测到在短时间内,这个方案还是可以的;但是一旦时间长了,尤其是过了弯道,误差就开始变大,那些常量会对车子运动产生很大的抖动,最终导致车子冲出跑道:
在这里插入图片描述
这是因为我们刚才的查常量表控制转弯的方法存在缺陷,我们控制的只是产生偏差后车子单个点的运行方向沿着路线;这里就要再次提到PID了;我们在这个例子里只是使用了PID的P来控制车子,为了让小车能平稳抓住路线,还需要更多数据(比如上一时刻小车的位置)去辅助控制。甚至在车子偏离路线的时候还可以再加一个控制量就是车速,偏移多的时候让车速慢下来,也是一种方法。总之迭代起来,一点一点加入各种各样的元素。

练习一段时间后,就可以把小车用RaspberryPi改装,这样就可以使用诸如Tensorflow的高级框架了。知道了路线控制,在彩色图像里,当然就是去提取道路路线,还要根据阻挡物信号灯控制车速并规划行车路径,比如三车道当前行驶在中间车道前方有车辆阻挡,可以规划减速或者换到另一个无阻挡的车道上。当然这些最好还是用用模型,真实路况实战还是去相应的自动驾驶公司吧。一切还是要考虑安全的…一步一个脚印去完成想法吧!

也欢迎大家微信交流讨论
在这里插入图片描述


版权声明:本文为prog_6103原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>