自动驾驶与运动控制平台(2)

操作系统

无论自动驾驶还是我们的运动控制平台的技术栈,都有很关键的一层,操作系统层。这一层下面接口硬件平台,上一层接驳软件算法单元,如下图:

我们的运动控制平台选择的是ROS(robot operation system) indigo, 百度的Apollo是在ROS indigo基础上做了定制。 有些自动驾驶初创公司公开信息中,看到也是基于ROS。除了百度的Apollo,日本的tierIV公司也开源了自己的整套自动驾驶算法Autoware, 也是基于ROS。

作为对比,我们也看到大的车商,更倾向于专业的商业解决方案,如宝马,是将操作系统和中间件的开发工作交给Intel。我们都知道Intel是一家专业的计算芯片解决方案提供商,但是大部分人不知道的是2009年Intel 收购了嵌入式操作系统解决方案提供商风河公司。做过嵌入系统开发的人,都会对这个曾经的霸主都有所了解,虽然现在它在慢慢被人淡忘,现在嵌入式设备是linux 和基于linux 的anroid的天下。风河公司在加入intel之后,一直没有闲着,只是一只隐藏在Intel背后。 此前Intel和三星推进的Tizen操作系统,是风河一直参与其中,期望在汽车市场展开第二春的Intel,它在软件上的王牌就是这个风河。 2014年,风河成为谷歌开放汽车联盟的一员,与谷歌推出的android for Automotive。风河在汽车操作系统上有天然的优势,很早就涉足汽车娱乐信息系统,显示屏和车联网业务,与车厂有长期稳定的合作关系,后续在此基础上,提供自动驾驶,高级辅助驾驶,汽车云服务,无缝连接,更值得车厂的信任。下图是2017年1月风河推出的面向汽车的Helix Chassis产品,依仗的就是Vxworks:

综上所述,我们可以看到汽车操作系统,基本是分为两个阵营,传统车商,他们的路线是商业产品,一直信赖,平滑过渡的产品。另一个阵营是行业闯入者,这个阵营如google的 Waymo,Tesla会有实力和及早布局自己的操作系统解决方案,其他的大部分会选择ubuntu+ROS 深度定制的方案,加快自己的开发效率。

下面我们带着以下几个问题去探讨:
1.  操作系统主要是做什么工作?
2.  为什么自动驾驶需要操作系统,为什么用ROS?
3.  ROS 应用在自动驾驶有什么缺陷?主要的改进。

对于每个做计算机行业的人来说, 操作系统这个概念是即熟悉和陌生的感觉。早期学计算机,尤其是做软件的,三大浪漫:操作系统,编译系统,图形学。一个牛人其中之一的标准,我做过一个操作系统内核,我能看Linux 内核代码并做贡献。 除非需要做相关工作,软件人员一般不会在上面下功夫, 一个是因为它的确难,另外一个最重要的原因是它像是水和空气一样,非常重要,但是大部分情况是免费的。 操作系统存在的价值在于,它可以有效的组织,调度机器的资源,提供给其他软件程序统一一致的接口服务或者命令行服务,屏蔽硬件细节,提供给软件人员一台友好的虚拟朋友,可以用我们熟悉的语言去沟通,去完成任务。我们拿一段程序去执行,其实不仅仅是我们的代码编译好的机器码在执行,而是在操作系统的协助下,一起执行,完成某项工作。 操作系统会将找到你要执行的程序(磁盘管理),将程序码导入内存(内存管理),分配进程,分cpu时间片去调度。你的程序若访问其他硬件资源,比如显示器,操作系统给你提供接口,它帮忙把的请求连接到显示系统进程去,将请求翻译成显示屏上的像素值,达成显示目标。进程间对相同资源的访问,操作系统会透明的帮你安排好。我们可以去想象一下,没有操作系统,软件开发者大部分会成为废人,就算是一个高手,你要关注太多的细节,才能完成一个简单的任务。大部分操作系统都会有存储管理,内存管理,进程管理等一般化的主要工作,对于不同的需求, 也会衍生不同的有针对性的操作系统。我们的PC工作站,对人机交互体验,对进程调用切换会更重要一些,对于大部分嵌入式设备,cpu资源的占用敏感,实时性则是考虑重点,而不需要考虑人机交互。开源Linux 给操作系统领域带来的震撼,改变了这个领域的发展格局,在linux内核的基础上,各个领域的计算机应用可以进行高效的量体裁衣的定制。以android为例,有很多人可能会以为它是一个全新的操作系统,事实上它是建筑在linux内核基础上,它的应用有自己的特点,它要无痛在各种硬件平台架构上无差异的执行,无论是Arm, powerPC,还是 x86。移动设备一般不会使用PC上的存储设备,flash,SD卡高效存取是它要着重考虑的。移动设备对能耗非常敏感,对人机交互要求很高。这一系列催生了我们所见到的android这个样子,也能很好理解为什么google要搞个Davlik虚拟机,java是android开发推荐的方式(虚拟机屏蔽了硬件的差异,新的虚拟机比原生的jdk虚拟机转换效率要高)。

