先看看无人驾驶基本的硬件构造及其成本


图片出处:wired.com/2015/04/cost-

看完图,就会发现一个十分尴尬的问题——除了超声波雷达以外,剩下的设备都买不起。

所以个人做无人驾驶研究,在没有大资金支持的情况下,就不要考虑基于实车做研究了。

断了从硬件方面着手做研究的念头,我们直接看看软件方面。

软件方面可以做的工作就很多了,掌握其中某一项或多项技能,对你在该领域的发展都大有裨益。

操作系统安装

必学指数:★★★★★

易学指数:★★★★★

既然是做软件,首先得有个操作系统。常见的操作系统Windows/Linux/Mac…(打…的操作系统我也没用过),考虑到社区支持、开发效率,推荐使用 Linux 作为无人驾驶研究的操作系统。

大部分做无人驾驶的团队都用的 Linux,跟着大趋势走,可以省很多事。

Linux 又分为很多版本,最常用且普及率很高的当属 Ubuntu 系列。虽然 Ubuntu 已更新至 17.04,但从稳定性上,推荐安装 14.04 版本。

推荐用一块单独的SSD安装Linux,或者使用虚拟机安装,最不推荐装双系统(不太稳定)

奉上 Linux Ubuntu 14.04 安装包 + 虚拟机安装方法

Linux基本指令

必学指数:★★★★★

易学指数:★★★★★

作为Linux的核心——命令行操作不仅对开发大有帮助,而且是装X利器。

另一个好处是使用指令 apt-get install,可以快捷地完成很多软件的安装,不用像Windows那样,在网上四处寻觅适配的安装包。

Linux的指令很多,而且比较杂,使用起来需要多学,多用。

有道云笔记分享:有道云笔记-Linux基本指令介绍

开发环境安装

必学指数:★★★★

易学指数:★★★★★

开发环境会涉及很多实际使用的库,不同的程序员处理相同的问题,可能使用不同的库。

下面通过安装我在工作和学习中经常使用到的库,抛砖引玉,将开发者”引进门”。

搭建环境所需安装包:

关注微信公众号:自动驾驶干货铺,回复“开发环境”,获取资源和安装方法。

详细的安装方法见笔记:有道云笔记-Linux开发环境搭建

开发环境介绍

必学指数:★★★★

易学指数:★★★

集成开发环境IDE

前面安装了一款开源的IDE qt,目前 qt 在 Linux 中的地位,就和 Visual Studio 在 Windows 中的地位一样。除非是不使用 IDE 开发的高玩,大部分在 Linux 下做开发的团队还是会选择用 qt 开发的。

qt 的主要作用是做交互式的界面,比如在界面中显示当前传感器采集到的各种信息。界面交互会明显加快开发者调试程序和标定参数的过程。

Tips:

熟悉 qt 可以网上找教程,我更推荐系统地学习,比如买一本 Qt 的书。

买书或者去图书馆借书,注意看写书的日期,越新越好,太老的书,相应的版本也很旧。

OpenCV

OpenCV是一个非常强大的库,其中封装了大量的可应用于无人驾驶研究的函数,包括各种滤波器算法、特征点提取、矩阵运算、投影坐标转换、机器学习算法等。

当然最重要的是,它在计算机视觉领域的影响力,相机标定,目标检测、识别、跟踪的接口使用起来十分方便。使用OpenCV库完全可以做出这张图展现的效果。

图片出处:nvidia.com/en-us/gtc/se

Tips:

请至少购买版本为2.4以上的教程学习OpenCV,但目前市面上买得到的OpenCV中文教程都讲的太浅,甚至连经典的Kalman Filter都不介绍。我推荐直接学习英文版的 Learning OpenCV3。

奉上电子版,讲解很详细,每次打印一章阅读,循序渐进。

libQGLViewer

libQGLViewer是大名鼎鼎的 OpenGL 适配 qt 的一个库,编程接口及方法与 OpenGL 大同小异,我们经常在各大无人驾驶公司宣传画上看到的环境感知信息的显示,就完全可以用 QGL 做出来。

