3. 自动驾驶软件栈与中间件

自动驾驶系统并不是一个“大一统”的程序,而是由多个职责清晰、节奏各异的软件模块协同构成的实时系统。理解这些模块的划分方式,以及中间件在其中承担的数据流、调度与通信职责,是设计 ROS2 自动驾驶架构的起点。本节先建立模块地图,再剖析中间件如何把分散的算法节点组织成一条可靠、可观测、可扩展的流水线。

一、核心原理:五类模块的职责与节奏差异

从功能上看,自动驾驶软件栈通常划分为感知、定位、预测、规划、控制五大类模块。它们并非简单的线性串联,而是存在大量反馈与并行关系:定位为感知提供位姿先验,感知为预测提供目标轨迹,预测为规划提供交互意图,规划为控制提供轨迹或加速度指令,控制再把执行结果反馈给车辆状态估计。

  • 感知(Perception):处理摄像头、激光雷达、毫米波雷达等原始数据,输出障碍物、车道线、可行驶区域、交通标志等结构化信息。典型频率 10~30 Hz,数据量大,计算密集。
  • 定位(Localization):融合 GNSS、IMU、轮速、激光/视觉匹配,输出车辆在全局地图中的位姿与速度。典型频率 50~100 Hz,对延迟和抖动极其敏感。
  • 预测(Prediction):基于感知目标与地图,推断其他交通参与者未来数秒的轨迹或意图分布。典型频率 5~10 Hz,计算量随目标数增长。
  • 规划(Planning):结合路由、行为决策与运动规划,生成安全、舒适、合法的行驶轨迹。典型频率 5~20 Hz,需要与预测、地图频繁交互。
  • 控制(Control):将规划轨迹转化为油门、刹车、转向指令,并通过 CAN 或线控底盘执行。典型频率 50~100 Hz,要求确定性时延。

这些模块的节奏差异决定了中间件不能采用“统一时钟、统一频率”的简单模型,而必须支持多速率、多优先级、多 QoS 的并发通信。

二、中间件的三大核心职责

中间件位于操作系统与算法模块之间,核心职责可归纳为数据流、调度与通信三条主线。

数据流职责:中间件负责把传感器原始数据、感知结果、定位位姿、预测轨迹、规划路径、控制指令等以主题(Topic)或服务(Service)形式组织起来,形成有向数据流图。它需要处理数据的分发、缓存、时间同步与生命周期管理,避免模块之间直接耦合。

调度职责:中间件通过执行器(Executor)、回调组(Callback Group)和优先级配置,决定哪个回调先执行、是否并行、是否抢占。对于控制与定位这类硬实时链路,需要绑定高优先级线程或实时调度策略;对于感知与预测这类计算密集链路,则更关注吞吐与资源隔离。

通信职责:中间件提供发布/订阅、请求/响应、动作(Action)等通信模式,并支持 QoS 策略,如可靠性、历史深度、截止时间、存活期。它还要处理节点发现、序列化、传输层选择(共享内存、UDP、TCP)以及跨进程、跨主机的透明通信。

中间件的价值不在于“让消息能发出去”,而在于让不同频率、不同可靠性要求、不同实时性等级的数据流在同一套系统中可预测地协同。

三、数据流与调度关系图解

下图给出一个典型的自动驾驶软件栈数据流与中间件职责关系。传感器数据经中间件进入感知与定位,定位结果同时反馈给感知和规划;预测与规划通过中间件交换目标轨迹与自车轨迹;控制模块以高优先级订阅规划结果,并通过车辆接口输出执行指令。

自动驾驶软件栈数据流与中间件职责 传感器层 Camera / LiDAR / Radar 定位模块 GNSS/IMU/匹配 感知模块 检测 / 分割 / 跟踪 预测模块 轨迹 / 意图预测 规划模块 路由 / 决策 / 运动规划 控制模块 纵向 / 横向控制 中间件核心职责 数据流:Topic / Service / Action 调度:Executor / 回调组 / 优先级 通信:QoS / 发现 / 序列化 时间同步 / 生命周期 / 可观测 DDS / RMW / 共享内存 中间件数据总线(DDS/RMW) 发布/订阅 · QoS · 时间戳 · 序列化 · 发现 执行器与调度层 单线程/多线程执行器 · 回调组 · 实时优先级 · CPU 亲和 车辆执行接口 CAN / 线控底盘 油门 / 刹车 / 转向 执行反馈 安全监控 原始数据 位姿 目标列表 预测轨迹 规划轨迹 控制指令