谈到汽车,一个汽车驾驶系统跑的软件,它要运行感知,控制,决策,定位等一系列高计算消耗,逻辑十分复杂,对安全可靠性要求特别强的程序。简单的单片机肯定是不可能的,它需要建立在一个成熟的几乎五脏俱全的通用操作系统基础上,同时要满足实时性,分布式,可靠性,安全性,通用性等硬性要求。从头搞一个操作系统是一个非常不明智的做法,没有风河vxworks家底的玩家,首先第一选择是选linux,然后在linux 基础上使用中间件的形式去扩展。 汽车行业的人可能会第一时间站出来,表示不同意见,因为搞汽车电子的最熟悉的嵌入式系统是类unix的QNX, 以往的汽车电子行业的嵌入式开发集中在汽车娱乐系统控制, QNX 体积小, 速度快,非常稳定和可靠为它赢得了汽车电子的近百分之七十五的份额。 但是简单几个问题就能让人理解这个选择:要做感知,目前公认解决方案是使用深度学习网络进行识别,有现成的深度学习框架运行在QNX上吗,它能驱动GPU加速嘛?这个技术方向选择,更要考虑开发的难度,后续扩展性和解决方案的开放性。光Linux对于自动驾驶及我们的运动控制平台,可以说够,也可以说不够。 因为这种机器人自主运动(自动驾驶我们可以这样抽象),它们都有一个很大的共性,各种传感,驱动已经模块是各自独立运作,决策,感知等算法是完全独立的模块,各自工作,同时要互相交流,使用一种规格一致,统一的交流语言。每个模块需要别的模块的配合,也就是我们常说的分布式协作系统。 如果把每个模块放入一个个独立的进程中,进程间通信将是一个十分重要的考虑要素。我们所知道的linux操作系统给我们提供的一系列进程间通讯手段: 信号量,队列,管道,共享内存,套接字,可以去搞,这需要大量的技术编码工作,而我们的注意力是算法,而不是通信。ROS就是解决这个问题的一个存在,它完全封装了模块之间的通信细节,提供了优雅的方式进行各种类型的交互, 一对一,多对一,多对多,有返回,无返回,同步,异步。像这种通讯框架,玩嵌入式的,分布式消息的同学可能都会熟悉,应该有很多其他的现成的东西可以用。 ROS 巨大的价值不仅如此,因为它出身高贵,前身是斯坦福人工智能实验室的机器人项目的STAIR,后来由Willow garage 组织维护,它是免费开源框架,软件架构清晰一流,提供多语言接口支持,提供了广泛的库文件实现以机动性、操作控制、感知为主的机器人功能,提供了大量的工具组合用以配置、启动、自检、调试、可视化、登录、测试、终止分布式计算系统。 ROS 为 常用 的 机器人 和 传感器 提供 了 硬件 驱动 接口。 从 软件 架构 角度 讲, 它是 一种 基于 消息 传递 通信 的、 分布式 多 进程 框架。 ROS 很早 就被 机器人 行业 使用, 很多 知名 的 机器人 开源 库, 例如 基于 quaternion 的 坐标 转换、 3D 点 云 处理 驱动、 规划 方面 的 MoveIt、 OpenRAVE 规划 库、 控制 方面 的 OROCOS 实时 运动 控制 库、 视觉 图像 处理 方面 的 OpenCV 和 PCL 开源 库、 定位 算法 SLAM 等 都是开源 贡献者 基于 ROS 开发 的。 这些良好的特性吸引了成千上万的机器人爱好者加入贡献,提供了机器人相关的各方各面算法包,各大硬件传感器厂商,会缺省提供ROS的驱动Wrapper。ROS的支持与发展依托着一个强大的社区。ros.org尤其关注兼容性和支持文档,提供了一套“一站式”的方案使得用户得以搜索并学习来自全球开发者数以千计的ROS程序包。这个生态是无价的,正因为这样,ROS基本是科研单位和机器人相关行业的首选。我们谈机器人操作系统, 说是ROS,其实更准确的说法是 Ubuntu+ROS。 如今是技术开放的时代,在做技术框架选择,不能去一味硬着头皮去重复造轮子,在选择上,技术先进性不是起绝对因素, 要看技术的生态环境,参与一个强大,开放的,可扩展的技术生态中,从中索取,贡献。 选择Linux, 是因为生态,选择ROS,更是因为生态。

