Skip to main content

概述

本篇实践介绍如何使用 TopicRecorder 将订阅的数据流保存为 MCAP 文件。应用场景包括记录实验数据、回看采集过程和准备离线分析数据。 对应的 Python 示例为 2.recording.py。 录制接口见 TopicRecorder 接口清单。
C SDK 没有对应的录制接口,本页介绍 Python 用法。

前置条件

硬件

本示例只读取,不写任何设备参数。

软件

前序步骤

先看懂数据订阅:回调。录制的输入就是 subscribe() 返回的订阅句柄,队列语义完全一致。

数据流

文件结构实测

录 6 条设备流加 2 条全局流、5 秒,产出文件的通道如下: 消息编码是 json,每条通道自带一份 schema。用 Foxglove Studio 打开能直接看到字段名,不需要额外的消息定义文件。 文件头的 library 字段实测为 mcap-rs-0.24.0,写入器是 SDK 内置的 Rust 实现。

压缩模式实测

同样录 3 条流、5 秒、约 1970 帧: JSON 编码的重复字段名压缩率很高。长时间录制默认选 zstd,对写入延迟敏感的场合选 lz4,需要边录边被别的进程流式读取时才用 none。 单独看 lz4 的一个 chunk,实测 3101 字节原始数据压到 938 字节。

质量指标实测

handle.stop() 返回的 summary 带一个 quality 对象:
完整字段与实测取值: 三处值得注意: sync_rate 在混入 tf 后掉到 0.857。 六条设备流都在 130 Hz 附近,彼此对得齐。tf 实测 872 Hz、tf_static 只有 1 Hz,与其他通道的节奏差一个量级,同步判定自然失败。录制里同时放不同频段的流,这个数字偏低是预期行为,不代表数据有问题。 max_sync_offset_ms 可能出现一个很大的孤立值。 3 条流那轮实测到 2966 ms,同一轮的 avg 只有 7.89 ms。这是录制刚启动、各通道首帧尚未对齐造成的。判断录制质量看 avg 和 frame_drop_rate,不要被 max 的启动毛刺带偏。 duration_s 是挂钟时长,不是有效录制时长。 用了暂停就会对不上,见下一节。

暂停与恢复

handle 除了 stop() 还有 pause() 和 resume(),示例没有展示。实测录 2 秒、暂停 2 秒、再录 2 秒,3 条流: 帧数对应的是 4 秒有效录制,暂停期间一帧不写。duration_s 仍然按挂钟走,所以拿 total_frames / duration_s 反推输出率会偏低。 暂停恢复这轮 spc_alert_count 变成 1。暂停期间通道静默,统计过程控制把它识别成一次异常。这是预期的,不是故障。 handle 还提供 subscribe_alerts()、subscribe_metrics()、subscribe_status() 三个订阅接口,可以在录制过程中实时拿到告警、质量指标和状态,不用等到 stop()。

集成步骤

完整示例见 Python 示例。以下片段按接入顺序展示关键操作,参数解析、信号处理和完整错误分支见示例。

1. 连接目标手套

将 serial_number 替换为目标手套的序列号。连接成功后,后续步骤复用同一个设备句柄。C 片段需包含 wuji_sdk.h。

2. 登记录制通道

创建录制器,再把需要保存的订阅登记进去。以下操作放在异步函数中,设备连接在外层 finally 中断开。

3. 启动录制

先创建输出目录,再启动录制。保留返回的句柄,用它停止写入并取得录制摘要。

4. 等待文件写完再断开设备

停止录制会完成文件写入。沿用 Python 示例 的取消保护,确保任务取消时仍等待 stop() 完成,然后在外层清理设备。

运行与输出

以上为实机运行结果,设备是右手 Wuji Glove,手套静置无人佩戴,录 3 条流 10 秒,lz4 压缩。3939 帧分摊到 3 条通道各约 1313 帧,等效每条 131 Hz。

注意事项

示例里这段是有意为之:
asyncio.shield 让 stop() 不被外层取消打断。少了这层保护,Ctrl+C 可能在 MCAP 写完索引之前就把任务砍掉,文件读不出摘要。

读取录好的文件

装了 mcap 命令行工具直接看:
用 Python 逐帧解析:
消息体是 JSON,直接 json.loads(message.data) 就能拿到与在线订阅一致的字段结构。

扩展用法

按需登记通道,别全开

八条流全录、zstd 压缩,实测 5 秒 6.01 MB,折算每分钟约 72 MB。tf 一条就占了 4361 条消息,比六条设备流加起来还多。录长时间数据前先想清楚哪些流真的要。

降低输出率再录

订阅句柄支持降频。把 130 Hz 降到 30 Hz,文件体积直接掉到四分之一以下,见输出率调节。

录制期间监控质量

不想等 stop() 才知道是否丢帧,用 handle.subscribe_metrics() 在线拿指标,handle.subscribe_alerts() 拿告警。长时间无人值守的采集应该接上这两个。

相关内容