图片出处:open.163.com/movie/2015

Tips:

学习 libQGLViewer 不需要购买任何教材,官网及压缩包内的 example 就是最好的老师,按照官网的tutorial,把每个例子实现一遍,就基本入门了。

官网链接:libQGLViewer Home Page

Boost

Boost库是有着“C++准标准库”之称。这个库里面有大量的”轮子“,对于C++开发者来说,方便直接调用,避免重造”轮子”。

Tips:

Boost是基于标准C++开发,其构造用尽精巧手法,不要贸然费时研读,找一份和 Boost 库相关的(电子或纸质)书,把目录读一遍,大致知道里面有哪些功能即可,需要时就某一个点,花时间做研究。

QCustomplot

除了上面提到的libQGLViewer外,还可以通过平面图的形式显示车载传感器的信息。鉴于 qt 内部只提供了基本的直线、圆等绘图工具,使用起来并不是很方便,因此QCustomplot诞生了。简单地调用API,然后把想要显示的数据作为参数输入进去,就可以绘制出下面这些很棒的图形。而且可以很方便地拖动和缩放。

图片出处:QCustomplot Home Page

下面是我在实际开发过程中,使用 QCustomplot 显示的部分传感器信息。

Tips:

官网提供了该库的源码下载,你只需要在你的工程中导入 .cpp 和 .h 文件即可。跟着官网提供的 tutorials 学习,可以快速上手。对照着example中的例程写代码,可以快速把自己的数据变成可视化图像。

LCM(Lightweight Communications and Marshalling)

团队开发软件必然存在程序(多进程)的通信问题,多进程通信的方式很多,也各有优缺点,使用起来就见仁见智了。2014年12月MIT公布了他们在美国DARPA机器人挑战赛中使用到的信号传输机制LCM,出处:MIT releases LCM driver for MultiSense SL

阿里云-推广AD

LCM含多种语言如java,c++等专门针对实时系统在高带宽和低的延迟的情况下进行消息发送和数据封送处理。它提供了一个发布/订阅消息模型、自动封装/解封代码生成工具含多种编程语言版本。这个模式和 ROS 现在节点间的通信方式很类似。

Tips:

LCM两个进程间通信的demo官网上有源代码,按照官网上的tutorial就能快速建立属于你自己的LCM通信机制。

官方网站:LCM Projcect

Git & Github

Git是团队开发不可缺少的版本控制工具,大家在写论文时肯定每天一个版本,如果没有特别标注每个版本改了些什么时间久了就会忘记。写代码更是如此。

使用Git可以极大地提高多人开发的效率,而且版本管理规范,代码追溯起来十分方便。

Github在软件开发领域如雷贯耳,需要某些代码时,直接上去搜索即可。

Tips:

目前世面上介绍Git的书,让人看起来十分吃力,而且对细枝末节的东西介绍地太过深入,让人无法快速上手。

于是我要强烈推荐Git入门的教程:廖雪峰的Git教程,浅显易懂,而且还配合图文+视频,简直良心。

以上基本介绍完了开发所需要的东西,掌握好这些东西,就可以来我司面试了。

———————分割线———————

现在有了自动驾驶开发的工具,那么再掌握一些自动驾驶开发的流程就如虎添翼了。

下面开始介绍做自动驾驶开发过程需要了解的基础知识。

自动驾驶开发流程

必学指数:★★★★★

易学指数:★★★★

实现一个智能驾驶系统,会有几个层级:

感知层 → 融合层 → 规划层 → 控制层

更具体一点为:

传感器层 → 驱动层 → 信息融合层 → 决策规划层 → 底层控制层

各个层级之间都需要编写代码,去实现信息的转化。

最基本的层级有以下几类:采集及预处理、坐标转换、信息融合

采集

传感器跟我们的PC或者嵌入式模块通信时,会有不同的传输方式。

比如我们采集来自摄像机的图像信息,有的是通过千兆网卡实现的通信,也有的是直接通过视频线进行通信的。再比如某些毫米波雷达是通过CAN总线给下游发送信息的,因此我们必须编写解析CAN信息的代码。

