结论:cereal 的消息契约必须拆成四层看:schema 定义、services.py 服务表配置、运行消息有效性、loggerd 落盘结果。union 分支存在不表示进程正在发布,也不表示 loggerd 会记录;logMonoTime 是消息封装时间,valid 也只表示运行有效位,不承诺车辆总线帧通过车型解析或 panda 安全检查。把「字段存在」当作「数据已发布或已记录」是这份契约最常见的误读。
四层契约各管一段
schema 层,Event 有 logMonoTime、valid 与 union,carState、carControl、carParams 指向 opendbc 的 car.capnp,customReserved* 保留固定 field ID。服务表层,SERVICE_LIST 声明服务名、期望频率、should_log、qlog decimation 和队列容量,build_header() 生成对应的 C++ 表——频率是配置与健康检查依据,不等于真实发布速率。
消息构建层,new_message() 默认 valid=False,把 logMonoTime 设为单调时钟纳秒并初始化主题,发布者通常再赋有效位。日志订阅层,loggerd_thread() 订阅 should_log 服务、非直播 EncodeData 和可选原始音频;普通消息按配置写 rlog,按计数抽样写 qlog。因此收到消息、valid=True、内容可信和时戳新鲜是四个不同判断。
| 层 | 源码与含义 | 不能推出的结论 |
|---|---|---|
| schema | Event 有 logMonoTime/valid/union;车型消息指向 car.capnp |
union 分支存在不表示进程正在发布或 loggerd 会记录 |
| 服务表 | SERVICE_LIST 声明频率、should_log、decimation、队列容量 |
频率是配置依据,不等于真实发布速率;should_log=False 也可能有专门编码路径 |
| 消息构建 | new_message() 默认 valid=False,设置单调时间 |
收到、有效、可信、时戳新鲜是不同判断 |
| 日志订阅 | loggerd_thread() 按 should_log 与计数抽样写盘 |
qlog 不是每个主题的完整回放数据 |
关键主题与字段语义
CAN 接入侧,Event 的 can 是从车接收帧,sendcan 是主机候选发送帧;CarState.canValid/canTimeout/canErrorCounter 表示车型解析健康,不能只取上次解码值。services.py 为 can 设大队列与 qlog 高抽样率,因此完整 CAN 分析应使用 rlog。执行决策侧,enabled、latActive、longActive 不等价,Actuators 的扭矩/转角/曲率属互斥横向命令语义,纵向 accel 为 m/s²。
模型到规划侧,modelV2 的 qlog 抽样未配置,不应拿 qlog 复原所有推理帧;LateralManeuverPlan 是调试覆盖曲率,不是一般模型输出。使能与监督侧,enabled 与 active 分开,警报文本/声音、人机监督策略与注意力状态在独立消息中。摄像头与编码侧,帧标识、曝光时间戳、编码索引/时间戳和视频字节是不同层,图像主数据经 VisionIPC,EncodeData 由 loggerd 分离写媒体文件。
| 链路 | 载荷定义 | 核心字段与边界 |
|---|---|---|
| CAN 接入 | Event.can/sendcan、CarState |
canValid/canTimeout/canErrorCounter 表示解析健康 |
| 执行决策 | CarControl、CarParams |
enabled/latActive/longActive 不等价;safetyConfigs/dashcamOnly/passive 决定执行边界 |
| 模型到规划 | ModelDataV2、LongitudinalPlan、LateralManeuverPlan |
模型含帧 ID、EOF 时间、耗时、轨迹;modelV2 qlog 抽样未配置 |
| 使能与监督 | SelfdriveState、DriverMonitoringState |
enabled 与 active 分开;监督策略独立消息 |
| panda 安全状态 | PandaState |
controlsAllowed、模式/参数、RX 无效、TX 阻断、心跳丢失分列 |
| 摄像头与编码 | FrameData、EncodeIndex、EncodeData |
帧标识、时间戳与视频字节分层;EncodeData 分离写媒体文件 |
需要单独记住:Event 的 logMonoTime 是消息封装时间;相机 timestampEof、模型 timestampEof、GNSS Unix 时间和 IMU 自有时间字段并不自动相等。传感器/定位插件必须显式声明时钟域、单位、采样时点和迟到处理。
Route 与 Segment 文件如何落盘
元数据由 logger_build_init_data() 记录版本、设备、内核、Git 信息、参数和部分硬件日志,参数值只有不带 DONT_LOG 标志才写入。命名/开段阶段,路由名由递增计数与随机后缀组成,段目录为 <route>--<part>;开段创建 rlog.lock、rlog.zst、qlog.zst,写 initData 与 START sentinel,结束段/路由写 END sentinel 并移除锁。
压缩阶段,rlog.zst、qlog.zst 是 zstd 压缩的连续 Cap’n Proto Event 字节流,qlog 只在抽样命中时附写。切段时,rotate_if_needed() 与 handle_encoder_msg() 等已出现的编码器进入新段后切段,相机/编码器异常时按时间回退切段;新段编码数据须等关键帧,先于关键帧的帧被丢弃。媒体文件按相机表写 fcamera.hevc、ecamera.hevc、可选 dcamera.hevc 与 qcamera.ts;RecordAudio 打开时 rawAudioData 还会写入 rlog(decimation=None,不进 qlog),这涉及额外的数据保留与隐私审查。
抽样率是理解落盘差异的关键:can 的 qlog 抽样率为 2053、sendcan 为 139、carState 为 10、modelV2 为 None。编码索引虽通常 should_log=False,但在 write_encode_data() 中专门转写且始终进 qlog。不要用 qlog 作为控制/安全故障分析的唯一依据。
对插件化与硬件的最低要求
- 插件 schema 需要版本、字段号与兼容策略;Cap’n Proto union 的固定编号不能任意复用,
customReserved*约束也不能未经全链路兼容评估就改控制主契约。 - 发布权限应按主题分级:观测只读、规划候选、
carControl和sendcan分开授权;valid、新鲜度、总线校验与硬件许可各自独立。 - 存储插件需保留元数据、段边界、单调时钟、媒体索引、丢帧及部分文件状态;为取证保留
rlog,不可用 qlog 抽样代替。
常见问题
消息字段存在,是否说明该数据一定被记录?
不代表。四层契约是分开的:schema 里 union 分支存在,不表示受管进程正在发布,也不表示 loggerd 会记录;服务表里的频率是配置与健康检查依据,不等于真实发布速率;只有 loggerd_thread() 按 should_log 与抽样配置实际写盘的内容才在日志里。
为什么不能用 qlog 复原所有推理帧?
因为 modelV2 的 qlog 抽样配置为 None,carState 抽样率为 10,can 为 2053,各主题抽样并不一致,qlog 只在抽样命中时附写。源文档明确 qlog 不是每个主题的完整回放数据,控制/安全故障分析不要以它作为唯一依据。
Event 的 logMonoTime 就是传感器采样时间吗?
不是。logMonoTime 是消息封装时间;相机 timestampEof、模型 timestampEof、GNSS Unix 时间和 IMU 自有时间字段并不自动相等。传感器/定位插件必须显式声明时钟域、单位、采样时点和迟到处理。
valid=True 是否表示这一帧数据可信?
不等于。valid 只是运行有效位,源文档明确它「不承诺车辆总线帧通过车型解析或 panda 安全检查」。车端数据是否可信还要看 CarState 的解析健康字段、时间戳新鲜度以及 PandaState 中的许可与故障分列。
延伸阅读
- CAN 报文解析的「健康位」在说什么:校验、计数器与总线空窗 —— 与本文
canValid/canTimeout/canErrorCounter字段直接衔接。 - 路由与段的身份切片 —— 承接本文 Route/Segment 命名、sentinel 与切段逻辑。
- 日志来源可用性缓存 —— 说明订阅可用性与落盘结果如何区分。
- 从使能到车轮:执行链上的八道门,以及它们各自不保证什么 —— 解释
sendcan之后为何仍由固件独立许可。
参考资料
- 项目 02 ——
openpilot-research/MESSAGE_LOG_CONTRACTS_DEEP_DIVE.md(取用了四层契约、关键主题字段语义、Route/Segment 落盘流程与 qlog 抽样率)。 - 项目 02 ——
openpilot-research/LOGGERD_SERVICE_SAMPLING_POLL_CONTRACT_DEEP_DIVE.md(仅用于确认loggerd逐服务订阅与计数抽样相位的边界)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11
发表回复