Rerun 0.35 版本解析:命令面板、内置 Catalog、HDF5 与 MCAP 流式处理全升级
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
本文以 Rerun 0.35 版本的官方发布说明(changeset-0-35.md)为核心骨架,深入解析该版本在 Viewer 交互、内置 Catalog、数据导入管线(HDF5 / MP4 / MCAP)以及 ROS 2 时间轴处理上的关键更新,并结合仓库源码验证底层实现,帮助读者理解每个新特性的使用方式、适用场景与破坏性变更的迁移路径。
一、0.35 版本概览
Rerun 0.35 是一个以「更流畅的数据接入与消费」为主题的版本:一方面强化 Viewer 的交互体验(改进的命令面板、实验性内置 Catalog、更智能的 URL 展示),另一方面大幅升级了数据导入管线——新增 HDF5 读取器、增强 MP4 视频解码、支持时间窗口与损坏文件的 MCAP 转换,并改善了 ROS 2 消息的时间戳处理。
该版本发布说明来自 docs/content/changelog/changeset-0-35.md,其结构为 Highlights(新特性)与 Breaking changes(破坏性变更)两大块,本文沿此脉络展开。
二、Viewer 交互升级
1. 改进的命令面板(Command Palette)
Viewer 的命令面板(Cmd+K/Ctrl+K)现在支持搜索并选中实体(entities)与组件(components)。这意味着你可以在不看数据面板的情况下,通过快捷键直接跳转到感兴趣的实体或组件。
此外,命令面板还增加了上下文相关的命令,例如刷新当前选中的 catalog 或 dataset。这类命令会根据当前上下文动态出现,进一步减少鼠标操作。
2. 实验性 Viewer 内置 Catalog
Viewer 现在内置了一个实验性的 catalog 功能,用于在没有启动独立 catalog 服务的情况下直接操作本地录制文件。目前它需要先在设置菜单中手动激活(因为仍有一些粗糙的边缘场景)。
内置 catalog 的核心价值在于:
- 轻松流式读取任意大小的 rrd 文件——不再需要先把整个文件加载进内存;
- 实现了完整的 OSS redap server 协议,因此可以通过 Python SDK 直接连接;
- 出于安全考虑,仅允许来自本机的连接。
从仓库结构看,redap 协议相关的客户端实现位于 crates/store/re_redap_client,Python 侧的 catalog 查询逻辑可参考 rerun_py/src/catalog(如 index_columns.rs、schema.rs)。官方将这一改动定位为「让 Viewer 在消费实时数据与服务端数据时更简洁、更显式」的第一步。
3. 内置 URL 类型的富展示
Rerun 现在能识别已知的链接格式(指向 rrd 文件、hub 数据集等),并将其显示为紧凑的链接按钮,而不再是一段普通文本链接。同时,Rerun Hub 数据集的打开按钮也被重新设计,交互更直观。
三、数据导入管线:HDF5 读取器(Hdf5Reader)
1. 快速上手
0.35 版本引入了实验性的Hdf5Reader,用于将 HDF5 文件读取为惰性(lazy)chunk 流。每个 HDF5 group 对应一个 Rerun entity,每个 dataset 对应一个 component:
from rerun.experimental import Hdf5Reader, IndexColumn reader = Hdf5Reader("episode.h5") store = reader.stream(index_column=IndexColumn.timestamp("/time", input_unit="s")).collect()2. 核心设计:group → entity,dataset → component
从 Python 侧的 _hdf5_reader.py 源码可以看出:
- 每个 HDF5 group 映射为一个 Rerun entity;文件根目录映射为实体
/,嵌套 group 映射为嵌套实体路径(如/observations/images对应实体/observations/images); - group 的叶子 datasets 成为该实体的列;
stream()是唯一的数据加载入口,所有加载选项都挂在它上面,因此同一个 reader 可以对同一文件多次stream()出不同配置的流。
3. 数据集维度到 Arrow 列的映射规则
stream()按维度加载数据集(详见stream()的 docstring):
| HDF5 数据集维度 | 生成的列 |
|---|---|
| 0-D(标量) | 静态(static)数据,单个值,无时间轴 |
1-D[N] | 含 N 个标量行的列 |
2-D[N, K] | N 行、每行是 K 个元素的定长列表(FixedSizeList<K>) |
3-D 及以上[N, d1, …, dk] | N 行、每行是一个匹配类型的 blob(ArrowList<PRIMITIVE_TYPE>),按行主序保存原始值 |
一维及更高维数据集的第一个维度(leading dimension)始终是行轴。元素类型映射为对应的 Arrow 等价类型(有符号/无符号整数、浮点、字符串),不施加任何语义解释。
测试文件 test_hdf5_reader.py 用固定 fixture 验证了这些规则,例如:
- 2-D
[5, 3]数据集映射为pa.list_(pa.float64(), 3); - 4-D
[5, 2, 2, 3]的图像数据每行是一个 12 元素的按行主序 blob; - 0-D 数据集(如
/meta/count)生成静态 chunk。
4. HDF5 属性(attributes)的处理
HDF5 attributes 会在专门的__hdf5_properties实体下以静态 chunk形式发出,保持与源文件布局一致:根属性落在__hdf5_properties,对象/a/b上的属性落在__hdf5_properties/a/b。每个属性成为一个以它命名的静态组件。这样设计是为了保持通用的__properties实体可用于用户自定义的属性层。
测试验证了属性映射的细节,例如根属性description、version,以及/observations上的frequency: 30.0与joints: [1.0, 2.0, 3.0](float64[3] 属性映射为定长列表)。
5. 行对齐(Row alignment)规则
所有加载的、未忽略的、非标量的数据集按位置对齐到文件级时间轴,因此必须共享相同的行数(标量数据集是静态的,不受此约束):
- 提供了
index_column时,共享行数即为该索引数据集的长度; - 未提供时,所有数据集必须协商出统一行数,该行数成为生成的
row_index时间轴的长度。
违反对齐的数据集会直接报错,除非被列入ignore_datasets;不会自动丢弃任何数据来满足对齐。测试中的test_data_misaligned.h5fixture 正是用来验证「不齐则报 ValueError,显式忽略后恢复」的行为。
6. stream() 完整参数
stream()的全部参数(均只接受关键字传参):
root_group:当作文件根处理的 group(默认整个文件)。只有其子树会被加载与对齐,它自己的属性作为根属性,其他路径(index_column、ignore_datasets、生成的实体路径)都相对它解释;root_group上方的属性不会被发出,需用attributes()读取。entity_path_prefix:给每个实体路径加的前缀(如"/world")。index_column:作为文件级时间轴索引的数据集,用IndexColumn构造,如IndexColumn.timestamp("/time", input_unit="s")或IndexColumn.sequence("/frame_id"),相对root_group解释;引用的数据集必须是一维的,省略时生成全文件统一的row_index序列时间轴(0, 1, …)。ignore_datasets:要整体排除的数据集或 group 路径列表(group 路径会排除整个子树),相对root_group解释;被忽略的数据集既不加载也不参与行对齐。use_structs:为True(默认)时,一个实体的所有列被打包进单个 ArrowStruct组件(每个 dataset 一个字段,以 dataset 命名);为False时每个 dataset 成为同实体上的独立组件。只有一个数据集的 group 始终以裸组件形式发出,绝不包装成单字段 struct。
7. 元数据访问器
除stream()外,Hdf5Reader还提供三个轻量元数据接口(只读元数据,不读取数据集值):
groups(path="/"):递归列出指定路径下的 group 路径;datasets(path="/"):递归列出数据集及其 shape 与 dtype,返回DatasetInfo(path, shape, dtype)结构(DatasetInfo 定义于同一模块);attributes(path="/"):以类型化 Python dict 读取对象属性,标量属性返回 Python 标量,数组属性返回列表。
8. 底层实现:惰性流与后台线程
从 Rust 侧绑定 hdf5_reader.rs 可以看到实现机制:
Hdf5StreamFactory通过re_hdf5::load_hdf5在独立后台线程(线程名hdf5-chunk-source)中解码,解码结果通过有界 crossbeam channel(容量由CHUNK_CHANNEL_CAPACITY决定)以配额感知方式(re_quota_channel::send_crossbeam)传递给消费端,实现真正的惰性流式读取;stream()会先调用re_hdf5::validate_layout急切校验布局(仅元数据),因此错误的配置(行不对齐、index_column不存在、root_group不存在或不是 group、文件存在但无法解析为 HDF5)都会在stream()调用处立刻以ValueError暴露,而不是在迭代中途才失败;- 时间单位支持
ns/us/ms/s,索引类型支持timestamp/duration/sequence,与 Python 侧IndexColumn的类型安全构造函数一一对应。
9. IndexColumn:统一的索引列描述
IndexColumn(定义于 _index_column.py)是实验性读取器共享的、类型化的时间轴索引描述:
IndexColumn.timestamp("/time", input_unit="s") # 时间戳时间轴,input_unit 描述原始值 IndexColumn.duration("/elapsed", input_unit="us") # 经过时间时间轴 IndexColumn.sequence("/frame_id") # 序数整数索引,无单位关键点:input_unit描述的是原始值代表什么单位(而非期望的输出单位),内部会统一换算为纳秒;时间轴种类由你选择的构造函数决定,因此不存在拼错字符串的问题。
四、数据导入管线:MP4 视频读取器增强
0.35 显著增强了Mp4Reader(Rust 与 Python 双端),核心能力是通过 FFmpeg 对视频进行管线化处理:
- 移除不支持的 B 帧(B-frames);
- 转码到不同的输出格式;
- 调整 GOP 大小;
- 利用部分 GPU 加速编解码器。
此外还改善了不支持编解码器的报错提示(更清晰),并修复了处理大 MP4 偏移量时的崩溃问题。
该功能仍处于实验阶段,官方明确表示「仍在迭代如何让 mp4 → RRD 的流程尽可能无缝」,并欢迎反馈。Python 侧封装见 _mp4_reader.py,集成测试见 test_mp4_reader.py。
五、时间窗口化与损坏 MCAP 转换
1. 按时间范围读取 MCAP
0.35 支持从源 MCAP 文件中读取选定的时间范围。该选项在 Python 的McapReader和 CLI 中均可用(详见rerun mcap convert --help)。
Python 侧(chunk/_mcap_reader.py)的McapReader构造函数接受:
start_time_ns:此时间之前的消息被跳过,None表示起始端开放;end_time_ns:此时间之后的消息被跳过,None表示结束端开放;recover:是否在内存中恢复缺失或无效的 MCAP summary(默认False)。
stream()上同样可以传start_time_ns/end_time_ns,用于覆盖构造时传入的值(仅对本次扫描生效;若两者任一提供,则两者都会被重置)。
2. 有界窗口:处理超大型录制文件的利器
除了简单的时间过滤,这一能力还允许在有限窗口中转换和优化大型录制文件,而不必一次性加载整个录制。发布说明给出的实测数据:
- 在一个 20 GB 的测试录制上,分 32 个窗口处理,峰值内存从约 26 GB 降到 1.4 GB;
- 墙钟时间从 14.3 秒降到 5.8 秒。
需要说明的是:窗口间的循环需要用户在源码 MCAP 侧写少量代码(每次用不同的时间范围重新stream()即可),0.35 本身不提供自动分窗的 CLI 标志。
3. 直接读取损坏的 MCAP 文件
转换器现在可以直接读取损坏的 MCAP 文件,无需单独的恢复(recovery)流程。当McapReader或 CLI 开启recover选项时,转换器会在处理过程中按需重建缺失的 summary 和索引。
从 CLI 实现 commands/mcap/mod.rs 可以看到相关参数:
--start-time TIME:仅转换该时间范围内的数据;--end-time TIME:仅转换该时间范围内的数据;--recover:开启恢复模式。
时间范围是半开区间[start, end),且当仅提供一端时另一端自动开放(start缺省为 0,end缺省为u64::MAX)。
底层恢复逻辑由 crates/store/re_mcap/src/recover.rs 承载。附带地,rerun mcap check命令(commands/mcap/check.rs)也支持--recover,用于在 summary 缺失或无效时先从文件可读部分重建 summary,再执行结构性与时间轴检查。
六、改进的 ROS 2 时间戳处理
1. 新行为
所有带有顶层std_msgs/msg/Header的 "header" 字段、或builtin_interfaces/Time的 "stamp" 字段的 ROS 2 MCAP 消息,现在都会额外出现在ros2_timestamp时间轴上(除了标准的 MCAP log 与 publish 时间轴之外)。
2. 之前的限制
在 0.35 之前,ros2_timestamp时间轴只为被转换为 Rerun archetype 的 ROS 消息填充。现在,任何经过 schema reflection(模式反射)处理的 ROS 消息(例如自定义 ROS 消息类型)都支持该时间轴,便于用户按 header 时间戳顺序查看所有数据。
3. 源码验证
在 decoders/ros2_reflection.rs 中,add_ros2_timestamps在解析器 finalize 阶段被调用:它通过解码计划(MessageDecodePlan)读取每个消息的纳秒时间戳,并逐个加入ros2_timestamp时间轴单元格(由 util.rs 中的TimestampCell::from_nanos_ros2构造)。若某条消息没有 header 或顶层时间戳则直接跳过;若时间戳无法读取,则整条ros2_timestamp时间轴会被丢弃并给出警告(而不是产生缩短的时间轴),相关行为有单元测试覆盖(如header_stamp_becomes_the_ros2_timestamp_timeline测试)。
七、破坏性变更与迁移指南
1.StateChange.state改为数组
StateChangearchetype 的state字段现在接受一组值而非单个值。每个条目在状态时间轴视图中获得自己的一条 lane(泳道),因此一个实体可以同时跟踪多个状态(例如一个游戏手柄的多个按钮)。
注意:线上数据格式与已存储的录制文件均无变化——这只影响各语言 SDK 的 API。
Rust(迁移需注意):
// 0.34 rec.log("door", &rerun::StateChange::new().with_state("open"))?; // 0.35 rec.log("door", &rerun::StateChange::single("open"))?; // 或等价写法: rec.log("door", &rerun::StateChange::new().with_state(["open"]))?;with_state现在接受迭代器,因此传入单个字符串不再能编译。要重置单个实例的状态,请使用新的with_state_opt——其中的None条目会重置该实例对应的 lane:
rec.log("buttons", &rerun::StateChange::new().with_state_opt([Some("Idle"), None]))?;Python:无需改动。rr.StateChange(state="open")继续可用,且现在支持state=["idle", "pressed"]表示多条 lane。
C++:无需改动。rerun::StateChange().with_state("open")继续可用,且现在支持with_state({"idle", "pressed"})。
状态时间轴视图的实现位于 crates/viewer/re_view_state_timeline,其测试(tests/basic.rs)覆盖了多状态 lane 的行为。
2.ParquetReader的索引列改用IndexColumn
实验性ParquetReader的index_columns参数不再接受(name, type[, unit])元组,改为传入用timestamp/duration/sequence构造器构建的IndexColumn值(时间轴种类由所选构造器决定,unit变为仅限关键字的input_unit):
# 0.34 ParquetReader(path, index_columns=[("frame", "sequence"), ("ts", "timestamp", "ms")]) # 0.35 from rerun.experimental import IndexColumn ParquetReader(path, index_columns=[IndexColumn.sequence("frame"), IndexColumn.timestamp("ts", input_unit="ms")])这实际上是与Hdf5Reader索引描述的统一——两者共享同一套类型安全的IndexColumn语法。相关实现见 _parquet_reader.py 与 parquet_reader.rs。
3. 移除--follow
Rerun 不再支持 tailing.rrd文件(--follow已删除)。如果你之前在实时工作流中依赖它,请改为将数据 tee 到多个 sink——例如在产生数据的进程中同时记录到 viewer 与一个.rrd文件。
多 sink 的 tee 模式配置方法见官方 sink 文档页(sinks 文档 中的 multiple-sinks tee pattern 一节)。
八、小结
Rerun 0.35 的主要收获可以归纳为三条主线:
- 交互层:命令面板支持搜索实体与组件、实验性内置 Catalog 让本机大 rrd 文件可以低门槛流式浏览、内置 URL 富展示提升数据链接的可读性;
- 导入层:
Hdf5Reader以 group/entity、dataset/component 的直观映射接入 HDF5 生态,Mp4Reader借助 FFmpeg 大幅扩展视频兼容性,MCAP 转换支持时间窗口与损坏文件恢复,为大规模机器人数据(如 LeRobot 风格的数据集)提供了可扩展的处理路径; - 时间轴语义:ROS 2 消息的 header 时间戳现在对任意经过 schema reflection 的消息可见,配合状态时间轴的多 lane 支持,让时序数据的观察与编排更精细。
升级到 0.35 时,需要重点处理的三处破坏性变更集中在StateChange.state数组化(Rust 侧)、ParquetReader索引列语法统一为IndexColumn,以及--follow的移除。这些变更都不影响已存储的数据格式,迁移成本集中在 SDK 调用代码上。
如需查看更早版本的迁移说明,可参阅官方迁移文档(migration.md)。
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考