2. Apollo架构基础
Apollo 是面向城市道路自动驾驶的完整软件栈,它的工程复杂度并不只来自算法本身,更来自“算法如何被组织、被调度、被观测、被治理”。理解 Apollo 架构,关键是先建立一张分层地图:从硬件抽象到感知决策,从运行时框架到模块治理,每一层都有明确的职责边界。只有先看清边界,后续讨论模块治理、进程隔离、资源配额和故障恢复时,才不会把“框架问题”误判成“算法问题”。
一、Apollo 整体架构分层
Apollo 在工程上通常被划分为五层,自下而上依次是硬件层、驱动与抽象层、运行时框架层、功能模块层和工具与治理层。硬件层包括激光雷达、摄像头、毫米波雷达、组合导航、底盘 CAN 总线与计算平台;驱动与抽象层把不同厂商的传感器统一成标准数据接口,屏蔽设备差异;运行时框架层提供通信、调度、时间同步、参数配置和生命周期管理;功能模块层承载感知、定位、预测、规划、控制等核心算法;工具与治理层则负责可视化、数据回放、监控、诊断和模块治理。
这种分层的价值在于“依赖单向”。上层可以依赖下层提供的接口,但下层不应反向依赖具体算法模块。例如规划模块只消费预测和定位结果,不关心预测是由哪种模型产生的;控制模块只接收规划轨迹和车辆状态,不直接读取摄像头原始图像。依赖方向一旦清晰,模块替换、灰度发布和故障隔离才有工程基础。
二、核心模块划分与数据流
Apollo 的核心功能模块可以概括为“感知—定位—预测—规划—控制”五段式数据流。感知模块把多传感器数据融合为障碍物、车道线和可行驶区域;定位模块输出车辆在高精地图中的位姿;预测模块推断周围交通参与者的未来轨迹;规划模块结合地图、预测和车辆状态生成安全、平滑的行驶轨迹;控制模块把轨迹转化为油门、刹车和转向指令,通过 CAN 总线发送到底盘。
这些模块之间通过 Cyber RT 的 Channel 进行通信,而不是直接函数调用。每个模块通常以 Component 形式注册,声明自己的输入通道和输出通道。这样做的好处是:模块可以独立编译、独立部署、独立启停,数据流天然可观测。例如规划模块订阅 /apollo/prediction 和 /apollo/localization/pose,发布 /apollo/planning;控制模块订阅 /apollo/planning,发布 /apollo/control。通道名就是模块之间的契约。
# 典型模块启动与通道观察
cyber_launch start modules/planning/launch/planning.launch
cyber_monitor
# 观察通道频率与延迟
cyber_channel hz /apollo/planning
cyber_channel delay /apollo/control
三、运行时环境组成
Apollo 的运行时环境由计算平台、操作系统、Cyber RT 框架、配置与参数系统、日志与监控系统共同组成。计算平台提供 GPU、CPU 和高速网络;操作系统通常基于 Ubuntu 并做实时性优化;Cyber RT 负责组件加载、任务调度、通信和资源管理;配置系统通过 protobuf 和 launch 文件描述模块行为;日志与监控系统则持续采集模块心跳、通道频率、CPU/内存占用和故障事件。
运行时环境中最容易被忽视的是“时间”。Apollo 依赖统一时钟源,传感器数据、定位结果和规划轨迹都带有时间戳。如果时间同步异常,感知和定位的融合结果就会错位,规划模块可能基于过期障碍物做出决策。因此,运行时环境不仅要“跑起来”,还要保证时间一致、数据有序、资源可控。
四、模块治理的定位与价值
模块治理位于工具与治理层,但它并不是一个独立于运行时之外的“管理后台”,而是贯穿模块生命周期的控制面。它关注的问题包括:模块是否按预期启动、资源占用是否超限、通道频率是否下降、故障后能否自动恢复、版本变更是否可追溯。模块治理把“能跑”提升为“可控、可观测、可恢复”。
| 治理维度 | 关注对象 | 典型手段 | 价值 |
|---|---|---|---|
| 生命周期 | Component 启停、加载、退出 | launch 管理、健康检查 | 避免模块僵死或重复启动 |
| 资源 | CPU、内存、GPU、线程 | 配额、优先级、隔离 | 防止单模块拖垮整车系统 |
| 通信 | Channel 频率、延迟、丢包 | cyber_monitor、告警 | 保障数据流稳定 |
| 故障 | 崩溃、超时、数据断流 | 重启、降级、熔断 | 提升系统可用性 |
| 版本 | 模块版本、配置变更 | 灰度、回滚、审计 | 降低发布风险 |
五、案例与常见误区
假设车辆在路口出现“规划轨迹抖动”。如果只盯着规划算法,很容易陷入参数调优的循环。更系统的做法是先看运行时数据:定位位姿是否跳变、预测障碍物是否频繁出现和消失、规划输入通道频率是否稳定。若定位模块的 /apollo/localization/pose 频率从 100Hz 掉到 20Hz,规划模块就会在稀疏输入上反复重算,表现为轨迹抖动。此时治理动作应是定位模块的资源检查与恢复,而不是修改规划代价函数。
常见误区有三个:第一,把架构分层当成“画图作业”,实际开发时随意跨层调用,导致模块无法独立替换;第二,只关注算法精度,不关注通道频率、延迟和资源占用,系统在实验室能跑、在车上不稳定;第三,把模块治理理解为“运维的事”,但治理接口和健康状态需要模块在设计和开发阶段就暴露出来。治理不是事后补丁,而是架构的一部分。