Ros2 bag
概述
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 技术要求
- 确定性:多次回放保证数据序列确定
- 适应性:消息字段添加
- 可扩展性
- 随机访问:无需遍历对某个主题的第 n 条消息的随机访问
- 范围访问
- 可变数据块大小
- 与 ROS 1 的向后兼容性
ros 2 bags 的设计方案
ros 2 bag 自下而上被分为 3 层:
- 数据包存储 api 层:与 ROS 2 解耦,仅负责读写抽象的二进制消息
- 数据包 api 层:负责获取 ROS 2 消息,对其进行序列化并添加充分描述信息,以供存储 API 层写入
- 数据包命令行接口层:为用户提供了控制数据包录制与回放的入口

存储 api 层
负责以二进制格式存储传入的 ROS 消息的底层软件包。数据存储负责持久保存 ROS 消息及其足够的元信息,以便在加载时恢复其完整上下文。
数据编码
ros 2 消息 <<=[唯一性]=>> 二进制
数据存储
抽象表示:实际消息的二进制数据块以及一个键值对元数据 支持多种数据存储解决方案(例如 SQLite 或 rosbag format2 )
该 API 能够:
- 支持多种数据存储;
- 将数据从一个存储传输到另一个存储。
Sqlite
ros 2 选择 sqlite 作为默认的解决方案。
理由:
- 轻量级依赖,在各主流平台经过充分测试
- 单文件即可运行,便于初期 API 开发和存储实现
- 基准测试显示写入速度可达>1 GB/s(大消息场景下接近磁盘写入极限)
- 高频小消息处理性能优异(>10 万条/秒)
优势:
- 表结构无需预定义,可灵活扩展
- 支持标准 SQL 语法和工具进行查询
劣势:
- 与直接将传入数据转储到文件的格式(例如 ROS 1 rosbag)相比,写入性能可能存在缺陷。
可插拔数据存储
ros 2 为该 API 层实现可扩展的插件架构,该架构能够连接各种数据存储解决方案,从而使用户有机会根据自己的用例优化数据存储。
api 设计
存储 API 接口设计如下(完整 API 可能采用 C 语言接口+C++实现,便于 Python/Java 等语言绑定):
- open:进程初始化时调用,准备数据读写格式
BagHandle open (string file_path, void * impl_data) - close:进程退出时调用
bool close (BagHandle * handle) - create_topic:对于每个要记录的新主题,
create topic函数都会被调用一次。它接收连接信息、指示相应二进制数据编码的唯一标识符、数据块大小,并且可以接受一个可选的指针来存储特定于实现的数据。这里隐含的约定是每个主题只能有一种编码方式。不支持同一消息和同一主题使用混合编码。
TopicHandle create_topic (BagHandle * handle, ConnectionHeader connection_header, string encoding_id, int chunk_size, void * impl_data) 

- open_topic:读取主题时获取句柄
TopicHandle open_topic (BagHandle * handle, string topic_name) - write:持久化存储数据,通过主题句柄定位存储位置
void write (BagHandle * handle, TopicHandle * topic, struct time_received, SerializedData * serialized_data, void * impl_data) - read_next:迭代器式顺序读取(可选主题过滤)
SerializedData read_next (IteratorHandle * iter, TopicHandle * topic, void * impl_data) - read:索引式范围查询(支持多主题和时间范围检索,可指定排序方式)
SerializedData[] read (struct query, enum order_by, void * impl_data) - info:获取存储数据的统计信息(主题列表、总时长等)
BagInfo info (BagHandle * handle) - index:录制完成后创建索引文件(YAML 格式),存储元数据
void index (BagHandle * handle) 数据结构定义
连接头信息(扩展 ROS 1 头信息,增加 QoS 参数):
struct ConnectionHeader {
string topic_name,
string topic_type,
string message_definition,
string message_md 5_sum,
struct quality_of_service_params
} 序列化数据载体:
struct SerializedData {
byte[] payload,
int size,
} 数据包信息(扩展 ROS 1 info,增加键值对存储):
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
} 主题句柄(封装编码信息):
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
- 压缩
包结构
~/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

各层职责:
- user layer:命令行接口与 launch 文件集成
- python bindings:提供 pybind 11 生成的 python 接口
- transport layer:包含作为 rclcpp:: Node 组件的 player 与 recorder(
Player和Recorder均以rclcpp组件的形式实现,可以加载到组件容器中以进行进程内通信) - core c++ layer:实现了存储 I/O、压缩和转换逻辑
- storage plugin layer:具有可插拔存储和压缩实现的抽象接口
rosbag2的核心组件: Packages and Components | ros2/rosbag2 | DeepWiki
关键类:

传输层

传输层使用 ROS 2 的通用发布和订阅机制来处理任意类型的消息。
基于服务的控制接口(rolling)
两个节点都暴露了 ROS 2 服务以进行运行时控制:
Player Services (namespace: ~/):
pause,resume,toggle_paused,is_pausedget_rate,set_rateseek,play_next,burstplay,stop
Recorder Services (namespace: ~/):
pause,resume,is_pausedsplit_bagfilesnapshot(仅在启用快照模式时)
时间控制系统

rosbag 2 中的时间控制系统负责管理播放时间,从而可以精确控制录制消息的重放方式。该系统负责协调播放的时间特性,包括播放速率控制、暂停/恢复和时间跳转功能。
在回放 ros 2 bags 时,时间控制系统决定:
- 根据时间戳确定何时发布下一条消息
- 如何控制播放速度(比实时速度快/慢)
- 如何实现暂停和恢复功能
- 如何处理时间跳跃(跳过过去或回到过去)
该系统将时间管理与消息的实际发布解耦,从而在 rosbag 2 架构中实现了清晰的关注点分离。
时间控制系统维护一个参考点,该参考点建立了两个时间域之间的关系:
- ROS 时间 :ROS 消息中使用的时间戳域
- 稳定时间 :用于测量实际经过时间的现实世界时钟

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

存储层
表结构

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)。因此可以通过记录普通主题的方式捕获这些消息。
service->configure_introspection(
node->get_clock(),
rclcpp::ServicesQoS(),
RCL_SERVICE_INTROSPECTION_CONTENTS); 服务事件主题识别方法
服务事件主题虽以普通主题形式存储,但在读取录制文件后需要区别处理。识别标准如下:
- 普通主题
[命名空间/]主题名
- 隐藏主题
[命名空间/]_主题名
- 服务事件主题
[命名空间/]服务名/_service_event 具体判定标准:
- 主题以
/_service_event结尾 - 主题类型名称匹配
*/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"**参数配合使用,默认为记录的服务内省消息。 |