百度Apollo 3.5是如何设计Cyber RT计算框架的?

自百度Apollo自动驾驶平台开源以来,已快速迭代至 3.5 版本,代码行数超过 39 万行,合作伙伴超过 130 家,吸引了来自 97 个国家的超 15000 名开发者。无疑,Apollo 是目前世界范围内最活跃的自动驾驶开放平台之一。


百度Apollo 3.5是如何设计Cyber RT计算框架的?_第1张图片


最新发布的 Apollo 3.5 总体架构从上到下仍分为四层,最底层为车辆平台,自动驾驶汽车需要对车辆进行线控改造,使得车载大脑可以通过电信号来控制车辆的执行器;往上一层是硬件平台,包括计算单元、传感器以及 V2X 相关接收设备等。再上一层是软件平台,主要包括操作系统、中间件、算法模块等。最顶层的是云端服务,主要包括地图、OTA 服务升级、数据平台、语音交互等方面。


此次发布的Apollo 3.5,解锁了Apollo 在复杂城市道路中的自动驾驶能力,并开源了 Cyber RT 计算框架、V2X 车路协同方案以及硬件平台的一些能力。


随着自动驾驶技术不断发展,Apollo 已经从研发走向量产产品落地。作为 Apollo 开源软件平台的一部分,Apollo Cyber RT 处于底层的实时操作系统(RTOS) 和算法模块之间,那么如何能够在保证高吞吐的情况下,又能低延迟的实时响应上层任务,并保证整个系统确定性的运转,1 月 24 日,在 CSDN 平台上举办的 Apollo 开发者社区公开课上,百度主任架构师王柏生就 Cyber RT 的设计思考,总体架构以及关键模块相关细节同开发者做了分享。


从 ROS 系统说起

百度Apollo 3.5是如何设计Cyber RT计算框架的?_第2张图片

Apollo 最初用的中间件是 ROS(机器人操作系统),概括来说,ROS 系统主要包含三方面:


第一是通信系统,ROS 是个分布式的松耦合系统,算法模块是以独立的进程形式存在的,也就是我们常说的 Node。ROS 基于 Socket 实现了pub/sub 的通信方式,不同的算法节点(node)之间通过 pub/sub 的发送/接收消息。


第二是 Framework&Tools (框架和工具),开发者可以基于 ROS 提供的 Client Library 和通信层,方便的收发消息。开发者只需要关注消息处理相关的算法,而至于算法何时被调用,全部由框架来处理。


第三是生态系统,从社区内,开发者可以很方便地寻找到很多现成的「传感器驱动」和「算法实现」等进行参考。


百度Apollo 3.5是如何设计Cyber RT计算框架的?_第3张图片


随着自动驾驶的发展,不少开发者,包括 Apollo 平台,把 ROS 应用于自动驾驶系统,毕竟自动驾驶汽车也相当于一个大的机器人。但是我们在实践中也遇到了很多挑战:


  • 首先,ROS 中的算法模块是以独立的进程形式存在的,那么这些进程之间应该以什么样的顺序去执行?实际上,Linux 本身是一个通用系统,内核中的调度器对上面的算法业务逻辑并不清楚,它只是在尽量满足公平的情况下让大家都得到调度。所以,ROS Node 运行顺序并无任何逻辑。


    但本质上自动驾驶是一个专用系统,任务应该按照一定的业务逻辑执行。那么是在 ROS 层加一个 Node,由其来同步各个算法任务的运行,还是在Linux 内核中实现新的调度策略,使其结合算法业务逻辑进行调度?前者的开销,后者的迁移性,都是需要思考的问题。


  • 其次,ROS 是一个分布式的系统。既然是分布式,就要有通信的开销。即使在同一个物理节点上,依然存在着通信的开销。所以 Apollo 前期曾经使用共享内存去降低 ROS 原生的基于 Socket 通信的开销。ROS 2 也在使用 DDS 解决通信方面的实时性。ROS 也支持 Nodelet 模式,这可以去掉进程间通信的开销,但是调度的挑战依然存在。


  • 第三,除了调度的不确定性,ROS 系统中还存在其他很多不确定的地方,比如内存的动态申请。


Cyber RT 的运行流程

百度Apollo 3.5是如何设计Cyber RT计算框架的?_第4张图片

算法模块通过有向无环图(DAG),配置任务间的逻辑关系。对于每个算法,也有其优先级、运行时间、使用资源等方面的配置。系统启动时,结合DAG、调度配置等,创建相应的 任务,从框架内部来讲,就是协程,调度器把任务放到各个 Processor 的队列中。然后,由 Sensor 输入的数据,驱动整个系统运转。


Cyber RT 架构

 

百度Apollo 3.5是如何设计Cyber RT计算框架的?_第5张图片

基本上,Cyber RT 包括如下软件模块: 


最下面一层是基础库,为了高效,Cyber RT 实现了自己的基础库。比如我们实现了 Lock-Free 的对象池,实现了 Lock-Free 的队列,随着成熟,会陆续开放更多。除了框架自身外,将来也会逐渐应用于算法模块。除了效率原因为,也希望 Cyber RT 减少依赖。


