Rerun 0.35 版本解析:命令面板、内置 Catalog、HDF5 与 MCAP 流式处理全升级
2026/9/16 1:30:13 网站建设 项目流程

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实体可用于用户自定义的属性层。

测试验证了属性映射的细节,例如根属性descriptionversion,以及/observations上的frequency: 30.0joints: [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_columnignore_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

实验性ParquetReaderindex_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 的主要收获可以归纳为三条主线:

  1. 交互层:命令面板支持搜索实体与组件、实验性内置 Catalog 让本机大 rrd 文件可以低门槛流式浏览、内置 URL 富展示提升数据链接的可读性;
  2. 导入层Hdf5Reader以 group/entity、dataset/component 的直观映射接入 HDF5 生态,Mp4Reader借助 FFmpeg 大幅扩展视频兼容性,MCAP 转换支持时间窗口与损坏文件恢复,为大规模机器人数据(如 LeRobot 风格的数据集)提供了可扩展的处理路径;
  3. 时间轴语义: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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询