急停优先:安全链路为什么必须独立于智能决策主线 系列:人形机器人大脑体系 · 安全专项
急停优先:安全链路为什么必须独立于智能决策主线
系列:人形机器人大脑体系 · 安全专项
字数:约 3200 字
摘要
几乎所有机器人系统都说自己"急停优先"。但这句话在工程上可以指三件完全不同的事:急停信号优先级最高、急停时降速运行、急停时整拍跳过。三者的安全强度差一个数量级,从外部却看不出来。
本文拆解一个具体问题:当安全链路和智能决策主线同时存在时,如何保证两者不会互相污染。 结论是四条结构性要求——安全状态只读、退出只认物理确认、动作模态整拍跳过、降级路径必须留痕。每一条都对应一段可以指认的代码,不是设计意图。
边界声明:本文讨论软件层的安全机制设计,不构成功能安全认证。机器人的本体急停、硬件安全联锁、力矩兜底防护,属于硬件厂商本体安全系统的职责范围。
一、先说清楚:安全链路为什么不能"接在"决策主线里
1.1 一个常见的错误设计
最直觉的做法是:决策主线算出一条动作序列,然后在末端加一道判断——如果急停有效,就把动作换成"停止"。
感知 → 决策 → 动作序列 → [急停判断] → 执行
这个设计能跑,能演示,看起来也符合"急停优先"。但它有三个隐患:
隐患 后果
判断在末梢 决策主线仍然完整运行,消耗算力、产生日志、可能触发副作用
判断可被绕过 只要有一条路径不经过这个末端判断,安全就失效
状态会交叉 急停期间决策仍在推进状态机,"恢复"时状态已经错位
第三条最隐蔽。 急停持续 3 秒,决策主线在这 3 秒里生成了 30 拍的动作计划。恢复的瞬间,这 30 拍的计划是"过期"还是"继续"?没人说得清,因为两套状态机一直在并行运行。
1.2 换一个结构:把安全放在最前面,而不是最后面
正确的结构是把判定放在每拍的第一步:
每一拍:
① 急停判定 ──► 成立 ──► 本拍动作模态整拍跳过(不执行、不推进)
② 质量门
③ 仲裁
④ 事件
差别看起来只是顺序,但性质完全不同:
· 放在末梢:决策跑完了,被拦下 —— 拦的是"结果"
· 放在最前:决策根本没跑 —— 拦的是"过程"
前者是过滤器,后者是开关。安全机制必须是开关。
二、四条结构性要求
下面的四条不是四条建议,是四条必须同时成立的要求。少一条,安全链路就退化成"看起来有"。
2.1 要求一:安全状态只读,软件没有触发接口
急停状态的进入,必须只由外部信号驱动。软件层不提供"触发急停"的接口。
这不是防君子,是防一类具体的事故:某段业务代码为了"稳妥",在检测到异常时主动调用急停。短期看是好事,长期看会形成依赖——因为业务代码可能误判,而误判触发的急停会让操作员对系统失去信任,进而养成"忽略急停"的习惯。这是安全系统最致命的腐蚀。
我们的实现里,急停状态机对外只有一个只读的感知接口:
observe() → 读取外部旁路信号,返回 True/False
类中没有任何写入旁路的接口
进入急停的路径只有一条:外部信号为真。软件无从干预。
2.2 要求二:退出只认物理确认,软件不得自动复位
进入由外部信号驱动,退出则必须由物理动作驱动——按下复位按钮、插入钥匙,而不是某个软件调用。
判断标准很简单:这次确认,能不能追溯到一个人。
ack_source == “physical” → 接受,状态解除
否则 → 拒绝,产生一条 ack_rejected 事件
拒绝不是静默的。每一次被拒绝的复位尝试都会留痕,因为"有人试图用软件复位急停"本身就是需要被看见的信号。
这条要求解决的是误复位风险。急停触发说明系统已经到了不该继续的状态,此时如果软件能自行复位,等于把安全状态变成了一个可以被代码清除的标记。
2.3 要求三:急停期间,动作模态整拍跳过
这是最容易被做错的一条,也是三条里技术含量最高的。
急停期间,“急停"和"正常"之间没有中间态。不是"降速运行”,不是"限制幅度",不是"只允许小幅动作"——是这一拍的整个动作模态都不参与仲裁。
if 急停有效 and 该模态属于动作相关:
本拍跳过质量门上报
该模态不参与仲裁
返回 decision = “estop_static”(附 absent_reason = “estop”)
注意 absent_reason 这个字段。它让"这一拍没有动作"变成一个有原因的状态,而不是"恰好没有数据"。这两者在日志里看起来一样,在排障时天差地别。
为什么是"整拍跳过"而不是"降优先级"? 因为降优先级意味着动作链路仍在运行,只是排在后面。一旦急停被绕过(比如某条路径直接读动作结果),降优先级就形同虚设。整拍跳过则不同:这一拍根本不存在动作输出,没有可以被绕过的东西。
2.4 要求四:安全不参与质量统计
这条很反直觉,但很重要。
系统里有"质量门"机制:通道质量不合格会导致降级,连续不合格达到阈值就回落到次优通道。
急停期间的动作模态,必须跳过质量门上报。 理由:
· 急停期间动作通道本来就没有输出,这是正常的
· 如果照常上报"质量不合格",会污染质量统计
· 连续 3 拍上报不合格 → 触发降级 → 系统认为动作通道坏了 → 急停解除后回落到次优通道
结果就是:一次正常的急停,导致急停解除后系统切到了备份链路。 这是个典型的"安全机制污染业务机制"的案例,而且从外部完全看不出来——机器人确实恢复运行了,只是走的是备份路径。
所以两套状态机必须不交叉:急停不进质量滞回统计。
三、急停和其他安全机制的关系
系统里不止一道安全防线。它们之间必须有明确的优先级,否则会出现"两个机制都认为自己该生效"的情况。

