Skip to content

Ros2 bag

ros2/rosbag2 | DeepWiki

概述

rosbag2是用于记录和回放ROS 2通信的官方工具。它能够从主题、服务和动作中捕获带时间戳的消息,并将其存储为数据包文件,从而支持数据回放功能,用于测试验证、调试排障、数据分析和仿真复现。

命令 功能描述
ros2 bag convert 根据输入的数据包,使用不同设置写出新的数据包
ros2 bag info 在屏幕上打印数据包的信息
ros2 bag list 在屏幕上打印可用插件的信息
ros2 bag play 从数据包回放ROS数据
ros2 bag record 将ROS数据记录到数据包
ros2 bag reindex 为数据包重建元数据文件
录制功能
  • 主题发现:动态监测并自动识别新出现的主题
  • 过滤机制:支持通过正则表达式、排除模式或显式列表指定记录目标
  • QoS适配:自动匹配发布者的服务质量配置
  • 数据包分割:根据文件大小或持续时间自动拆分存储文件
  • 压缩功能:支持可插拔格式的消息级/文件级压缩
  • 快照模式:按需触发的环形缓冲区录制
  • 服务/动作记录:完整捕获服务调用与动作通信数据

回放功能

  • 速率控制:通过--rate参数或运行时服务调整回放速度
  • 时间控制:在/clock主题发布仿真时间戳
  • 跳转定位:支持基于时间戳的精准片段回放
  • 过滤回放:可选定特定主题/服务/动作进行回放
  • 循环模式:提供连续循环回放便于测试验证
  • 服务/动作回放:完整重放服务请求与动作目标数据

ros 2 bag

ROS 1 最关键和基本的部分之一是其持久数据记录机制,称为 rosbags。为了在记录时保持高性能,rosbags 避免了记录消息的序列化和反序列化。

袋文件的回放必须是确定的。这意味着当顺序播放袋文件 n 次时,接收端应接收到确定的序列 n 次。这可以通过在记录时正确标记每条 incoming message 的时间戳来实现。时间戳可以是两重的:第一次是实际消息离开发布者时的时间戳,第二次是消息被接收并存储在袋文件中的时间戳。

当考虑将 rosbag 文件作为长期存储时,可能会出现从录制到回放的时间段内消息定义已发生变化的情况。 为了应对这种情况,回放功能应提供一种机制将旧消息转换为新的定义。这可能仅限于新消息定义的字段添加。这意味着所有重叠的字段都应进行转移,而新添加的字段可以默认。显然,执行此转换步骤需要反序列化 ROS 2 消息,不能在高效回放序列化数据时完成。

ros 2 bag 技术要求

  1. 确定性:多次回放保证数据序列确定
  2. 适应性:消息字段添加
  3. 可扩展性
  4. 随机访问:无需遍历对某个主题的第 n 条消息的随机访问
  5. 范围访问
  6. 可变数据块大小
  7. 与 ROS 1 的向后兼容性

ros 2 bags 的设计方案

ros 2 bag 自下而上被分为 3 层:

  1. 数据包存储 api 层:与 ROS 2 解耦,仅负责读写抽象的二进制消息
  2. 数据包 api 层:负责获取 ROS 2 消息,对其进行序列化并添加充分描述信息,以供存储 API 层写入
  3. 数据包命令行接口层:为用户提供了控制数据包录制与回放的入口

image.png

存储 api 层

负责以二进制格式存储传入的 ROS 消息的底层软件包。数据存储负责持久保存 ROS 消息及其足够的元信息,以便在加载时恢复其完整上下文。

数据编码

ros 2 消息 <<=[唯一性]=>> 二进制

数据存储

抽象表示:实际消息的二进制数据块以及一个键值对元数据 支持多种数据存储解决方案(例如 SQLite 或 rosbag format2 )

该 API 能够:

  1. 支持多种数据存储;
  2. 将数据从一个存储传输到另一个存储。
Sqlite

ros 2 选择 sqlite 作为默认的解决方案。

理由:

  • 轻量级依赖,在各主流平台经过充分测试
  • 单文件即可运行,便于初期 API 开发和存储实现
  • 基准测试显示写入速度可达>1 GB/s(大消息场景下接近磁盘写入极限)
  • 高频小消息处理性能优异(>10 万条/秒)

优势:

  • 表结构无需预定义,可灵活扩展
  • 支持标准 SQL 语法和工具进行查询

劣势:

  • 与直接将传入数据转储到文件的格式(例如 ROS 1 rosbag)相比,写入性能可能存在缺陷。
可插拔数据存储

ros 2 为该 API 层实现可扩展的插件架构,该架构能够连接各种数据存储解决方案,从而使用户有机会根据自己的用例优化数据存储。

api 设计

