机器人团队常说“包录好了”,但这句话离“可以拿来复现实验”还差几道检查:相机话题是否真的有消息,雷达是否在中途停了十秒,时间戳是否回退,数据文件是否完整。Backplane Robotics 在 10 月 14 日发布 Tracecheck v0.2.0,把这些问题组织成一份 JSON 录制合同,再对 MCAP 文件生成机器可读和可读的检查报告。在数据入库前,它检查结构、计数、时间和校验和;回放、标定与安全测试仍须另做。[1][2]
先分清容器、消息和实际传感质量
MCAP 是承载带时间戳消息的容器,而非某一种传感器数据格式。规范规定文件首尾魔数、Header、Data、可选的 Summary 与 Summary Offset、Footer;消息通过 Channel 指向 Schema,log_time 与 publish_time 是容器字段。sequence 可以由发布者或录制器赋值,也允许在无意义时填零。数据区的 Message 既可直接出现,也可封装在 Chunk 内;可选 Summary 支持快速清点,但不能据此推断每条消息的实际时间行为。[3]
Tracecheck 的合同可以要求某话题存在、编码或 schema 匹配、最小消息数、平均频率、最大相邻时间间隔、录制顺序下的时间回退、序号连续性及指定时间窗覆盖。检查的是外壳:项目说明明确不解码、不执行消息负载。于是,/camera/image 有 30 Hz 不等于画面清晰,Schema 名字吻合不等于字节内容有正确的曝光和标定;CRC 正确也只表明被覆盖的字节没有在写入后意外改变,不能证明数据采集时就正确。[2][4]
v0.2.0 的读取与扫描方式
v0.2.0 的明显变化不只是项目从 Recording Health Checker 改名、Python 包改为 tracecheck、发行名改为 backplane-tracecheck。新的有界流式读取器在完整扫描中单遍计算 SHA-256 和存在的 CRC,取消旧版 64 MiB 的CLI 检查文件上限;zstd、lz4 压缩块解出后的长度严格不能超过块声明的未压缩大小。独立的本地 serve 上传界面仍有 64 MiB 限制,不能把“CLI 无文件大小上限”误写为所有入口无上限。浏览器版在 Web Worker 中分片读取本地文件,项目称文件不上传,并提供与 Python 版共享预期结果的测试。[1][2]
流式扫描仍有内存开销。合同文档列出默认单条记录、未压缩块及 Summary 各 256 MiB,排序间隔检查最多追踪 2000 万条时间戳,Schema/Channel/Metadata 记录也各有数量限制。遇到超限时应把 C01 失败和扫描未完成视为没有得出后续合格结论,而不是调大阈值就自动放行。大文件上先测磁盘吞吐、内存峰值和超时,再按机器预算设置 --max-chunk-mib、--max-record-mib、--max-tracked-messages、--timeout。这些限制防止无界分配,但不能等同于对任意恶意文件完成安全审计。[1][4]
--fast 只查 Header、Footer、Summary 中的统计、Channel、Schema 和可索引的 Metadata,并核验 Summary CRC;C06—C10 需要逐条消息时间戳,会跳过。缺少可用 Summary 或 Statistics 时会回退完整扫描,报告用 scan_mode、fast_mode_fallback 表示走了哪条路径;快速模式的源文件 SHA-256 为 null。因此把快速模式用于批量初筛可以,把其 PASS 当成无掉帧证明则不行。若门禁关心时间间隙,一定要求完整扫描且检查 SKIPPED。[1][2][4]
CRC 的边界:有校验、没校验、没覆盖
MCAP 的 Chunk CRC 针对未压缩记录,Data End 的 CRC 覆盖此前数据区相关字节,Footer 的 Summary CRC 校验摘要段;字段为零意味着该处不提供 CRC。Tracecheck v0.2.0 核验数据区、Chunk 和 Summary 中已存在的 CRC,但合同注明不校验 Attachment CRC,附件与未知记录虽计入哈希仍被跳过。C01 现在只在数据区 CRC 缺失、且某些消息又没有 Chunk CRC 等其他覆盖时提示缺失:默认 ROS 2 文件有 Chunk CRC、无 Data End CRC,也可以通过。missing_crc: "ignore" 或 --ignore-missing-crc 仅抑制缺失提示,损坏的现有 CRC 仍失败。[1][3][4]
报告中的 checksum_coverage 用来说明哪些字节实际获得校验覆盖。对未压缩区外、附件内容和缺失校验的范围,不要偷换为已经逐项校验。文件 SHA-256 可用于归档时比对完全相同的字节,但也没有来源认证能力;真正需要防篡改,应在可信存储链路上管理签名、访问权限及采集设备身份,而非要求这个检查器代劳。
从两条话题写起的录制合同
先从每批录制都应该出现的话题入手,不要直接复制演示值。下例的时间阈值仅供团队与采集协议核对;只有确认日志时间使用同一可解释时钟,才把 clock_confirmed 设为 true:
1 | { |
合同采用 UTF-8 JSON,最大 64 KiB;键名精确匹配且不接受未知键和重复键。每个话题的多条 Channel 分别应用数量等限制,不会自动合并为一个发布者。平均频率按排序后的首末时间计算 (N−1)/(last−first),不是滑动窗口频率;max_gap_ns 不覆盖录制开始前与结束后的空档。需要检查完整运行时长,要另设 interval_ns 和边界容忍值。publish_time == log_time 可能只是没有发布时刻,不意味着传输零延迟;ROS 消息头内的 stamp 也不在这些检查范围。[4]
实际操作可用 tracecheck validate-contract contract.json 先校验合同,再运行 tracecheck check run.mcap --contract contract.json --out reports/run-001;--out 必须指向新目录,防止覆盖既有报告。完整扫描报告应连同录制文件的哈希、合同规范化哈希、工具版本、文件来源和运行批次保存。默认退出码 1 包含失败、警告或扫描不完整;如果团队明知警告不阻塞,可显式用 --fail-on fail,但 CI 仍应保存并复查警告。输入配置错误或操作错误为退出码 2,且无报告;不能把“没有生成报告”判为通过。[2][4]
如何解释一份看似矛盾的报告
假设一批底盘录制有 /scan、/odom 和 /camera/image:快速模式给出三个话题都有足够消息,不代表相机没有连续五秒断流。完整扫描的平均速率也可能被断流前后高频消息“拉平”,所以要同时看最大相邻间隔和预期录制区间的两端覆盖。若日志时钟在仿真重启时从较大值回到零,排序后计算的间隔可能仍然平滑,只有按物理记录顺序检查回退才会提示异常。反过来,有些采集流程本来会重置时钟或把多个子任务拼到一份文件,这时应先拆分录制、明确每段时钟域,再决定是否设回退规则,而不是一见 FAIL 就删除数据。[4]
另一个容易误解的场景是同一话题有两条 Channel:一条有大量消息,另一条登记了 Channel 却为零。按合同参考,每条匹配 Channel 独立检查计数;总话题“存在”与个别 Channel 不满足条件并不冲突。Schema 名称、编码和字节指纹也各有作用:名称适合人为识别,指纹适合发现确切的 schema 字节变化,但注释或空白变化也可能改变指纹;发生变化后应人工比较消息定义、录制软件版本和兼容性,而不是简单把新指纹加进白名单。检查报告给出的偏移是复核入口,并不能自动告诉你哪一个传感器零件失效。[2][4]
文件层也可能直接阻断检查:截断的尾部可能让 Footer 或最后的魔数缺失,错误的声明长度可能使解析器申请过大空间,未知压缩算法也可能根本无法解出 Chunk。受限解析器应在这些条件下中止并明确说明原因,而不是“尽可能读出前面的数据”之后照样给整体 PASS。如果业务确实希望保留部分可恢复消息,应由单独的恢复流程产出新文件、标注缺失区间,随后对新文件重新跑质量合同;原始残损证据仍应留存。SHA-256 的作用在此是保证后续复核针对同一份字节序列,不能恢复缺失消息。[1][3][4]
给工程团队的一张检查单
- 数据接收:确认文件来源、大小、采集设备与录制时段,保留只读原件;为保密录制决定是否允许浏览器环境处理,项目“本地处理”声明不替代组织的浏览器安全审核。
- 合同评审:明确各话题的精确名称、Schema 字节指纹、时钟来源、允许的丢帧窗口及序号是否由单一来源递增。跳过无法证明前提的时间与序号规则,不要伪造精度。
- 两级运行:快速模式供库存初筛;完整模式检查时间与覆盖。要求报告记录实际扫描模式、回退与所有
SKIPPED;C01 扫描失败时不放行 C02—C10。 - 异常复核:按报告字节偏移定位可疑记录,与播放器回放、传感器日志、同步/标定记录及场景标签交叉核对。针对未覆盖 CRC 的消息、Attachment 和未解码负载另做检查。
- 回归测试:使用项目
examples/expected.json的合成样例作为 Python/浏览器双实现的黄金结果;引入自己的无 Summary、无 CRC、截断、恶意长度、压缩炸弹、时钟跳变、掉线和重复 Channel 样本。改变规则时人工审阅 golden diff,不要把“测试通过”误读为真实车队全部传感数据被验证。[1][2]
上线前可先做一轮有答案的盲测:准备干净包、故意删除一段消息的包、保留消息但换错 schema 的包、截断包、CRC 被篡改包,以及不带 CRC 却格式合法的包。让值班人员只看报告判定是否接收,再与预先设定的期望比较。这个演练会暴露合同缺少时间窗、把 WARN 错当 PASS、把 fast 模式误作完整扫描等流程性漏洞。新批次仍要抽样人工回放,因为合成 golden tests 证明实现对已知样本稳定,不等于覆盖所有编解码器、作业时钟和现场噪声。
把这套门禁接到训练数据管线时,建议定义三个结果层级:文件可读且扫描完整、合同条件满足、语义质量可用。第一层看 CRC 和解析完成度;第二层看话题、时间与计数;第三层必须结合样帧审阅、标定、运动状态、场景难度与标注质量。每个层级由不同团队签字,避免把一次自动化检查的绿灯层层转述成“已经安全可训练”。合同也应随采集设备和固件升级而版本化:在受控样本中增加新要求,先对旧数据做影子运行、审查误报和漏报,再切到阻断模式。对历史文件做重扫时保留旧合同和旧报告,不应悄悄覆盖;如果调整阈值是为了绕过某一批失败,应另附偏差说明、业务后果和审批人。抽样回放与现场日志仍是发现合同未覆盖故障的主要补充。
本文依据发布说明、仓库说明、合同参考与 MCAP 规范;未在目标车队文件上运行 CLI、浏览器或压测,也未独立验证网页的网络隔离与全部安全边界。Tracecheck 报告用于定位合同失败项。是否可用于训练或事故分析,还要看回放与标定、跨传感器对时、内容质量、场景覆盖和安全评估。
资料来源
[1] Backplane Tracecheck v0.2.0 发布说明(标注 2026-10-14):https://github.com/backplane-robotics/backplane-tracecheck/releases/tag/v0.2.0
[2] 项目 README、使用方式及测试说明:https://github.com/backplane-robotics/backplane-tracecheck/tree/v0.2.0
[3] MCAP 格式规范,File Structure、Message、Chunk、Data End、Footer:https://mcap.dev/spec
[4] v0.2.0 合同参考,扫描、校验和与限制:https://github.com/backplane-robotics/backplane-tracecheck/blob/v0.2.0/docs/CONTRACT_REFERENCE.md