四、方法流程:从模块划分到中间件配置

在实际工程中,模块划分与中间件配置需要同步推进,通常遵循以下流程:

  1. 定义数据契约:为每个模块确定输入输出消息类型、频率、时间戳语义和坐标系。例如感知输出 DetectedObjectArray,定位输出 Odometry,规划输出 Trajectory。
  2. 划分节点粒度:按计算资源、故障隔离和复用需求决定节点边界。感知可拆分为检测、跟踪、融合多个节点;控制可合并为单节点以保证低延迟。
  3. 配置 QoS:传感器数据常用 SensorDataQoS(Best Effort、小队列);控制指令使用 Reliable、Keep Last 1;地图与静态信息使用 Transient Local。
  4. 设计执行器:为实时链路创建独立回调组和线程,绑定 CPU 亲和;为计算密集链路使用多线程执行器并限制并发度。
  5. 加入可观测性:通过中间件统计话题频率、延迟、丢包和回调耗时,形成运行时监控。
# 示例:为控制链路配置高优先级 QoS 与独立回调组
control_qos:
  reliability: reliable
  durability: volatile
  history: keep_last
  depth: 1
  deadline:
    sec: 0
    nanosec: 20000000   # 20 ms

executor:
  type: MultiThreadedExecutor
  callback_groups:
    - name: control_group
      priority: 90
      cpu_affinity: [2]
    - name: perception_group
      priority: 50
      cpu_affinity: [3,4,5]

五、案例场景:城市路口通行

以城市无保护左转为例:感知以 20 Hz 输出周围车辆与行人;定位以 100 Hz 输出自车位姿;预测以 10 Hz 推断对向直行车辆的未来 3 秒轨迹;规划以 10 Hz 生成左转轨迹,并在冲突点前进行博弈决策;控制以 100 Hz 跟踪轨迹并输出转向与制动。中间件需要保证定位位姿与控制指令的低延迟,同时允许感知与预测在资源紧张时适度降频,但不能阻塞控制链路。

在 ROS2 中,可通过 ros2 topic hz、ros2 topic delay 和 ros2 doctor 快速检查数据流健康度;通过 ros2 run 配合 --ros-args -p 调整节点参数,验证不同 QoS 下的行为差异。

六、常见误区与复盘

误区 表现 后果 改进方向
所有话题使用默认 QoS 传感器与控制共用 Reliable、大队列 控制延迟抖动,内存增长 按数据语义分级配置 QoS
单执行器承载全部回调 感知回调阻塞控制回调 控制周期超时,车辆抖动 拆分回调组,实时链路独立线程
模块间直接共享内存指针 绕过中间件传递大对象 耦合严重,无法分布式部署 通过消息契约与零拷贝传输解耦
忽略时间同步 感知与定位时间戳不一致 融合结果偏差,规划误判 统一时钟源,使用消息时间戳对齐
缺少运行时监控 只在上线前测试 偶发丢包与延迟难以定位 接入中间件统计与日志追踪
模块划分不是越细越好。过度拆分节点会增加序列化、发现和调度开销;过度合并则牺牲故障隔离与并行度。应以数据频率、实时性等级和团队边界为依据,在中间件层用 QoS 与执行器策略弥补模块粒度的不足。

综上,感知、定位、预测、规划、控制五类模块构成了自动驾驶软件栈的功能骨架,而中间件通过数据流组织、调度策略和通信机制,把这些异构模块粘合成一个可预测、可观测、可扩展的实时系统。掌握模块划分与中间件职责的对应关系,才能在 ROS2 中做出合理的节点、话题、QoS 与执行器设计。