存储 API 接口设计如下(完整 API 可能采用 C 语言接口+C++实现,便于 Python/Java 等语言绑定):

  1. open:进程初始化时调用,准备数据读写格式
cpp
BagHandle open (string file_path, void * impl_data)
  1. close:进程退出时调用
cpp
bool close (BagHandle * handle)
  1. create_topic:对于每个要记录的新主题, create topic 函数都会被调用一次。它接收连接信息、指示相应二进制数据编码的唯一标识符、数据块大小,并且可以接受一个可选的指针来存储特定于实现的数据。这里隐含的约定是每个主题只能有一种编码方式。不支持同一消息和同一主题使用混合编码。
cpp
TopicHandle create_topic (BagHandle * handle, ConnectionHeader connection_header, string encoding_id, int chunk_size, void * impl_data)

image.png

image.png

  1. open_topic:读取主题时获取句柄
cpp
TopicHandle open_topic (BagHandle * handle, string topic_name)
  1. write:持久化存储数据,通过主题句柄定位存储位置
cpp
void write (BagHandle * handle, TopicHandle * topic, struct time_received, SerializedData * serialized_data, void * impl_data)
  1. read_next:迭代器式顺序读取(可选主题过滤)
cpp
SerializedData read_next (IteratorHandle * iter, TopicHandle * topic, void * impl_data)
  1. read:索引式范围查询(支持多主题和时间范围检索,可指定排序方式)
cpp
SerializedData[] read (struct query, enum order_by, void * impl_data)
  1. info:获取存储数据的统计信息(主题列表、总时长等)
cpp
BagInfo info (BagHandle * handle)
  1. index:录制完成后创建索引文件(YAML 格式),存储元数据
cpp
void index (BagHandle * handle)
数据结构定义

连接头信息(扩展 ROS 1 头信息,增加 QoS 参数):

cpp
struct ConnectionHeader {
  string topic_name,
  string topic_type,
  string message_definition,
  string message_md 5_sum,
  struct quality_of_service_params
}

序列化数据载体:

cpp
struct SerializedData {
  byte[] payload,
  int size,
}

数据包信息(扩展 ROS 1 info,增加键值对存储):

cpp
struct BagInfo {
  string path,
  int file_size,
  time duration,
  time start,
  time end,
  int message_count,
  int topic_count,
  string[] topics,
  string[] types,
  map[string, string] key_value_data
}

主题句柄(封装编码信息):

cpp
struct TopicHandle {
  string topic_name,
  string topic_type,
  string encoding_identifier
}

rosbag API

rosbag API 描述了记录、回放以及读取和写入 ROS 消息所需的接口。它负责将传入的消息以正确的数据格式存储到数据存储中。同样,该 API 还必须能够根据数据存储中的二进制表示,恢复 ROS 消息的原始数据格式。

rosbag API 提供通用函数,支持在任意 ROS 2 消息与可用编码格式之间进行双向序列化/反序列化。默认提供 CDR 格式的插件实现,使所有中间件都能通过该函数将 CDR 数据反序列化为 ROS 2 消息,并可按需序列化为自身编码格式。这种可插拔序列化机制是实现通用 rosbag 的唯一途径,同时会带来显著性能开销。

如果给 ros2 bag record 命令指定了编码选项(例如 --encoding ),则每个传入的 ROS 2 消息在存储到 bag 之前都会被序列化为指定的编码格式。相反,如果没有指定任何选项,rosbag API 会直接以二进制格式接收传入的消息,并可以直接将其转发到存储 API,而无需进行任何进一步的序列化。

API 1

与存储层交互,提供 ROS 2 消息的读写功能及其与指定编码格式的转换。

API 2

实现 ROS 2 消息的发布/订阅传输机制。这些函数会订阅一组主题,记录传入的消息并将其写入存储 API。回放操作则相反,给定一个查询,将查询结果对应的主题发布出去。

rosbag CLI

rosbag CLI 将作为现有 ros2cli 的一个新动词集成,并为 bag 文件的简单录制和回放提供入口点。这个命令行包仅作为一个简单的接口,不包含任何重要的 API。大部分逻辑都在 rosbag API 中实现。

可选功能

  • 并行 IO
  • 压缩

包结构

bash
~/Workspace/bag_files ⌚ 14:56:53
$ ros2 bag info  rosbag2_2025_11_10-14_55_45/

Files:             rosbag2_2025_11_10-14_55_45_0.db3
Bag size:          25.0 KiB
Storage id:        sqlite3
Duration:          28.998816488s
Start:             Nov 10 2025 14:55:46.627438064 (1762757746.627438064)
End:               Nov 10 2025 14:56:15.626254552 (1762757775.626254552)
Messages:          30
Topic information: Topic: /topic | Type: base_interfaces_demo/msg/Test | Count: 30 | Serialization Format: cdr