ROS 在用于我们的运动控制平台,完全够用。但是用于自动驾驶工程实践,其实是有很多问题的。首先我们看一下它的框架示意图:

见上图,我们可以看到各个节点之所以可以互相认识,互相通信,事实是因为它们在启动前,把自己的信息告知一个统一的ROS Master,ROS Master 是一个名字服务器的存在,这样就会造成一个问题, 这样的架构不是一个纯粹的分布式架构,有单点失败问题,这个单点专指 ROS Master, 其他应用节点的损失是互相不影响的。这个问题对于自动驾驶这种要求高可靠性,甚至会为此设计冗余备份机制是完全不能接受的。 ROS 节点与节点之间的通信是socket,即使一对多的情况, 也是分解成 N对socket, 如果是多对多,读者可以想象。自动驾驶有很多传感器,对于带宽资源是十分敏感的,见下图:


以照相机传感器为例子,因为自动驾驶要用在高速行驶的情况下,采样率要高,至少每秒30帧, 以1080P的像素这辆,大概 180M/S。它传感数据是不只一个节点感兴趣的,见下图:

这个带宽的占用是恐怖的, 这只是一个摄像头,一般汽车配置多个摄像头, 还有64线雷达,那数据量也是十分恐怖的,当这种订阅者众多的时候,在ROS当前机制下带宽资源是消耗巨大的。 ROS 的传递的消息不支持向前兼容,也就是说在后面应用中,在已经定义的消息类型中,增加一个字段,这样新节点和老节点之间就这个消息进行沟通会发生错误的,准确的讲是md5校验失败。接口兼容性问题会对历史数据的使用造成很大的影响,尤其是自动驾驶领域,海量的历史数据是宝库,不能用了,或者做大量的处理来用都是不可接受的。 另外一个问题就是安全问题,如果一个ROS node 被挟持,黑客可以通过这个node 将资源耗尽,进而将这个系统搞垮。ROS node和node之间的消息被截获或者伪造,那么自动驾驶汽车可能会被黑客控制。这四个主要问题,原生的 ROS 1.0 都是无法解决的,ROS 2.0 虽然解决了部分,但是ROS 2.0 还在测试阶段, 自动驾驶玩家是没有时间和耐心去等待ROS 2.0成熟的,一般的思路是在ROS 1.0上做深度定制,以下详细描述定制的思路。

单点失败问题,一般是有两个思路。 百度Apollo 采用的是一种叫RTPS 的服务发现协议,通过节点之间的自动发现,完成纯粹意义上的p2p分布式拓扑结构,见下图描述:

ROS 2.0 其实也是有相同的思路去解决这个问题,它采用工业级别的DDS 中间件,节点直接可以自动发现。 解决这个问题的另外一个思路是ROS master 这个关键节点采取备份机制,如果ROS Master 宕机了,备份节点会顶上,可以采用开源的分布式协调框架zookeeper 去完成这个事情,见下图:

对于进程通讯使用socket 造成带宽的拥塞和cpu 的负担,方案很简单,进程通信采用共享内存机制,还是拿摄像机为例子,见下:

使用共享内存的好处,相比于套接字,越是 多对多,对带宽利用的优化越明显。 ROS 2.0 采用的DDS 中间件方案,已经考虑了进程间通信采用共享内存。

对于接口兼容问题, 百度Apollo 框架采用的方案是使用谷歌开源的protobuf(中间消息结构,类比XML,JSON,包括消息传递,序列化和反序列化机制)封装成ROS msg,来代替原生的ROS msg, protobuf 提供了良好的消息向前兼容性。这样修改不破坏原生ros msg机制及仍然使用这个机制通信的其他ros 节点,是一个比较干净的侵入修改方案。

安全方面的问题,可以采用LXC(linux container) 这种轻量级虚拟化技术,把每个ROS Node 放入沙盒,限制每个ROS node 权限。节点与节点的通信消息可以进行加密解密处理,防止中间人攻击。

以上,我们总结了为什么自动驾驶的基础解决方案和我们的运动控制平台都采用ubuntu+ROS 作为机器人操作系统的背景和原因探讨,说明了目前原生 ROS 1.0 对于自动驾驶使用场景的不足及参考的修改方案。 希望通过本文的描述,读者会对机器人,自动驾驶生态的软件操作系统层面有一个大概的了解。

推荐阅读更多精彩内容