cereal 消息契约:schema、服务表、valid 与落盘各管什么

作者:

在

结论: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 作为控制/安全故障分析的唯一依据。

对插件化与硬件的最低要求

  1. 插件 schema 需要版本、字段号与兼容策略;Cap’n Proto union 的固定编号不能任意复用,customReserved* 约束也不能未经全链路兼容评估就改控制主契约。
  2. 发布权限应按主题分级:观测只读、规划候选、carControl 和 sendcan 分开授权;valid、新鲜度、总线校验与硬件许可各自独立。
  3. 存储插件需保留元数据、段边界、单调时钟、媒体索引、丢帧及部分文件状态;为取证保留 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 中的许可与故障分列。

延伸阅读

参考资料

  • 项目 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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注