结论:在 Toyota 输入链里,can_valid 与 bus_timeout 是两种不同的健康语义。can_valid 只对已注册报文做活性检查;bus_timeout 只代表总线流量空窗,而且 CANParser.update() 对该总线的任何帧都会刷新 last_nonempty_nanos,即使不是已注册地址。因此「总线有流量」不等于「每个必需信号都健康」,单看 vl 值也无法区分「未收到有效样本」和「物理零」。
入口与关键函数
Toyota 的输入链从 card 解码 CAN 帧开始,经车型接口把信号归一成 CarState,再向下游发布与消费。
| 组件/函数 | 源码 | 作用 |
|---|---|---|
CarInterface 绑定 |
interface.py |
指定 Toyota CarState/CarController/雷达接口;参数构建决定车型标志、角度模式和纵向能力。 |
card.state_update() |
card.py |
接收 can,转为帧列表,再调用车型接口和雷达接口。 |
CarInterfaceBase.update() |
interfaces.py |
先更新所有 CANParser,后调用 CarState.update(),再汇总 canValid/canTimeout、速度显示迟滞和按钮启用。 |
CarState.get_can_parsers() |
carstate.py |
为动力总线 0 和相机总线 2 创建解析器,仅预注册 BLINKERS_STATE。 |
parse_wheel_speeds() |
interfaces.py |
四轮均值乘单位及车型系数,再进入 KF1D 得到 vEgo/aEgo。 |
总线注册与健康的准确含义
Toyota 的动力总线只预注册 BLINKERS_STATE,频率传入 NaN;NaN 在 _add_message() 中令该报文 ignore_alive=True,所以转向灯报文本身不参与超时失效,并非所有 Toyota 输入都忽略超时。其余报文是在 CarState.update() 第一次读 cp.vl[...] 时由 VLDict 动态注册;首次读发生在本轮 cp.update() 之后,即该轮此前收到的报文尚未由新注册状态解码。
普通动态报文先以 1 Hz 假定频率、10 秒超时阈值注册,收到足够样本后解析器估计频率并改为约十个周期的阈值。这里有两个容易混淆的点:其一,CANParser.update() 对该总线的任何帧都会刷新 last_nonempty_nanos,所以 bus_timeout 只代表总线流量空窗;其二,MessageState.parse() 遇 DBC checksum 或 counter 错误不更新缓存值与时间戳。最终 CarInterfaceBase.update() 对两路解析器取 all(can_valid) 和 any(bus_timeout)。
还有一个细节:转角偏移更新分支内部也读取 cp.can_valid,接口汇总时又读取一次;当前 can_valid 属性读取会更新 can_invalid_cnt,不是纯查询。因此不能把它解释为严格的「连续五次 update 失败后失效」。
信号到 CarState 的映射
| 类别 | 来源与条件 | 输出/状态 |
|---|---|---|
| 车身与踏板 | 动力总线 BODY_CONTROL_STATE、BRAKE_MODULE、ESP_CONTROL;SecOC 用 GAS_PEDAL,其他用 PCM_CRUISE.GAS_RELEASED |
doorOpen、安全带、驻车制动、制动/保持、gasPressed。 |
| 档位与车速 | SecOC 用 GEAR_PACKET_HYBRID,其他用 GEAR_PACKET;四轮 WHEEL_SPEEDS |
枚举映射档位;轮速先得 vEgoRaw,再滤波为 vEgo/aEgo;vEgoCluster 初始设为 vEgo * 1.015。 |
| 转向 | STEER_ANGLE_SENSOR、STEER_TORQUE_SENSOR、EPS_STATUS |
转角/角速度、扭矩、驾驶员转向判定、LKA/LTA 临时与永久故障。 |
| 巡航 | UNSUPPORTED_DSU 用 DSU_CRUISE 与 PCM_CRUISE_ALT;其他用 PCM_CRUISE_2 与 PCM_CRUISE_SM;运行态来自 PCM_CRUISE |
主开关、设定车速、仪表设定车速、启用/停止/非自适应状态和故障。 |
| 按键/HUD | 相机 LKAS_HUD;部分平台的 ACC_CONTROL.DISTANCE |
LKAS 边沿合成按钮事件、gap 调整事件;相机 HUD 缓存供控制器构帧。 |
其中 stockAeb 仅在非 SecOC、未禁雷达路径读取,且要求 PRECOLLISION_ACTIVE 与负 FORCE;accFaulted 的低速 lockout 附加判据仅在源码指定的 TSS2/ACC 类型和 openpilot 纵向控制条件下执行,不应泛化为所有 Toyota 车型。
来源选择也是常被误解的点:cp_acc 在 TSS2 且非 RADAR_ACC 时指相机解析器,否则指动力解析器;这是 ACC/PCS 的信号来源选择,不是对两路数据作一致性比对。相机解析器初始没有注册报文,全部依赖动态注册;原车 ADAS 的 stockAeb、stockFcw 与左右盲区还受 TSS2、HAS_BSM、DISABLE_RADAR 条件控制,ACC_CONTROL.ACC_TYPE 影响低速 lockout 分支。
转角标定、故障与按钮时序
STEER_TORQUE_SENSOR.STEER_ANGLE 在非零、未初始化时才让 accurate_steer_angle_seen 永久锁存为真。此后仅在原角度小于 90 度、角速度小于 100 度/秒且 cp.can_valid 为真时,才更新 60 秒时间常数的 FirstOrderFilter 偏移;首次合格样本直接初始化。偏移一旦初始化,后续即便本轮不再更新,也会继续用于 torque_sensor_angle - offset。这里没有单独的偏移年龄或置信度字段。
steeringPressed 是驾驶员力矩绝对值直接大于 STEER_THRESHOLD,不是调用基类的去抖函数。EPS_STATUS.LKA_STATE 总是参与故障映射,仅角度控制模式再并入 LTA_STATE;代码列出的临时故障为 0/9/11/21/25,永久故障为 3/17,这只是软件分类。TSS2 相机 LDA_ON_MESSAGE 从非零值切换到不同值时,代码合成一次 LKAS 按下和释放事件。lkas_hud 与 SecOC 同步字段是从解析器字典浅拷贝的最近缓存,没有在此单独检查样本年龄。
消费与插件设计约束
card 将 CS.canValid 作为 carState 外层 valid,也用于 sendcan 消息的外层有效位;后者是否真正被 MCU 拒绝仍取决于车端传输和 safety 链,不能把外层位等同于物理禁发。CarEvents 把 vehicleSensorsInvalid、accFaulted、转向故障、驾驶员施力等转成事件。重构成车型输入插件时,输出至少应为逐信号的来源总线、DBC/车型版本、原始采样时间、年龄、有效/缺失/故障状态及标准物理单位。
常见问题
can_valid 和 bus_timeout 到底有什么区别?
can_valid 对已注册报文做活性检查,并把计数器达到失败阈值视为无效;bus_timeout 只代表总线流量空窗,任何帧(即使未注册)都会刷新 last_nonempty_nanos。所以有总线流量仍可能缺少某个必需信号。
为什么转向灯报文不参与超时失效?
因为动力总线只预注册 BLINKERS_STATE,其频率传入 NaN,在 _add_message() 中令该报文 ignore_alive=True。这只针对转向灯报文本身,并非所有 Toyota 输入都忽略超时。
动态注册的报文首轮会被解码吗?
不会。其他 cp.vl[...] 首次读取时 VLDict 才动态注册,而首次读发生在该轮 cp.update() 之后,因此该轮此前收到的报文尚未由新注册状态解码,初值零可能只是「未收到有效样本」。
can_valid 的读取会改变状态吗?
会。当前 can_valid 属性读取会更新 can_invalid_cnt,不是纯查询;而且转角偏移分支与接口汇总都会读取它。因此不能把它当成「连续五次失败后才失效」的严格计数语义。
延伸阅读
- CAN 报文解析的「健康位」在说什么:校验、计数器与总线空窗 —— 与本文
can_valid/bus_timeout语义直接对应。 - 车载信号为什么会说谎:TTL、源时间与 500 ms 新鲜度阈值 —— 解释「最近缓存无年龄检查」的风险。
- 同一个「转向灯」在三家车厂是三种实现:车辆状态归一化的坑 —— 承接 Toyota 信号到统一
CarState的映射。 - card 作为车辆网关:帧、状态与事件怎么串起来 —— 承接本文
card与车型接口的调用顺序。 - 车型参数与安全模式契约:CarParams 到固件白名单 —— 承接 TSS2/SecOC 分支与参数构建。
参考资料
- 项目 02 ——
openpilot-research/TOYOTA_CARSTATE_INPUT_HEALTH_CONTRACT_DEEP_DIVE.md(取用了总线注册与健康语义、信号到 CarState 映射、转角标定与按钮时序、消费与插件约束)。 - 项目 02 ——
openpilot-research/TOYOTA_SECOC_KEY_FRESHNESS_SAFETY_BOUNDARY_DEEP_DIVE.md(仅用于确认 SecOC 同步 MAC 与 freshness 的上游验证边界)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11
发表回复