~/Workspace/bag_files ⌚ 14:57:01
$ tree rosbag2_2025_11_10-14_55_45
rosbag2_2025_11_10-14_55_45
├── metadata.yaml
└── rosbag2_2025_11_10-14_55_45_0.db3

0 directories, 2 files

~/Workspace/bag_files ⌚ 14:57:24
$ cat rosbag2_2025_11_10-14_55_45/metadata.yaml
rosbag2_bagfile_information:
  version: 5
  storage_identifier: sqlite3
  duration:
    nanoseconds: 28998816488
  starting_time:
    nanoseconds_since_epoch: 1762757746627438064
  message_count: 30
  topics_with_message_count:
    - topic_metadata:
        name: /topic
        type: base_interfaces_demo/msg/Test
        serialization_format: cdr
        offered_qos_profiles: "- history: 3\n  depth: 0\n  reliability: 1\n  durability: 2\n  deadline:\n    sec: 9223372036\n    nsec: 854775807\n  lifespan:\n    sec: 9223372036\n    nsec: 854775807\n  liveliness: 1\n  liveliness_lease_duration:\n    sec: 9223372036\n    nsec: 854775807\n  avoid_ros_namespace_conventions: false"
      message_count: 30
  compression_format: ""
  compression_mode: ""
  relative_file_paths:
    - rosbag2_2025_11_10-14_55_45_0.db3
  files:
    - path: rosbag2_2025_11_10-14_55_45_0.db3
      starting_time:
        nanoseconds_since_epoch: 1762757746627438064
      duration:
        nanoseconds: 28998816488
      message_count: 30%

ros 2 bags 五层架构

Transport Layer | ros2/rosbag2 | DeepWiki

image.png

各层职责:

  1. user layer:命令行接口与 launch 文件集成
  2. python bindings:提供 pybind 11 生成的 python 接口
  3. transport layer:包含作为 rclcpp:: Node 组件的 player 与 recorder(Player 和 Recorder 均以 rclcpp 组件的形式实现,可以加载到组件容器中以进行进程内通信)
  4. core c++ layer:实现了存储 I/O、压缩和转换逻辑
  5. storage plugin layer:具有可插拔存储和压缩实现的抽象接口

rosbag2的核心组件: Packages and Components | ros2/rosbag2 | DeepWiki

关键类:

image.png

传输层

image.png

传输层使用 ROS 2 的通用发布和订阅机制来处理任意类型的消息。

基于服务的控制接口(rolling)

两个节点都暴露了 ROS 2 服务以进行运行时控制:

Player Services (namespace: ~/):

  • pauseresumetoggle_pausedis_paused
  • get_rateset_rate
  • seekplay_nextburst
  • playstop

Recorder Services (namespace: ~/):

  • pauseresumeis_paused
  • split_bagfile
  • snapshot (仅在启用快照模式时)

时间控制系统

rosbag2/docs/design/rosbag2_playback_time.md at humble · ros2/rosbag2 --- rosbag2/docs/design/rosbag2_playback_time.md at humble · ros2/rosbag2

image.png

rosbag 2 中的时间控制系统负责管理播放时间,从而可以精确控制录制消息的重放方式。该系统负责协调播放的时间特性,包括播放速率控制、暂停/恢复和时间跳转功能。

在回放 ros 2 bags 时,时间控制系统决定:

  • 根据时间戳确定何时发布下一条消息
  • 如何控制播放速度(比实时速度快/慢)
  • 如何实现暂停和恢复功能
  • 如何处理时间跳跃(跳过过去或回到过去)

该系统将时间管理与消息的实际发布解耦,从而在 rosbag 2 架构中实现了清晰的关注点分离。

时间控制系统维护一个参考点,该参考点建立了两个时间域之间的关系:

  1. ROS 时间 :ROS 消息中使用的时间戳域
  2. 稳定时间 :用于测量实际经过时间的现实世界时钟

image.png

该参考允许系统在这些域之间进行转换,从而使其能够根据 ROS 时间戳确定何时发布消息。

image.png

存储层

表结构

Service/Action 记录与回放 (rolling 版本)

Rosbag 2 服务记录与回放功能

rosbag2/docs/design/rosbag2_record_replay_service.md at rolling · ros2/rosbag2

背景说明

ros2/rosbag2#773 议题中,社区建议为 rosbag 2 增加记录服务请求的功能。

本文档将描述如何基于当前架构实现该功能,并扩展现有命令行参数。

服务消息记录原理