不同的传输介质,需要使用不同的协议去解析这些信息,这就是上文提到的“驱动层”

通俗地讲就是把传感器采集到的信息全部拿到,并且编码成团队可以使用的数据。

预处理

传感器的信息拿到后会发现不是所有信息都是有用的。

传感器层将数据以一帧一帧、固定频率发送给下游,但下游是无法拿每一帧的数据去进行决策或者融合的。为什么?

因为传感器的状态不是100%有效的,如果仅根据某一帧的信号去判定前方是否有障碍物(有可能是传感器误检了),对下游决策来说是极不负责任的。因此上游需要对信息做预处理,以保证车辆前方的障碍物在时间维度上是一直存在的,而不是一闪而过。

这里就会使用到智能驾驶领域经常使用到的一个算法——卡尔曼滤波。

坐标转换

坐标转换在智能驾驶领域十分重要。

传感器是安装在不同地方的,比如毫米波(上图中紫色区域)是布置在车辆前方的;当车辆前方有一个障碍物,距离这个毫米波雷达有50米,那么我们就认为这个障碍物距离汽车有50米吗?

不是的!因为决策控制层做车辆运动规划时,是在车体坐标系下完成的(车体坐标系一般以后轴中心为O点),因此毫米波雷达检测到的50米,转换到自车坐标系下,还需要加上传感器到后轴的距离。最终所有传感器的信息,都是需要转移到自车坐标系下的,这样所有传感器信息才能统一,供规划决策使用。

同理,摄像机一般安装在挡风玻璃下面,拿到的数据也是基于摄像机坐标系的,给下游的数据,同样需要转换到自车坐标系下。

自车坐标系:拿出你的右手,以大拇指 → 食指 → 中指 的顺序开始念 X、Y、Z

然后把手握成如下形状:

把三个轴的交点(食指根部)放在汽车后轴中心,Z轴指向车顶,X轴指向车辆前进方向。

各个团队可能定义的坐标系方向不一致,只要开发团队内部统一即可。

信息融合

信息融合是指把相同属性的信息进行多合一操作。

比如摄像机检测到了车辆正前方有一个障碍物,毫米波也检测到车辆前方有一个障碍物,激光雷达也检测到前方有一个障碍物,而实际上前方只有一个障碍物,所以我们要做的是把多传感器下这辆车的信息进行一次融合,以此告诉下游,前面有一辆车,而不是三辆车。

当然,信息融合中还涉及时延的补偿,具体如下:

对于一些大容量数据,确实不能以很高的频率发送(比如10Hz,100ms才发送一次)。这样的数据对高速行驶中的汽车来说,肯定会有偏差。

这些偏差我们算一下:

传感器检测到前方有一个静止障碍物,我100ms之后收到了这个传感器的信息,告诉我这个障碍物离我有30m。如果自车这时正以60KM/h的速度行驶,则这100ms,自车行驶了60 / 3.6 * 0.1 = 1.67m。

所以实际上这个障碍与我的距离为31.67m。

所以面对通信中产生的时延问题,尤其是低频率的信息,一定要考虑时延产生的后果。

时延补偿的另外一个问题:程序处理时,不能保证任何时候都是按固定的频率发送的。

这取决于硬件系统当时的环境,可能温度高了,性能下降,处理速度变慢,10Hz 的发送频率变成了 8Hz。如果我们的程序还是按固定的100ms去计算时延导致的偏差,必定会出现计算错误的情况。

因此我们需要引入时间戳,即在我们发送的信息中加入当前的系统时间,通过两帧数据的时间差来判断接受到的信号到底延时了多久,这种方式比根据频率判断来得更准确。

决策规划

这一层次主要设计的是拿到融合数据后,如何正确做规划。

规划包含纵向控制和横向控制。

纵向控制即速度控制,表现为 什么时候加速,什么时候制动。

横向控制即行为控制,表现为 什么时候换道,什么时候超车等。

个人对这一块不是很了解,不敢妄作评论。