图:急停位于最外层,任何新增结构都不能绕过;急停有效时,内层机制一律不生效。
3.1 层级关系
┌─────────────────────────────────────┐
│ 急停(最外层) │ ← 每拍最先判定
│ ┌───────────────────────────────┐ │
│ │ 扩展模式门(链路互斥) │ │ ← 急停有效时整体不生效
│ │ ┌─────────────────────────┐ │ │
│ │ │ 仲裁 / 质量门 / 降级 │ │ │
│ │ └─────────────────────────┘ │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
这个结构的要点:急停不在链路内部,而是在链路之外、之上。
扩展机制、模式切换、第三方能力接入——这些都是后来加进来的。它们的设计原则里有一条硬约束:不得延长急停的有效路径。如果某个新增结构让急停从"触发"到"生效"多走了几步,这个结构就不合格。
3.2 为什么急停不能"聪明"一点
有人会问:急停期间机器人正在走上坡,突然全停会不会摔倒?能不能让它在急停时先保持平衡再停?
这个想法合理,但答案是不行,原因是责任归属。
如果急停时系统还要"聪明地"判断怎么停,那么"停下来之后倒了"这件事,责任就落在软件身上了。而软件无法判断当前的地形、负载、姿态是否允许安全停止——这些信息在急停那一刻往往是不可靠的(急停本身就常因为传感器异常而触发)。
所以边界必须这样划:急停是硬切断,怎么安全地停住是本体安全系统和机械设计的事。软件不做判断,因为做了就要担责,而担责的前提是能判断。
四、留痕:拒绝和降级都不能静默
安全机制的第三个维度是可追溯。一个不出声的安全系统,等于不存在。
4.1 降级必须发事件
链路降级的逻辑是:主通道连续 N 拍质量不合格 → 回落到次优通道。
这里最容易犯的错是:悄悄切换。从用户角度看,系统还在运行;只有日志里能找到痕迹,而日志往往没人看。
我们的做法是每次降级和恢复都产生一个事件:
link.fallback → “主通道连续 3 个 horizon 质量不合格,回落次优通道”
link.restore → “主通道恢复稳定 5 个 horizon,回切”
事件带上通道标识、触发原因、计数。这三个字段足够让人在事后回答:“那一刻系统为什么走了备份路径”。
绝不静默兜底——这是一条纪律,不是一个建议。静默兜底的危险在于:系统看起来一直是好的,直到有一天备份通道也坏了,才发现主通道已经坏了三个月。
4.2 拒绝必须带原因
前面提到的 absent_reason 字段,本质上是在回答一个问题:这一拍为什么没有动作?
可能的原因有很多:急停、通道未注册、数据逾期、质量不合格、上游未提供……如果不区分,排障时只能看到"没有动作",然后从零开始排查。
区分之后,"没有动作"变成了一个带原因的明确状态。这是可运维性的基础。
五、这套设计付出了什么代价
前面讲的全是好处,现在讲代价。任何安全机制都不是免费的。
5.1 代价一:延迟
每拍多几次判定,单次开销很小,但在高频控制循环里会累积。我们的选择是接受——因为它换来的是"上层沉默时系统仍然安全"。
具体量级:每拍多一次急停状态读取 + 一次模态判断,相对整拍的轨迹求解与仲裁,占比可以忽略。但如果有人在这条路径上加日志、加锁、加网络调用,量级立刻变化。所以这条路径上禁止任何阻塞操作,这是硬约束。
5.2 代价二:可用性下降
更严格的机制意味着更多请求被拒。上面说的"违反收紧约束返回空轨迹",在功能视角是"没完成任务",在安全视角是"正确地拒绝了"。
这不是设计缺陷,是安全优先范式下主动选择的取舍:安全锁的排他性,天然会牺牲一部分灵活切换的可用性。
但有一个判断标准是确定的:
如果一套系统从未拒绝过任何请求,那它的校验层大概率没有真正生效。
5.3 代价三:与业务逻辑的摩擦
“急停期间动作模态整拍跳过"意味着:上层应用在急停期间调用动作接口,会得到"没有输出”,而且不会报错。这对不熟悉这套机制的开发者是困惑的。
所以必须提供明确的状态查询:当前是否处于急停、这一拍为什么没有动作。否则开发者会用"重试"来绕过困惑,而这恰恰是最危险的反应。
六、给集成方的三个自检问题
如果您正在评估一套机器人软件的安全设计,可以问这三个问题:
问题 如果答案是"否",意味着什么
急停状态能否由软件主动触发? 能,说明安全依赖业务代码的正确性——这是最危险的依赖
急停期间动作链路是完全停止,还是降级运行? 降级运行,说明存在可以被绕过的窗口
降级和拒绝是否都留下了可查的证据? 没有,说明出问题时无法定位,只能重启
三个问题都不涉及实现细节,但足以区分"看起来有安全机制"和"安全机制真的生效"。
七、小结
急停优先不是一个功能,是一个结构位置。
放在末梢,它是过滤器;放在最前,它是开关。前者的安全强度取决于"有没有绕过的路径",后者取决于"这一拍还有没有动作输出"——后者是可判定的,前者不是。
四句话说清这套设计:
进入只认外部信号,软件没有触发权。
退出只认物理确认,软件不能自我复位。
期间整拍跳过,没有"稍微动一下"的中间态。
降级与拒绝都留痕,沉默就是故障。
最后一句可能有点反直觉,但它是这套设计的核心:
安全机制的价值,不在于它能在正常运行时不碍事,而在于它能在异常发生时不需要被信任。
因为异常发生时,最不可信的就是上层软件。
获取与部署
⚠️ 重要说明:软件包托管于我方阿里云 ECS 静态服务节点,链接为配套文章专属访问地址。
服务仅用于本次文稿配套评估试用,链接会按需维护,我方有权随时关停访问。
文件禁止二次分发、转存商用;如需商用正式包与持续技术支持,请联系我方商务对接获取正式发布渠道。
下载地址
http://47.119.135.145:8080/lumina_pmd_v3.1.2_so_publish.tar.gz
部署四步
- 下载并校验总包 MD5
md5sum lumina_pmd_v3.1.2_so_publish.tar.gz期望值:eab169edc7a6d31ee636c8edc0f6c99c
- 解压
tar -xzf lumina_pmd_v3.1.2_so_publish.tar.gz - 执行安装脚本配置环境
bash install.sh
如提示 /etc/profile.d 权限不足,改用用户级 PYTHONPATH 方案:
echo ‘export PYTHONPATH=PWD/coremodules:PWD/core_modules:PWD/coremodules:PWD/adapter:PWD/vtlahal:PWD/vtla_hal:PWD/vtlahal:PYTHONPATH’ >> ~/.bashrc
source ~/.bashrc - 执行冒烟测试,验证模块导入与全链路功能
cd lumina_pmd_v3.1.2_so_publish
bash install.sh
install.sh 已内置核心模块导入自检,全部通过时输出 OK: core modules loaded。
环境要求:Ubuntu 22.04 LTS · Python 3.10 · x86_64 · 内存 8GB 起(推荐 16GB)
文件级验真:包内附 md5_manifest.txt(251 条文件级指纹),可执行以下命令逐文件复核:
md5sum -c md5_manifest.txt --quiet
全部条目无输出即代表一致;若出现 FAILED,请核对 Python 版本是否为 3.10(编译产物与解释器版本绑定)。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)