Part 8: The Harsh Reality of Deployment · From lab to real world
Chapter 22
可靠性工程 - 让机器人不只是“能跑”而是“能用”
你在公司做了一个 web 服务的 demo,给老板演示一切正常,老板说“不错,上线吧”。你心里慌不慌?多少慌一点。因为 demo 的时候你知道网络是好的、数据是干净的、用户只有你一个人。一旦上线,几千个用户同时访问,各种奇怪的输入涌进来,凌晨三点数据库连接池耗尽 - 这些才是真正的挑战。
机器人的 demo-to-production gap 比 web 服务大十倍。web 服务崩了,用户看到一个 500 页面,刷新一下可能就好了。机器人崩了,一台几十万的设备可能撞墙、夹伤人、或者在仓库中央趴窝堵住所有通道。物理世界没有“刷新”按钮。
这就是为什么可靠性工程在机器人领域不是一个“Nice to have”,而是产品能不能交付的生死线。一台 demo 成功率 90% 的机器人,意味着每跑 10 次就失败 1 次。如果它每天执行 100 个任务,那就是每天 10 次故障。客户不会用第二个月。
90% 到 99.9%:每一个百分点都是血泪
先说一个让很多从软件转过来的开发者不适应的现实:机器人的 failure mode 是组合爆炸的。
web 服务的输入空间虽然大,但大部分是文本和数字,你可以做输入校验、类型检查、边界测试。机器人的输入是整个物理世界 - 光照变了、地上多了一滩水、有个人突然从货架后面走出来、WiFi 信号被金属货架反射导致丢包。你不可能枚举所有场景。
在软件工程里有个概念叫“九的个数” - 99%(两个九)意味着每 100 次有 1 次失败,99.9%(三个九)意味着每 1000 次有 1 次失败。机器人行业的普遍目标是三个九到四个九,取决于应用场景。仓库 AGV 可以接受偶尔停下来等人类介入(三个九),但手术机器人必须四个九以上。
从 90% 到 99% 靠的是修 bug 和调参。从 99% 到 99.9% 靠的是系统性的可靠性工程 - 异常检测、自动恢复、安全边界、全链路监控。后面这个 0.9% 的提升,往往比前面 9% 花的精力还多。
异常检测:最难抓的 bug 是传感器在”正常”地输出错误数据
一台仓库机器人,偶尔会在一个特定货架附近突然急转弯,差点撞上旁边的货物。日志里没有任何 error,传感器 topic 的频率正常,所有 health check 都是绿色。排查了两天,最后发现是深度相机的镜头上沾了一层薄灰,导致右侧深度图有一块区域持续输出 0 值。感知模块把这些 0 值当成了”前方无限远,可以通行”,于是规划器生成了一条向右偏转的路径。
这就是传感器的静默失败(silent failure) - 传感器还在按时发布数据,数据格式完全正确,但内容是错的。它比”传感器断了”危险十倍,因为你的 health check 全部通过,机器人却在用错误的信息做决策。
类似的情况还有:LiDAR 的一个通道坏了,点云少了一个扇区,机器人在那个方向变成”半盲”;IMU 的陀螺仪温漂导致角速度有缓慢偏移,积分后位置估计越来越歪。这些故障的共同特点是 - 你不去主动检测,就永远不会发现。
怎么检测?三层防线:
数据合理性检查(sanity check):对每个传感器的输出设定合理范围。比如室内 LiDAR 的距离读数不应该超过 50 米,深度图中连续大面积的 0 值要报警,IMU 的加速度在机器人静止时应该接近 [0, 0, 9.8]。这是最简单也最容易被忽视的一层。
数据时效性检查:监控每个传感器 topic 的发布频率。一个标称 30Hz 的相机如果 200ms 没有新数据,很可能出了问题。ROS 2 里可以用 diagnostic_updater 包来做这件事,它提供了标准化的传感器健康监测框架。
跨传感器一致性检查:如果 LiDAR 说前面 1 米有障碍物,但深度相机说前面 3 米才有东西,那至少有一个在撒谎。多传感器交叉验证是检测 silent failure 的最有效手段。
执行器:电流飙升通常意味着坏事正在发生
一台机械臂在连续工作 4 小时后,某个关节开始发出异响,抓取精度明显下降。如果你在监控关节电流,其实 2 小时前就能看到信号 - 那个关节的电流基线从 1.2A 悄悄爬到了 1.8A,说明减速器磨损导致机械阻力增大。但因为没人在看这个指标,问题一直积累到机械层面才被发现。
关节电机的电流是执行器健康最灵敏的指标。电流突变意味着受到了外力(撞到东西了)或者控制器在震荡;电流缓慢爬升意味着机械磨损。温度是第二道信号 - 好的实践是接近阈值时自动降速(类似手机过热降频),超过阈值直接停机。位置误差(期望位置和实际位置的差值)是第三道:如果一个关节被命令转到 45 度但实际只到了 40 度,而且误差在持续增大,很可能是编码器松了或者减速器打滑。
通信断连与恢复
机器人系统是分布式的 - 传感器节点、感知节点、规划节点、控制节点通过 ROS 2 topic/service 通信。通信中断是家常便饭,尤其是涉及 WiFi 的场景(比如云端任务调度和机器人之间的通信)。
关键的设计原则是fail-safe default:当通信中断时,机器人应该进入一个安全的默认状态。具体来说:
- 如果和上位机(任务调度系统)断连,机器人应该停在当前位置等待恢复,而不是继续执行上一个任务
- 如果内部节点之间的通信中断(比如感知节点挂了),控制节点应该减速并准备急停,而不是用过期的感知数据继续飞奔
- 通信恢复后,不要直接“续上”之前的任务,而是重新评估当前状态再决定下一步
ROS 2 的 lifecycle node 机制在这里很有用。每个节点有明确的状态(unconfigured → inactive → active → finalized),可以在检测到异常时把节点切到 inactive 状态,问题解决后再切回 active。这比直接杀进程再重启要优雅得多。
安全边界:异常检测会失败,然后呢?
异常检测的目标是”发现问题”。但任何检测系统都有漏网之鱼 - 没见过的故障模式、传感器恰好没覆盖到的死角、检测逻辑本身的 bug。安全边界的设计思路不一样:即使所有检测都失效了,也不让机器人造成严重伤害。这是物理世界的 defense in depth。
想象成同心圆:最外层是速度和力矩限制,中间层是碰撞检测和自动减速,最内层是硬件急停。每一层都假设外面那层可能失效。
最外层 - 速度与力矩限制:每个关节都应该有硬编码的速度上限和力矩上限,这些限制不应该被上层软件覆盖(这叫 safety-rated software)。而且这不是一个固定数字 - 机器人周围没人时可以全速运行;检测到附近有人时,自动降速(Speed and Separation Monitoring,SSM);和人直接接触协作时,力矩压到非常低(Power and Force Limiting,PFL)。ISO/TS 15066 对人体不同部位能承受的最大接触力有明确规定,做协作机器人产品的话这个标准必读。
中间层 - 碰撞检测与软件急停:力矩突变检测或外部接触传感器触发后,在 10ms 内让所有关节停止运动。安全距离检测发现有人进入预设范围时,自动减速或停止。
最内层 - 硬件急停(E-Stop):一个大红色蘑菇头按钮,按下去硬件层面直接切断电机供电回路。不经过软件,不经过网络,不经过任何可能卡死的东西。
这三层里有一个经典的认知误区:大家觉得最难的是急停,其实急停后的恢复才是噩梦。机器人急停时可能正好拿着一个东西、手臂伸在半空中、或者停在了一个”不正常”的位姿。恢复时不能简单地”继续执行” - 你需要先评估当前状态,可能需要把手臂收回安全位姿,确认环境安全,然后才能恢复任务。很多团队在急停功能上花了一周,在急停恢复流程上花了一个月。
还有一层容易被忽视的防护:Watchdog(看门狗)。软件最危险的故障不是报错,而是卡死 - 一个死循环或死锁会让程序完全失去响应,但电机还在按照最后的指令运动。Watchdog 是一个独立模块,持续监听主控程序的心跳信号,如果规定时间内没收到心跳,自动触发急停。它守护的不是某个具体的故障,而是”软件本身失灵”这个最底层的风险。
日志与监控:用 web 服务的思路管理机器人数据
rosbag 录制和 Foxglove 可视化的基础知识在第 19 章已经讲过。这里要聊的是产品化部署时的核心问题:机器人的 SSD 空间有限,你不可能录制所有数据,但出事故时你又需要完整的事故现场。
解决方案和 web 服务的 APM(Application Performance Monitoring)如出一辙 - 常态采样 + 异常全量录制:
- 常态录制:只录低频关键 topic(任务状态、机器人位姿、关键传感器摘要),控制数据量在每天几个 GB 以内
- 触发式全量录制:当异常检测(前面那些 sanity check、电流监控)触发告警时,自动开始录制所有 topic 的全量数据,持续到异常结束后 30 秒。这样你既不会被海量数据淹没,又能在出问题时有完整的回放
关键事件(任务开始/结束、异常、急停)要实时上报到远程服务器,不能只存本地。对于车队管理场景(下一章会详细讲),你还需要一个 fleet dashboard,关注聚合指标:任务成功率、平均完成时间、故障频率、电量分布。
事故复盘流程
可靠性工程不只是防止事故,更重要的是从事故中学习。每次机器人出现故障,应该有一个标准化的复盘流程:
- 从 rosbag 回放事故前后的完整数据
- 定位根因:是感知错误、规划错误、执行错误,还是外部因素
- 判断是否是已知 failure mode - 如果是,为什么现有的检测机制没有捕获到它
- 修复并增加对应的检测/恢复逻辑
- 在仿真中重现这个场景,加入回归测试套件
这个流程看起来平平无奇,但坚持执行几个月后,你会发现机器人的可靠性有质的飞跃。大部分故障模式是重复出现的,你的系统会越来越“见多识广”。
踩坑实录:一个“简单”的传感器超时
分享一个典型的可靠性问题排查过程。
场景:一台在仓库里跑的移动机器人,偶尔会突然停下来不动,大概 5-10 秒后恢复正常。频率大概一天两三次,不可复现。
第一反应是看日志 - 没有任何 error 级别的日志。看 warning - 有一些 Nav2 的 “controller failed” 告警,但这类告警平时也偶尔出现,被忽略了。
后来在异常时段的 rosbag 里发现:LiDAR 的 /scan topic 在故障时段有大约 3 秒的数据缺失。3 秒对人来说很短,但对一台 2m/s 速度的机器人来说是 6 米的“盲区”。Nav2 的 local costmap 在这 3 秒内没有更新,local planner 发现 costmap 数据太旧,触发了 recovery behavior,机器人原地等待。
根因:仓库的 WiFi AP 每隔一段时间做信道切换,LiDAR 的数据通过内部网络传输时受到了干扰。注意 - LiDAR 本身没有坏,是网络环境的问题。
修复:把 LiDAR 数据的传输从 WiFi 切到有线连接(LiDAR 和主控板之间用 USB 或以太网直连),同时给 local costmap 增加了一个“数据新鲜度”检查 - 如果 LiDAR 数据超过 500ms 没更新,立即触发减速而不是等 Nav2 自己发现问题。
这个案例说明两件事:第一,可靠性问题的根因往往不在你第一个怀疑的地方;第二,没有完善的数据录制,你根本无从排查间歇性故障。
可靠性是一种文化
技术手段 - 异常检测、安全边界、日志监控 - 只是可靠性工程的一半。另一半是团队的工程文化。
做机器人产品的团队需要建立这样的共识:demo 成功不是里程碑,连续稳定运行 1000 次才是。每一个“偶尔出现的小问题”都值得被认真对待,因为在规模化部署后,“偶尔”会变成“每天”。安全相关的代码改动需要额外的 review 流程。事故复盘不是追责,而是系统改进的输入。
当你的机器人能在真实环境中连续跑一周不需要人类介入,你才算真正跨过了从“能跑”到“能用”的门槛。