结论:从「软件认为该动作」到「车轮真的动了」,中间至少有八层各自独立的门。任何一层通过,都不代表下一层会放行:使能状态为真不代表执行器活动,控制消息的 valid 只是元数据,主机发出去的帧还可能被板端白名单拒掉。把「发出去」当成「执行了」,是这类系统里最贵的误判。
八层门各自检查什么
本文基线为源码快照 c8fb906,静态串联「状态机 → 控制器 → 车型网关 → 主机发送 → 板端固件」这条链:
| 层 | 真正检查了什么 | 不能据此推断什么 |
|---|---|---|
| 使能状态 | 非被动模式且已初始化才计算使能与活动 | 使能为真不等于横纵执行器都活动,也不等于板端已放行 |
| 横纵活动位 | 横向还要求无临/永久转向故障与静止转向许可;纵向要求纵向能力且无纵向覆盖事件 | 此处没有统一的全量检查;纵向活动位基于「使能」而非「活动」 |
| 控制数值与发布 | 关闭活动位时重置控制器;曲率限幅;非有限数值置零 | 消息的 valid 是元数据,不是硬阻断 |
| 车型网关 | 非被动且事件集不含初始化中,才进入控制更新;控制消息存活时才应用车型控制器 | 该分支只检查单条消息存活,不是全量检查;sendcan.valid=False 仍可能带着候选帧 |
| 主机 CAN 回调 | 指纹、固件查询、初始化可另发帧;安全模式握手等两个完成信号才切车型安全模式 | 「所有发送都来自控制器」不成立;握手参数也不是本机代码的权限认证 |
| 发送线程 | 事件时间距现在小于 1 秒且非测试发送才走硬件发送 | 该函数不读事件有效性、不读使能状态,一秒是陈旧帧门而非安全截止期限 |
| 心跳线程 | 约 10 Hz 依据状态消息的存活/有效与使能计算是否接管 | 心跳与发送线程相互独立;未接管不是逐帧否决 |
| 板端发送 | 完整 CAN 包经白名单、车型发送钩子与继电器故障门 | 白名单中有帧不等于动作获准;车型钩子通常还查许可以及扭矩/角度/加速度限值 |
失效时各层怎么反应
这是排查线上问题的实用部分——同一类故障在不同层的行为并不一致:
| 情况 | 本快照中的处理 | 仍待验证 |
|---|---|---|
| 状态消息失联或无效 | 心跳侧据此令后续心跳显示未接管;控制器本轮计算并未据此统一停止 | 各进程更新顺序、残留帧、车型钩子与原厂接管时延 |
| 控制消息失联 | 网关不再发布新的控制帧 | 独立诊断/初始化回调、最后一帧生效时间、板端与车辆超时 |
| CAN 无效但仍发了控制帧 | 网关把发送标记为无效,但发送线程只查年龄与测试标志 | 车型控制器是否真生成帧、板端是否拒帧、故障消息调度顺序 |
| 主机帧陈旧 | 年龄达到 1 秒的发送事件被丢弃,板端从未见到该包 | 低于 1 秒但超过车型安全周期的行为及总线/接口堵塞 |
| 板端心跳中断 | 点火时约 5 秒、非点火约 2 秒阈值后切入静默并清除接管标志 | 中断与接口故障的最坏墙上延迟、继电器与车端实际恢复 |
| 许可与接管标志不一致 | 板端 1 Hz 段连续累计 3 次后清许可;上位机侧也对不一致累计并进入不匹配路径 | 两条路径异步,不能把 3 次与 200 次解释成相同的失效时限 |
三个容易被当成「安全证明」的东西
- 消息的
valid字段。它由 CAN 有效位赋值,是元数据。它既不阻断车型控制器生成帧,也不阻断发送线程,更不能替代板端校验。 - 界面上的使能图标。使能状态为真只说明状态机走到了这一步,横向与纵向是否真的活动要分别看活动位,板端是否放行还要再往下一层。
- 安全模式握手的完成参数。握手表示板端可以切到对应车型的安全模式,它不是本机代码的权限认证,也不是「动作已被批准」的凭据。
做故障注入该覆盖哪些场景
如果自研硬件或做插件化改造,下面这些场景必须逐条注入,而且顺序上应先回放与软硬件在环,再进封闭场地:
| 注入场景 | 要观察什么 |
|---|---|
| CAN 无效 | 是否会带着无效标记继续产生候选帧,板端是否拦截 |
| 控制消息丢失 | 最后一帧的实际生效时刻与停帧确认 |
| 状态消息丢失 | 心跳切换与控制器是否继续计算之间存在的时间差 |
| 送板延迟与接口堵塞 | 1 秒陈旧门以下、车型安全周期以上的中间地带 |
| 心跳中断 | 板端静默阈值的实际墙上时间 |
| 校验错与原厂接管 | 原厂巡航/制动/转向接管与诊断回调并发时的行为 |
插件化改造的硬要求
把传感器、车型或控制算法做成可替换插件时,状态消息与控制消息主题不应成为无认证的任意写入口。核心要维持唯一控制权、消息来源与新鲜度校验,板端保留独立的发送限制与安全模式回读。
特别要把这五个环节分开记录:候选帧生成、发送消息发布、接口发送、板端接受、车辆执行。把这五件事混成一个「已下发」的日志,等于放弃了事后定责的能力。
常见问题
为什么「使能」了动作却没执行?
因为使能只是第一层。横向和纵向各有独立活动条件(故障、静止许可、纵向覆盖事件),网关、发送线程和板端白名单还会各自过滤。任何一层不通过,动作就不会发生。
发送消息标记为无效,为什么还可能发出去?
因为有效性是元数据,发送线程实际只看事件年龄和测试标志,不读有效性也不读使能。所以带无效标记的候选帧仍可能到达板端——真正的拦截点在车型钩子和板端。
板端心跳中断后多久会停发?
源代码里的名义阈值是点火时约 5 秒、非点火约 2 秒后切入静默并清除接管标志。但这是 1 Hz 检查的计数阈值,最坏墙上延迟还要看中断与接口故障情况。
安全模式握手完成就代表动作被批准了吗?
不是。握手只表示板端可以切换到对应车型的安全模式,它既不是权限认证,也不代表具体动作已获准。动作是否放行仍由板端白名单与车型钩子逐帧判定。
延伸阅读
- UDS 诊断工具为什么不能随手调 —— 诊断这条旁路如何绕过执行链
- 签名包与 A/B 回退 —— 板端固件侧的完整性防线
- 同一个「转向灯」在三家车厂是三种实现 —— 执行链上游的输入质量
参考资料
- 项目 02 —— NAS
谭健强/openpilot-research/ACTUATION_GATE_CHAIN_DEEP_DIVE.md(执行链门控与失效边界,含源码行号索引) - 项目 02 ——
openpilot-research/CAN_PARSER_HEALTH_DEEP_DIVE.md(解析健康语义) - 项目 02 ——
openpilot-research/CAR_STATE_NORMALIZATION_DEEP_DIVE.md(车辆状态归一化)
说明:本文为对固定源码快照的静态分析,描述的是多层控制请求与板端过滤,不是实车执行时延证明。本轮未运行测试、未刷写板卡、未发送 CAN 报文、未连接车辆。车型控制器、板级电气与硬件在环结果仍须逐车核验。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11
发表回复