每当谈到自动驾驶的软件开发,人们首先想到的,是深不可测的人工智能算法,是各种感知融合,是各类路径规划…但是,就算是再智能再高深的算法,如果没有底层操作系统的支持,一切都将是纸上谈兵。
而即便拥有了一套优秀的操作系统也还远远不够,我们还需要一条重要的“纽带”来承上启下,使上层应用与底层操作系统可以紧密的”连接“起来!
而这条重要的“纽带”,就是我在本文中将为大家详细介绍的一种全新的,或许能够支撑起自动驾驶未来整体软件架构的“主心骨” – iceoryx「冰羚」。
壹
中间件
在解释iceoryx「冰羚」之前,我们不妨先来简单的了解一个重要的概念-「中间件」(Middleware)。
「中间件」的主要任务,是负责各类应用软件模块之间的通信以及对系统资源的调度。
它的优点,是可以大大降低应用层软件的开发难度,使研发工程师可以完全把注意力集中到功能算法的开发上。而目前最为业内所熟知的「中间件」当属Classic AUTOSAR中的RTE(Runtime Environment)了。它不仅负责上层SWC(Sofware Component)之间的通讯,也同时负责对SWC进行调度以及对底层操作系统及通讯服务的调用。
总的来说,「中间件」是整个软件架构的核心组成部分。
如果你使用过Linux或QNX等操作系统,就一定会接触一种使用进程间通信的机制(IPC:inter-process communiction),来完成拥有不同虚拟地址空间(virtual address space)的系统应用(Application)之间的数据传输。
而本文的主角iceoryx「冰羚」就是由罗伯特·博世公司 (Robert Bosch GmbH) 自动驾驶部门的架构大牛Michael Pöhnl先生发明的
一种基于「零拷贝」(zero-copy)和「共享内存」(shared memory)技术来优化「进程间通信」(IPC)的「中间件」(Middleware)。
贰
IPC的核心问题
众所周知,在汽车,机器人和游戏等领域,各个软件系统的不同部分之间需要传输大量数据。
在过去的几十年中,由最初的发动机控制系统,发展到当下热门的辅助驾驶/自动驾驶等等,汽车电子技术有了革命性的发展。随之而来的,是电子控制单元(ECU)中不同执行线程(threads of execution)之间的数据传输单位从KB/s增加到了GB/s,而能够完整地“支撑”自动驾驶功能的数据传输速度甚至将会达到10 GB/s(图 1)。
图 1:ECU内部数据交换的演变 [1]
与机器人和物联网(IoT)等领域相似,汽车中使用的通用通信范例是发布/订阅。
其中最典型的一种支持IPC的「中间件」解决方案是在传递消息时通过「中间件」来回拷贝数据。由此而产生的后果是,系统将在「中间件」堆栈内部,产生多个数据副本,甚至在必要时对数据的有效负载(payload)进行序列化,这将在无形中极大的消耗系统的资源(图 2)。
图 2:典型IPC中间件解决方案的消息复制 [1]
换句话说,当传输速度达到GB/s级别时,在「中间件」堆栈中所创建的每个消息副本都会使系统在运行时间(runtime)和延迟(latency)方面付出巨大的代价(图 3)。而事实上我们本应将宝贵的系统运行时间用于进行功能计算(上层应用),而不是浪费在“来回移动内存中的字节”上。
图 3:运行时间和延迟随着越来越高的传输速度剧增
叁
真正的“零拷贝,共享内存”数据传输
其实,作为一种基于内存共享的IPC技术,iceoryx虽算不上是一项革命性的创新(自上世纪70年代起“共享内存技术”就已经存在并一直被使用),但是,Pöhnl先生和他的研发团队对这项技术进行了极大的改进,将其与发布/订阅架构(publish/subscribe architecture),服务发现机制(service discovery),现代C ++(modern C++)以及无锁算法(lock-free algorithms)相结合。通过添加避免复制的应用程序接口(API),实现了真正的零拷贝 – 即实现了数据从“发布者”到“订阅者”的端到端传输方法,其过程中无需创建任何数据副本。
它的工作原理是这样的:
1. 通过iceoryx API,“发布者”将信息直接写入到事先由「中间件」预订好的内存块(memory chunk)中。
2. 当数据传递完成后,“订阅者”将收到指向这些内存块的参照指针(reference),并同时可以管理自己可配置容量的信息队列。
3. 每个“订阅者”拥有唯一的且属于自己的视角,可以查看哪些数据仍在处理状态中,以及哪些数据可以被丢弃。
4. 「中间件」iceoryx在“幕后”则对内存块进行引用计数(reference counting),当其发现被引用的次数变为零时就会释放内存块(图4)。
图 4:真正的零拷贝通信 [1]
打个比方来说:在下图5中,左边的“工厂”代表发布者发布数据,右边的“大脑”和“眼睛”则代表订阅者要读取数据,中间的红色区域代表共享内存,而其中的内存池(memory pool)是一个或者多个内存块的集合,可以被想象成一节节的车厢。
图 5:像货车车厢一样的内存池 [2]
第一步,“工厂”向「中间件」发送请求,要求占用一定数量的“车厢”(Allocate)。第二步,“工厂”向“车厢”里装货,也就是进行数据写入的操作(Write)。第三步,“工厂”特以写入数据的车厢进行“编号”(如图中的0xBEEF,相当于内存指针),并将”车厢编号”发送给订阅者(Deliver)。最后,订阅者可以直接从编号为“0xBEEF”的“车厢”中提货(按照指针指向的地址读取数据)。
整个过程,“货物”只被装了一次车,直到被“提货”前都再没有离开过车厢
= 数据仅仅只被”写入”了内存一次,但并没有被复制,故而实现了真正的“零拷贝”!
接下来我们在列举一个例子:如下图6中所示,假设这个时候又有两条新的数据(0xFACE和0xCAFE)被写入,而之前在车厢0xBEEF里面的货物已经被提走(数据已经被读取)。
图 6:共享内存的自动回收 [2]
这个时候,之前提到的引用计数机制(reference counting)就可以派上用场了:当它意识到这个车厢0xBEEF内的货物已经被提空的时候(没有再次发生读取操作),就可以判定这个“车厢”可以被再次回收利用了!(内存块再次被释放,重新回到可以被预订的状态)。
这时,如果我们重新绘制图3,就会得到下面图7这样的一条水平线。
图 7:使用iceoryx实现了恒定时间内几乎无限的数据传输 [2]
它表明:在使用“零拷贝,共享内存”的「中间件」iceoryx之后,系统的运行时间和延迟已经跟传输的数据量没有关系了。换句话说,系统可以在一定时间内实现几乎无限的数据传输。
肆 技术细节
中间件iceoryx有一个非常重要特性:由于“发布者”跟“订阅者”是独立运行的,因此“发布者”可以在“订阅者”仍在读取数据的同时再次进行数据的写入操作而不受影响。如果先前的内存块仍然被占用,则只需为“发布者”重新分配一个新的内存块即可。
如果“订阅者”以轮询模式(polling)运行,并且内存块在排队等待被”订阅者“再次检测时,系统则可以启用无锁队列(lock-free queue),在被称为“安全溢出(safely overflowing)”的过程中回收较旧的内存块。
无锁队列能够使“订阅者”更高效的使用内存,并最大限度的在队列里储存最新的消息数据,无论连续轮询之间的时间间隔有多长。这对高频的“发布者”和仅对最新的数据信息感兴趣的“订阅者”是非常有帮助的。
由于在整个数据的传输过程中,「中间件」iceoryx只是在来回的传递“指针”,因此它在数据传输的过程中实际并不需要实际传输数据。换句话说,无论数据信息的大小如何,数据在传输过程中所消耗的时间都是恒定的。
除此之外,iceoryx API在支持轮询访问(polling)的同时,也支持事件驱动回调(event-driven callback)。这个特性使其可以被广泛适用于大量的不同应用场景,包括实时系统的应用程序。
同时,由于数据消息的有效负载未被序列化,所以数据的“发布者”和“订阅者”必须具有相同的内存布局(memory layout),对于特定处理器上的IPC,我们可以通过使用相同的编译器设置来确保这一点。
而共享内存也可以分为具有不同访问权限和可配置内存池的段。这里我们需要了解使用共享内存的两个限制:一个是它只支持固定长度的消息,另一个是不能使用virtual members以防止member function被派生类重新定义。
除此之外,被传输的数据消息中不能包含任何指向进程中内部虚拟内存空间的“指针”,此限制也适用于基于堆的数据结构(heap-based data structures)。即使无法满足上述条件,「中间件」iceoryx仍然可以与能够处理消息序列化与反序列化的上层软件进行合作,实现零拷贝的底层传输。
「中间件」iceoryx依赖可移植操作系统接口 (POSIX API)。目前,它支持Linux和QNX作为底层操作系统而运行。由于API间往往存在细微的差异,因此当我们需要将iceoryx移植到另一个基于POSIX的操作系统时,可能需要进行较小的配置改动。
iceoryx通过使用服务发现机制实现了动态调度(dynamic scheduling):它可以在实时状态下建立应用之间的连接,这个特性与基于SOA架构(service-oriented architecture)的adaptive AUTOSAR可谓完美契合。
同样,在大家都关心的功能安全领域,iceoryx的目标是达到ASIL-D安全等级,保证软件运行的确定性则是实现这个目标的钥匙。
为此我们需要遵守以下几点编码准则:
-
禁止使用堆,只使用静态的内存
-
只使用部分STL(C++ standard template library)
-
禁止未定义的行为
-
禁止使用exception
目前支持「中间件」iceoryx的平台有:
-
Linux
-
QNX
-
macOS(未完全测试)
-
Windows 10(正在开发阶段)
由于iceoryx是一种与数据无关的基于共享内存的传输机制,因此它仅仅提供了相当底层的API。因此,Pöhnl先生及其研发团队不建议开发者直接使用该API,而是应该将其集成到一个更大的能够提供高级API和工具的框架中去,比如AUTOSAR Adaptive Platform和ROS(Robotic Operating System)。
如果目标框架也基于发布/订阅的架构,那么系统对iceoryx的集成将非常简单。 目前已经集成iceoryx的框架有ROS2,eCAL,RTA-VRTE和Cyclone DDS。例如,如果我们将Eclipse Cyclone DDS和iceoryx结合使用,就可以创造出一个同时支持IPC和网络通信的开放且功能强大的中间件!
伍
使用许可
说了这么多和「中间件」iceoryx相关的内容,那么究竟谁最应该熟练掌握iceoryx的开发和应用呢?答案是:自动驾驶系统开发人员,机器人系统开发人员和独立游戏系统开发者!
首先,iceoryx本身是开源的[3],并且它使用了非常宽松的Apache-2.0许可证。也就是说,任何个人或者开发团队都可以把iceoryx用于商业用途而不必公开其衍生产品的源代码。
如果你想使你开发的iceoryx达到较高的安全级别,则需要从博世的子公司ETAS GmbH购买相关的安全手册,其中内容包括符合各安全级别的编译器设置信息和VRTE等配套产品,如ara_on_iceoryx (AUTOSAR API)等等。
当然,如果你的开发团队有足够的实力,也可以尝试自己开发整套API并取得安全级别认证。
结
随着整车的EE架构越来越集中化,域控制器和中央计算平台的装车率越来越高,基于POSIX的操作系统也会在汽车上越来越频繁的出现,各种新的功能也将会以服务或者APP的形式被不断的添加到车载系统上。
如何实现高效的IPC,都是各APP间通信一个绕不过去的坎儿。因此,IPC的效率直接决定了整个系统的实时性能。
同冯诺依曼瓶颈有些相似的是,无论顶层应用算法多么优秀,一个低效的「中间件」都会在开发的过程中“演变”为一个巨大的瓶颈,进而会慢慢地拖垮整个系统的运行。
幸运的是,iceoryx的出现则完全解决了这个存在于IPC中的“顽固问题”,它通过“零拷贝,共享内存”的特性,实现了恒定时间内近乎无限的数据传输!
iceoryx的这个特性在实际应用中意义重大!
在大大提高中央域控制器自身实时性能的同时,它也允许整个系统任意增加传感器或者提高传感器的分辨率,而无需承受由于传输数据量的增加带来的系统性能方面的损失,可谓是给自动驾驶技术的发展(至少在数据传输方面)铺平了道路。
因此,我们有理由相信,作为软件架构的核心部件,中间件Iceoryx这根backbone将完全撑的起自动驾驶技术的未来。
注
本文中大部分内容源自作者对参考文献的翻译与总结以及与Pöhnl先生及其开发团队核心成员Hoinkis先生的技术讨论。除个别图片来源于互联网,其他所有文中配图的使用均已得到Pöhnl先生的允许。本文仅在「几何四驱」平台独家首发,未经「作者本人」或者「几何四驱」授权,不得进行商业性转载。违规,必死磕到底!
参考文献
[1] Michael Pöhnl – 博世
https://www.eclipse.org/community/eclipse_newsletter/2019/december/4.php
[2] Simon Hoinkis – 博世
https://fosdem.org/2020/schedule/event/ema_iceoryx/attachments/slides/3723/export/events/attachments/ema_iceoryx/slides/3723/introduction_to_iceoryx_fosdem_2020.pdf
[3] Iceoryx
https://github.com/eclipse/iceoryx
[4] ROS
https://github.com/ros2/rmw_iceoryx
[5] ETAS GmbH
https://www.etas.com/en/products/rta-vrte.php
[6] Eclipse
https://github.com/eclipse-cyclonedds/cyclonedds
[7] Continental
https://github.com/continental/ecal
完
特邀撰稿:赵玉龙
作者微信:michalzhao
作者简介:现就职于德国斯图加特某世界顶级汽车零部件供应商 智能驾驶与控制事业部,负责车载计算平台的软件架构开发。
更多相关文章推荐
-
Part 3 | 无人车安全之战 — AI觉醒的前夜,人类还在沉睡?
本篇文章来源于微信公众号: 几何四驱