再往上是通信相关的,包括服务发现,还有 Publish-Subscribe 通信机制。 Cyber RT 也支持跨进程、跨机通信,上层业务逻辑无需关心,通信层会根据算法模块的部署,自动选择相应通信机制。 


通信层之上是 数据缓存/融合层,多路传感器之间数据需要融合,而且算法可能需要缓存一定的数据。比如典型的仿真应用,不同算法模块之间需要有一个数据桥梁,数据层起到了这个模块间通信的桥梁的作用。


再往上是计算模型,计算模型包括刚才前面提到的调度和任务,后面我们会详细讨论。


计算模型之上是为开发者提供的接口。Cyber RT为开发者提供了Component 类,开发者的算法业务模块只需要继承该类,实现其中的 Proc 接口即可。该接口类似于 ROS 中的 Callback,消息通过参数的方式传递,用户只要在Proc中实现算法、消息处理相关的逻辑。Cyber RT 也基于协程,为开发者提供了并行计算相关的接口。


Cyber RT 也为开发者提供了开发调试、录制回放等工具,未来还会开放性能调试工具。


从内核空间到用户空间

 

百度Apollo 3.5是如何设计Cyber RT计算框架的?_第6张图片

ROS 的主要挑战之一是没有调度,为了解决 ROS 遇到的问题,Cyber RT 的核心设计将调度、任务从内核空间搬到了用户空间。调度可以和算法业务逻辑紧密结合。


从 Cyber RT 角度,OS 的 Native thread 相当于物理 CPU。


在 OS 中,是内核中的调度器负责调度任务(进程、线程…)到物理 CPU 上运行。而在 Cyber RT 中,Cyber RT 中的调度器调度协程(Coroutine)在 Native Thread 上有序运行。


编排调度策略

 

百度Apollo 3.5是如何设计Cyber RT计算框架的?_第7张图片


任务编排策略是 Cyber RT 开源的主要策略之一。每个 Processor (Native Thread) 一个任务队列,由调度器编排队列中的任务。任务在哪个 CPU 上运行?任务之间是否需要相邻运行?哪些先运行?哪些后运行?都由调度器统一调度,任务基于协程实现。在任务阻塞时,快速让出 CPU。


每个物理 CPU 上除运行1个 normal 级别的 thread 外,运行着另外 1+ 个高优先级的 thread,基于此,实现用户空间的高优先级的任务抢占运行。比如,之前去 GPU 运行的算法,在 GPU 上完成运行返回后,应该尽快的得到运行。


这种调度策略,很好的结合了业务逻辑、数据共享和算力的平衡。并且任务不会在不同 CPU 上随机的调度来调度去,具有非常好的 Cache 友好性。


经典调度策略

 

百度Apollo 3.5是如何设计Cyber RT计算框架的?_第8张图片


任务编排策略,不仅需要对业务逻辑的深度理解,也需要结合计算机的算力等综合考虑。因此,Cyber RT 也提供了类似经典线程池模式的调度算法,这种模式几乎不存在配置的代价。对此,Cyber RT 也做了一些改进,比如为了减小锁的瓶颈,任务是多队列的。任务队列也支持优先级,后续还会支持分组,通过组控制算法对资源的使用。


算法任务的载体—协程

 

百度Apollo 3.5是如何设计Cyber RT计算框架的?_第9张图片


Cyber RT 使用了协程作为算法任务的载体。协程之于线程,就类似于线程之于物理 CPU,由 Cyber RT 中的调度器负责在各个线程之上周而复始,切换调度协程。为了算法模块在其他协处理器执行计算时,可以让出Processor(Native Thread),并在完成之后,回来时可以再次运行,Cyber RT采用了有状态的协程。


那么 Cyber RT 为什么采用协程呢?除了协程的切换非常快之外,调度的确定性是另外一个重要的原因。举个典型的例子,假设用 native thread 去执行一个任务,当任务因为去 GPU 等加速器运算时,或者因为资源原因被Block 时,在 thread 就绪时,什么时候调度上来其实是一个非确定的过程,完全依赖于操作系统以及其上任务的情况。


Cyber RT也支持跨进程、跨机通信


百度Apollo 3.5是如何设计Cyber RT计算框架的?_第10张图片


实际部署中,也存在着比如某个工具需要运行在独立的进程,安全系统部署在另外的节点。因此,Cyber RT 也支持跨进程、跨机通信。上层业务逻辑无需关心,通信层会根据算法模块的部署,自动选择相应通信机制。 

 

以上就是本次直播分享的内容。非常感谢大家的参加!也欢迎大家提出问题,进行交流。更多 Apollo 相关的技术干货也可以继续关注 Apollo 开发者社区每月的课程分享,也可以在 Apollo GitHub(https://github.com/ApolloAuto/apollo)上提出技术问题与我们互动,期待大家的沟通交流!

你可能感兴趣的:(百度Apollo 3.5是如何设计Cyber RT计算框架的?)