服务内省机制 (ros2/ros2#1285) 已实现。所有服务消息(请求与响应)都会发布到名为 _service_event 的隐藏主题下(例如 /add_two_ints/_service_event)。因此可以通过记录普通主题的方式捕获这些消息。

cpp
service->configure_introspection(
  node->get_clock(),
  rclcpp::ServicesQoS(),
  RCL_SERVICE_INTROSPECTION_CONTENTS);

服务事件主题识别方法

服务事件主题虽以普通主题形式存储,但在读取录制文件后需要区别处理。识别标准如下:

- 普通主题  
  [命名空间/]主题名

- 隐藏主题  
  [命名空间/]_主题名

- 服务事件主题  
  [命名空间/]服务名/_service_event

具体判定标准:

  1. 主题以 /_service_event 结尾
  2. 主题类型名称匹配 */srv/*_Event 模式(例如 example_interfaces/srv/AddTwoInts_Event

新增/修改命令

新增命令:ros2 service echo

ros 2 bag record​ 更新列表:

参数 类型 功能描述
--services 新增 指定要记录的服务列表(至少一个服务名)
--all-topics 新增 记录所有普通主题(自动排除隐藏主题,含服务事件主题)
--all-services 新增 记录所有服务事件主题
--exclude-regex 修改 通过正则表达式排除主题和服务
--exclude-topics 新增 设置不记录的主题黑名单
--exclude-services 新增 设置不记录的服务黑名单
ros 2 bag play​ 更新列表:
参数 类型 功能描述
--publish-service-requests 新增 根据记录的服务内省消息重放服务请求
--service-requests-source 新增 指定服务请求来源:
• service_introspection - 服务内省消息
• client_introspection - 客户端内省消息
--services 新增 指定要重放的服务列表
--exclude-topics 新增 设置不重放的主题黑名单
--exclude-services 新增 设置不重放的服务黑名单
--exclude-regex 修改 通过正则表达式排除主题和服务

Rosbag 2 动作记录与回放功能

rosbag2/docs/design/rosbag2_record_replay_action.md at rolling · ros2/rosbag2

背景说明

本文档基于当前架构描述动作记录与回放功能的实现方案,并说明如何扩展现有命令行参数。

动作消息记录原理

动作的实现使用三个服务和两个主题。启用服务内省功能后,rosbag 2 可通过服务事件主题记录动作相关数据(参考 rosbag2_record_replay_service.md),因此可完整记录动作的所有通信数据。

动作记录涉及的主题/服务

- 目标提交服务  
  [命名空间/]动作名/_action/send_goal  
  服务事件主题:[命名空间/]动作名/_action/send_goal/_service_event

- 结果获取服务  
  [命名空间/]动作名/_action/get_result  
  服务事件主题:[命名空间/]动作名/_action/get_result/_service_event

- 目标取消服务  
  [命名空间/]动作名/_action/cancel_goal  
  服务事件主题:[命名空间/]动作名/_action/cancel_goal/_service_event

- 状态主题  
  [命名空间/]动作名/_action/status

- 反馈主题  
  [命名空间/]动作名/_action/feedback

每个动作将记录五个相关主题/服务事件主题。、

扩展 'record' 命令参数

新增参数:

参数名称 功能描述
--actions 动作名 [动作名 ...] 要记录的动作列表(空格分隔)
--all-actions 通过服务事件主题和隐藏主题记录所有动作
--exclude-actions 动作名 [动作名 ...] 不记录的动作列表(空格分隔),可与其他过滤参数叠加使用

更新参数:

参数名称 功能描述
-a, --all 记录所有主题、服务和动作(排除其他隐藏主题)
-e 正则表达式, --regex 正则表达式 仅记录匹配正则表达式的主题、服务和动作(注意:--all, --all-topics, --all-services 或 --all-actions 会覆盖此参数)
--exclude-regex 排除正则表达式 排除匹配正则表达式的主题、服务和动作(可与其他参数叠加使用)

扩展 'play' 命令参数

新增参数:

参数名称 功能描述
--actions 动作名 [动作名 ...] 要回放的动作列表(空格分隔)
--exclude-actions 动作名 [动作名 ...] 不回放的动作列表(空格分隔)
--send-actions-as-client 基于记录的服务事件消息分别发送 send_goal、cancel_goal 和 get_result 请求。注意:动作的"状态主题"和"反馈主题"消息不会被发送,因为这些应由动作服务器端发送。

更新参数:

参数名称 功能描述
-e 正则表达式, --regex 正则表达式 仅回放匹配正则表达式的主题、服务和动作
-x 排除正则表达式, --exclude-regex 排除正则表达式 通过正则表达式排除不回放的主题、服务和动作
--service-requests-source 指定服务请求的回放来源。需与"--publish-service-requests"或**"--send-actions-as-client"**参数配合使用,默认为记录的服务内省消息。

基于 VitePress 构建