本节摘要:ROS 解决"模块怎么通信",架构解决"功能该放哪个模块"。本节给出传感器层-感知层-决策层-执行层的四层参考架构,讲清模块切分的三条判据与接口设计的四条约定,并说明失效降级为什么必须在架构期设计而非事后补丁。
很多项目这样开始:一个节点负责读雷达、算定位、做规划、发指令——反正都在一起方便。三个月后它变成三千行的"万能节点":改一行参数要整包重启;日志里四类信息搅在一起,查问题像考古;新人不敢动任何一行。然后有人提议拆分,拆分失败——因为代码里的依赖已经缠死,定位与规划共享了七个全局变量。这个反例的教训不是"要模块化"这句废话,而是:模块边界必须由数据的所有权划定,而不是由开发顺序顺成。谁生产这份数据、谁消费它、过期了归谁,想清这三问,边界自然浮现。
机器人软件的通行分法是四层,每层一个明确职责:
| 层 | 职责 | 典型频率 | 典型内容 |
|---|---|---|---|
| 传感器层 | 驱动与原始数据出仓 | 10–1000 Hz | 雷达驱动、IMU 驱动、底盘驱动 |
| 感知层 | 从原始数据到估计 | 1–50 Hz | 定位、SLAM、检测、融合 |
| 决策层 | 从估计到计划 | 1–10 Hz | 任务调度、全局规划、行为状态机 |
| 执行层 | 从计划到力矩 | 50–1000 Hz | 轨迹跟踪、伺服控制、安全停障 |
两层之间的箭头就是第 5.1 节的话题网络。分层的深层理由是时间尺度分离:层内数据频率相近,层间用消息队列解耦——感知慢半拍不该拖死执行层,执行层的高频回路也不该被决策层的大计算阻塞。反过来,架构审查第一问就是"这条消息跨了几层、频率差多少",频率差越大越要小心队列深度与时间戳。

模块间消息一旦定下就是长期合同,四条约定能省掉绝大多数扯皮:
每个关键模块都要回答"我挂了系统怎么办"。参考答案分级:感知降级(SLAM 失效 → 退到里程计航位推算,限速行驶)、决策降级(规划器超时 → 原地停等,不发模糊指令)、执行降级(轨迹跟踪发散 → 断开轨迹环,走安全停障)。设计要点有两条:降级触发必须是显式状态(广播 FAULT 与原因码,让全系统知道现在是降级态);降级后的行为要单独测试——大量现场事故源于降级路径从未被走过,真降级时行为未知。
💡 关键直觉:架构的好坏不画在图上,显现在凌晨三点的故障里。模块化、置信度、降级出口,每一条都是给"出事那天"写的保险——平时看着冗余,出事时是唯一的光。
组件化之后的新问题:二十个节点的启动顺序、依赖等待、故障重启由谁管。生命周期节点把节点状态显式化——未配置、未激活、已激活、已关闭——状态迁移由外部管理者驱动,每个迁移点执行校验(配置阶段检查参数合法、激活阶段自检传感器就绪)。这解决了"隐式启动"的三类事故:节点起好了但下游先动(拿到空数据误判故障)、节点反复崩溃重启(没有退避策略拖垮整机)、关闭顺序错乱(驱动先停导致控制层收到僵尸数据)。生命周期管理的代价是启动逻辑变复杂,换来的是"整机启停像开关灯一样确定"——设备量上去之后这笔交易稳赚。
架构的最后一层是"让架构自己可被观察"。三级监控从下往上:进程级(节点是否存活、CPU 内存水位)——最低保障;数据级(关键话题的频率、时延、时间戳年龄)——第 5 章反复强调的时序看板在这里实现;语义级(系统处于什么业务状态、降级了没有、为什么)——行为状态机的状态广播。三级都做才叫可观测:只做进程级,会出现"节点活着但发的是三年前的地图"这种僵尸状态;只做语义级,出问题不知道是哪个进程的锅。工程上第三级常被漏掉——而恰恰是它,决定运维人员能否在用户投诉前发现问题。
这是架构期的经典矛盾:感知层与决策层都要用坐标变换,放哪边?原则是"按数据流方向复用,不按方便程度复用"。坐标变换是感知层的产出物(它需要全系统的外参标定知识),决策层只应消费变换服务,而不是自己持有一份标定副本——两份标定迟早不同步。通用判断式:一段代码若被两层需要,看它依赖的原始数据属于哪层,就把代码放哪层,另一层通过接口调用。把这条写进团队的架构评审清单,能消掉一半的"代码放哪"争论。
补机器人软件分层的黄金五层:驱动层(硬件封装,标准是接口稳定可替换硬件不动上层)→功能层(感知、定位、规划、控制各模块,标准是输入输出契约明确、可独立测试)→任务层(状态机或行为树编排,标准是任务逻辑改动不碰功能模块)→接口层(人机界面、遥操作、语音,标准是降级可用)→运维层(日志、监控、OTA、参数管理,标准是出问题能定位)。分层的价值在改动隔离:换一个激光雷达只动驱动层,改一个任务流程只动任务层。判断一个机器人软件架构好不好的快捷方法:提三个假设变更(换传感器、改任务流程、加一个新功能),看各自要碰几层——碰的层数越少,架构的模块化成色越好。多数架构烂尾的原因是把功能逻辑写进驱动回调、把任务判断散在功能模块里,两层污染让每次改动都变成全局回归。