Wiki
回溯rosbag2
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
1.概述

方式1一邊採集數據,一邊生成地圖信息。
方式2是將採集數據和生成地圖信息分割開來了,方式2做到了解耦合,所以更靈活一些。用同一套數據,可能用不同的算法處理,總之,非常靈活。
留存的過程咱們也可以叫做序列化。(轉化為磁盤文件)
留存一般叫錄製(序列化)。
讀取一般叫回放(反序列化)。

留存時也可以將文件進行分卷,也就是每個文件最大能佔多大的大小,如果超過該大小,就新建一個文件繼續留存。(類似於壓縮文件的分卷)
這樣的話,存的數據太大,我們一次性打開太慢,就可以分段打開。


需要依賴於rosbag2_cpp或者rosbag2_py
然後還要依賴於geometry_msgs,這個是因為我們要序列化的數據是這個包下的速度指令。
ros2 pkg create cpp02_rosbag --build-type ament_cmake --dependencies rclcpp rosbag2_cpp geometry_msgs --node-name cpp01_writer
2.rosbag2的命令工具

一般ROSBAG2的使用有命令行工具和編碼兩種使用方式,命令行工具功能比較齊全,夠用。
查看幫助文檔ros2 bag -h

主要有6個指令。



可以看record的詳細用法。

record是用來將消息序列化的,但實際上比這個複雜。(錄製)
play是用來反序列化消息的,但實際上比這個複雜。(回放)
ROS 2 Message
↓ serialization
serialized bytes
↓ rosbag2 + timestamp + topic metadata + storage plugin
bag
序列化只是錄製過程中的一個環節。
record 實際上包含:
发现 Topic
↓
建立 Subscription
↓
接收序列化消息
↓
记录时间戳
↓
交给 Storage Plugin
↓
写入磁盘
读取 bag
↓
按照记录时间调度消息
↓
创建 Publisher
↓
按照 QoS 发布
↓
ROS 2 其他节点重新收到消息
這一點非常重要,因為後面所有 QoS 問題,本質上就是 Recorder 是訂閲者、Player 是發佈者。
info是用來輸出bag文件的相關信息的。比如有多少條消息,錄製起始時間和終止時間以及持續時間。
reindex是重建bag文件,可以根據現有 bag 數據重新構建 metadata。 例如異常退出導致 metadata.yaml 缺失或損壞時,它很有價值。
list是輸出rosbag2中可用的插件(高階應用)。
convert我們可以用這個給bag重新讀取再寫出一個新的 bag,也可以把多個bag文件合併成一個文件。 可以用來:
- 合併 bag
- 拆分 bag
- 重新選擇話題
- 改 storage
- 壓縮/解壓
- 修改序列化格式

打開小烏龜節點與鍵盤控制小烏龜節點。
我們用鍵盤控制小烏龜,然後把速度指令通過rosbag2給序列化。
然後我們關掉兩個節點,再重啓小烏龜節點,然後這次不通過鍵盤控制,而是通過play bag文件讓小烏龜運動。
record指令後面要跟一個話題組成的列表,但是在咱們下面的操作中,只用到了一個話題。


然後再用output,把序列化後的文件寫出到一個磁盤目錄中去。

cd進想保存bag的目錄,然輸入record指令,後面跟話題名稱,然後-o +bag文件名,這裏也可以不重新命名bag文件,這樣會用默認的名字,默認的名稱是年月日命名的。
這樣就已經開始錄製了。


按Ctrl + C進行結束,結束有個提示,説正在將消息寫入bag,需要一段時間。


my_bag/
├── metadata.yaml
└── my_bag_0.db3
其中:
metadata.yaml
→ bag 的描述信息
→ 录了哪些 topic
→ topic 类型
→ 消息数量
→ duration
→ storage id
→ bag 分片信息
...
*.db3
→ SQLite3 storage plugin 真正保存的消息数据
db3是SQLite數據庫,這個是移動端(比如手機)常用的數據庫,但其他平台其實也可以用。 所以 .db3 才是主要的數據載體。
這個數據庫就存儲了錄製的數據。
Humble 默認用 SQLite3 storage plugin 保存 bag。
而且存儲插件是可替換的。你本機究竟有哪些插件,不應該靠猜,應該直接:
ros2 bag list storage

Humble 的 CLI 會根據系統實際註冊的 writer 插件決定 -s/--storage 可以選擇什麼。ROS 2 Humble rosbag2 README
3.rosbag2中的QoS
前面已經知道,rosbag2 在錄製和回放時並不是單純地“讀寫文件”:
录制:Publisher → rosbag2 Recorder(Subscriber)
回放:rosbag2 Player(Publisher)→ Subscriber
因此,只要 rosbag2 參與 ROS 2 通信,就同樣要遵守 ROS 2 的 QoS(服務質量,Quality of Service)規則。
ROS 2 的 QoS 策略很多,例如 History(歷史策略)、Depth(隊列深度)、Reliability(可靠性)、Durability(持久性)、Deadline(截止期限)、Liveliness(活躍性) 等。
對於 rosbag2 的錄製和回放,首先最需要理解的是:
- Reliability(可靠性):
Reliable(可靠) 和Best Effort(盡力而為) - Durability(持久性):
Transient Local(本地瞬態) 和Volatile(易失性)
官方文檔:
- ROS 2 Humble:Quality of Service settings
- ROS 2 Humble:Overriding QoS Policies for Recording and Playback
3.1.Request / Offered 模型
ROS 2 中,Publisher 和 Subscriber 的 QoS 並不是“必須完全相同”才能通信。
它採用的是 Request / Offered 模型:
Publisher
↓
Offered QoS(提供的服务质量)
Subscriber
↓
Requested QoS(请求的服务质量)
只有 Publisher 提供的 QoS 能滿足 Subscriber 請求的 QoS,兩者才能正常通信。
所以不能簡單理解成:
Publisher QoS == Subscriber QoS
而應該理解成:
Publisher 提供的能力
↓
能不能满足 Subscriber 的要求?
這個規則對普通 ROS 2 節點成立,對 rosbag2 也一樣成立。
錄製時:
原节点 Publisher
↓
rosbag2 Recorder Subscriber
回放時:
rosbag2 Player Publisher
↓
算法节点 Subscriber
3.2.Reliability(可靠性)
Reliability 決定消息傳輸過程中,對“消息是否必須儘量送達”的要求。
Reliable(可靠) 可以理解為:
尽量保证消息送达
如果底层发现消息丢失,可以进行重传等处理
Best Effort(盡力而為) 可以理解為:
尽最大努力发送
如果某条消息丢失,不要求一定重传
更加关注最新的数据
很多高頻傳感器數據使用的 Sensor Data QoS Profile 會採用 Best Effort。對於這類數據,相比於等待舊數據重傳,系統通常更關心最新的傳感器數據。
Reliability 的兼容關係如下:
| Publisher Offered | Subscriber Requested | 是否兼容 |
|---|---|---|
| Best Effort | Best Effort | ✅ |
| Best Effort | Reliable | ❌ |
| Reliable | Best Effort | ✅ |
| Reliable | Reliable | ✅ |
最容易混淆的是下面兩種情況:
Best Effort Publisher
↓
Reliable Subscriber
❌ 不兼容
原因是 Subscriber 要求“可靠傳輸”,但 Publisher 只提供 Best Effort,無法滿足 Subscriber 的要求。
反過來:
Reliable Publisher
↓
Best Effort Subscriber
✅ 兼容
因為 Publisher 提供的能力已經能夠滿足 Subscriber 較低的要求。
因此,Reliable 並不是簡單意義上的“比 Best Effort 更高級,所以任何時候都應該選 Reliable”。
QoS 的核心是:雙方是否兼容,以及這種通信策略是否適合當前數據。
3.3.Durability(持久性)
Durability 主要決定:一個 Subscriber 後加入通信時,能不能收到 Publisher 之前已經發布過的數據。
Volatile(易失性) 可以理解為:
只接收建立通信之后的新消息
不保留之前已经发布的历史消息
例如:
Publisher:A B C
Subscriber 在这里启动
Publisher: D E
如果 Subscriber 使用 Volatile,它通常只關心:
D E
而不會要求得到之前的:
A B C
Transient Local(本地瞬態) 則允許 Publisher 為後加入的 Subscriber 保留一定的歷史樣本。
可以把它理解成:
Publisher
│
├── 发布消息
│
└── 在本地保留历史样本
↓
Late Joiner Subscriber
它的行為和 ROS 1 中 latched publisher 的概念有一定相似之處。
Durability 的兼容關係如下:
| Publisher Offered | Subscriber Requested | 是否兼容 |
|---|---|---|
| Volatile | Volatile | ✅ |
| Volatile | Transient Local | ❌ |
| Transient Local | Volatile | ✅ |
| Transient Local | Transient Local | ✅ |
其中:
Volatile Publisher
↓
Transient Local Subscriber
❌ 不兼容
因為 Subscriber 要求能夠獲得 Transient Local 的歷史數據能力,但 Publisher 並沒有提供這種能力。
而:
Transient Local Publisher
↓
Volatile Subscriber
✅ 可以通信
但 Volatile Subscriber 並不會因為 Publisher 是 Transient Local,就自動要求得到建立通信之前的歷史數據。
3.4./tf_static為什麼特殊
/tf_static 是理解 Durability 很典型的例子。
靜態 TF 的特點是:
变换关系基本不会变化
↓
没有必要像动态 /tf 一样持续高频发布
例如機械人中的某個固定傳感器變換:
base_link
↓
laser_link
這個靜態關係可能在系統啓動時就已經發布。
假設:
10:00:00
Static TF Publisher 发布 /tf_static
10:00:20
rosbag2 Recorder 才启动
如果 Recorder 只能接收啓動之後的新數據,而 /tf_static 後面又沒有重新發布,那麼這個 bag 就可能缺少關鍵的靜態座標變換。
因此 /tf_static 使用 Transient Local Durability,使後加入的 Subscriber 也有機會獲得之前保留的靜態 TF 數據。
這也是為什麼錄製 SLAM、定位和導航數據時,不能只確認“bag 裏面有沒有 /tf”,還需要關注 /tf_static 是否被正確錄製。
3.5.rosbag2會自動適配QoS
理解 QoS 以後,也不要走到另一個極端:
是不是录每一个 Topic 都必须手动写 QoS?
通常不是。
ROS 2 Humble 的 rosbag2 在錄製時會根據發現到的 Publisher 嘗試調整 Recorder 的 Requested QoS;在回放時,也會嘗試保留原 Topic 原先 Offered 的 QoS。
因此大多數普通 Topic 不需要手動指定 QoS。
但是在一些需要明確控制行為的場景中,例如:
- 關鍵傳感器 Topic
/tf_static- 同一個 Topic 存在多個 Publisher,並且 QoS 不完全一致
- 默認自動適配無法滿足實際錄製或回放需求
- 希望實驗中的 QoS 行為固定、可復現
就可以使用 rosbag2 的 QoS Override。
3.6.查看Topic實際使用的QoS
不要只根據源碼、Topic 名字或者經驗猜測實際 QoS。
系統真正運行起來後,可以使用:
ros2 topic info -v /topic_name
查看該 Topic 當前 Publisher 和 Subscriber 實際使用的 QoS。
例如重點觀察:
Reliability
Durability
History
Depth
尤其在實車中,最終的 rosbag2 配置應該以實際運行時的 Topic 和 QoS為準。
3.7.rosbag2 QoS Override
rosbag2 可以通過 YAML 文件為特定 Topic 覆蓋 QoS。
例如:
/tf_static:
reliability: reliable
durability: transient_local
如果某個傳感器 Topic 實際使用 Best Effort,也可以按實際情況配置:
/sensor_points:
reliability: best_effort
durability: volatile
這裏的 /sensor_points 只是示例。實際工程中應當先運行系統,再通過 ros2 topic info -v 確認真實 Topic 和 QoS。
錄製時使用:
ros2 bag record \
--qos-profile-overrides-path qos_overrides.yaml \
/topic1 /topic2
此時 QoS Override 影響的是:
rosbag2 Recorder
↓
Subscription QoS
回放時使用:
ros2 bag play \
--qos-profile-overrides-path qos_overrides.yaml \
my_bag
此時 QoS Override 影響的是:
rosbag2 Player
↓
Publisher QoS
所以同一個參數在 record 和 play 中的作用對象並不相同。
最終可以把這一節的關係整理成:
录制
原 Publisher
│ Offered QoS
↓
rosbag2 Recorder
Requested QoS
回放
rosbag2 Player
│ Offered QoS
↓
算法 Subscriber
Requested QoS
理解這個模型以後,後面處理傳感器數據、/tf_static 以及 rosbag2 的 QoS Override,就不再只是記配置參數,而是在判斷:
Publisher 提供的 QoS,能不能滿足 Subscriber 請求的 QoS。
4.rosbag2的話題選擇
實際使用 rosbag2 時,首先要決定的就是:到底錄哪些 Topic。
最直接的方式是顯式指定 Topic:
ros2 bag record /topic1 /topic2 /topic3
這種方式最明確,也最適合已經知道自己需要哪些數據的場景。
如果希望錄製當前系統中的全部 Topic,可以使用:
ros2 bag record -a
其中:
-a
--all
表示錄製所有能夠發現的 Topic。
默認情況下,rosbag2 在錄製過程中還會繼續進行 Topic Discovery。也就是説,即使某個 Topic 在啓動 rosbag2 時還不存在,只要後面出現,Recorder 仍然可以發現它並開始錄製。
如果不希望錄製過程中繼續發現新 Topic,可以使用:
ros2 bag record -a --no-discovery
此時只會考慮 Recorder 啓動時已經存在的 Topic。
需要注意,Humble 中 --use-sim-time 和 --no-discovery 不能同時使用,因為使用仿真時間時 Recorder 需要發現並訂閲 /clock。
4.1.使用正則表達式選擇Topic
除了顯式列出 Topic 和使用 -a 以外,還可以使用:
-e
--regex
例如:
ros2 bag record -e ".*camera.*"
它適合 Topic 數量比較多,並且命名有明顯規律的系統。
4.2.排除不需要的Topic
如果希望先選擇一大批 Topic,再排除其中一部分,可以使用:
-x
--exclude
例如:
ros2 bag record -a -x ".*debug.*"
可以理解成:
先选择一批 Topic
↓
再排除匹配 exclude 的 Topic
Humble 中,--exclude 需要和 --all 或 --regex 一起使用。顯式列出 Topic 時不能同時使用 --exclude。
4.3.Hidden Topic和Unpublished Topic
--include-hidden-topics 用於把隱藏 Topic 也納入發現和錄製範圍。隱藏 Topic 通常用於 ROS 2 內部或框架功能,一般不需要默認錄製。
--include-unpublished-topics 則允許發現併為當前沒有 Publisher 的 Topic 建立 Subscription。對於這種 Topic,如果沒有額外提供 QoS Override,rosbag2 會使用默認 QoS 建立 Subscription。
4.4.Topic選擇的基本原則
可以簡單理解為:
临时调试 / 初步摸清系统
↓
-a 比较方便
长期录制 / 固定实验
↓
显式 Topic 或正则筛选更可控
-a 並不一定是錯誤的,但它可能把大量無關、高頻或者調試 Topic 一起錄下來。
Topic 越多,通常意味着:
DDS 接收量增加
↓
内存缓存压力增加
↓
磁盘写入量增加
↓
bag 体积增加
因此在正式實驗中,更重要的不是“錄得越多越好”,而是保證真正需要的數據被完整記錄。
5.rosbag2中的時間
rosbag2 不只是保存消息內容,還必須為消息記錄時間。時間決定了回放時消息之間的先後關係和間隔。
在普通系統中,Recorder 通常使用正常的 ROS/System 時間。
但是在 Gazebo 等仿真環境裏,經常會使用 ROS Time,並由 /clock 提供仿真時間。
5.1.錄製時使用仿真時間
Humble 中可以使用:
ros2 bag record --use-sim-time -a
開啓以後,Recorder 會訂閲 /clock,並使用最新收到的仿真時間作為寫入 bag 的時間戳。
這裏有一個非常重要的行為:
在收到第一條
/clock之前,rosbag2 不會把消息寫入 bag。
這是為了避免前面的消息以時間 0 寫入,隨後時間突然跳到正常仿真時間,導致 bag 的時間軸出現很大的跳變。
可以理解成:
启动 Recorder
↓
等待 /clock
↓
收到第一个有效仿真时间
↓
开始正常写 bag
所以:
实机正常系统
↓
通常不需要 --use-sim-time
使用 /clock 的仿真系统
↓
需要考虑 --use-sim-time
5.2.回放時發佈/clock
回放 bag 時,可以讓 Player 發佈 /clock:
ros2 bag play my_bag --clock
Humble 中,--clock 可以指定發佈頻率:
ros2 bag play my_bag --clock 40
如果只寫 --clock,Humble 默認使用 40 Hz。
這對於設置了:
use_sim_time = true
的節點很重要,因為這些節點需要從 /clock 獲取 ROS Time。
5.3.bag時間和消息Header不是一回事
很多 ROS 2 消息本身帶有:
header.stamp
但 rosbag2 自己也會記錄用於保存和調度消息的 bag 時間。
所以不能簡單把:
消息内部的 header.stamp
和:
rosbag2 的记录/回放时间
認為是同一個概念。
6.rosbag2的分卷
如果長時間錄製數據,一個 bag 內部的數據文件可能越來越大。
rosbag2 支持按照文件大小或者錄製時間自動分卷。
6.1.按大小分卷
Humble 使用:
-b
--max-bag-size
單位是 byte。
例如:
ros2 bag record -a -b 1000000000
噹噹前 bag 數據文件達到設定大小後,會切換到新的分片繼續寫入。參數為 0 時關閉按大小分卷。
6.2.按時間分卷
Humble 使用:
-d
--max-bag-duration
單位是秒。
例如:
ros2 bag record -a -d 900
表示大約每錄製 900 秒切換到新的分片。參數為 0 時關閉按時間分卷。
6.3.同時設置大小和時間
兩個條件可以同時啓用:
ros2 bag record -a \
--max-bag-size 1000000000 \
--max-bag-duration 900
此時:
达到大小上限
或
达到时间上限
↓
哪个先发生,就先触发分卷
一個 bag 目錄中可能出現:
my_bag/
├── metadata.yaml
├── my_bag_0.db3
├── my_bag_1.db3
├── my_bag_2.db3
└── ...
這些文件仍然屬於同一個邏輯上的 bag。
分卷除了控制單文件大小,也方便長時間錄製、文件傳輸、數據歸檔和異常情況下的恢復。官方 rosbag2 文檔也建議在使用壓縮時考慮配合分卷。
7.rosbag2的壓縮
傳感器數據、圖像、點雲等 Topic 可能很快產生大量數據。
rosbag2 可以在錄製過程中進行壓縮,主要通過:
--compression-mode
--compression-format
配置。
7.1.Compression Mode
Humble 支持:
none
file
message
其中:
none:不啓用壓縮;file:對 bag 數據文件進行壓縮;message:按消息進行壓縮。
7.2.Compression Format
Humble 官方 rosbag2 提供的壓縮格式是:
zstd
例如:
ros2 bag record -a \
--compression-mode file \
--compression-format zstd
如果指定了 --compression-format,卻沒有設置有效的 --compression-mode,Humble 會認為參數組合無效。
7.3.壓縮不是沒有代價
壓縮本質上是在:
磁盘占用
↕
CPU计算量
之間進行權衡。
大致可以理解成:
不压缩
↓
CPU 开销较低
磁盘写入量和文件体积较大
启用压缩
↓
文件体积可能下降
但需要额外 CPU 进行压缩
因此不能只因為“文件更小”就默認打開壓縮,還應該觀察 Recorder 是否掉消息、CPU 是否過載、磁盤是否成為瓶頸,以及最終 bag 是否能夠穩定回放。
Humble 還提供:
--compression-queue-size
--compression-threads
用於控制壓縮隊列和並行線程。這類參數通常應該在確實遇到性能問題以後再調整。
8.rosbag2的存儲配置
前面已經知道,rosbag2 的底層數據保存由 Storage Plugin 完成。
可以查看當前系統安裝的 Storage Plugin:
ros2 bag list storage
錄製時可以通過:
-s
--storage
選擇 storage id,例如:
ros2 bag record -a -s sqlite3
如果不指定,rosbag2 會使用當前系統的默認 writer。
8.1.storage配置文件
Humble 支持:
--storage-config-file
傳入 Storage Plugin 自己的配置。
對於 SQLite3 Storage Plugin,配置結構可以包含:
read:
pragmas: []
write:
pragmas: []
這裏的 pragma 是 SQLite 自己的數據庫配置,例如可能涉及 journal mode、synchronous、cache size、page size 等。
這些參數會影響:
写入性能
内存占用
崩溃时的数据安全性
因此不應該在不瞭解 SQLite 行為時隨意修改。
8.2.性能和數據安全之間的權衡
rosbag2 默認 SQLite 設置偏向錄製性能。
這樣有利於高吞吐寫入,但如果 Recorder 或整個系統異常崩潰,當前正在寫入的數據文件可能存在損壞風險。
如果已經啓用分卷,風險通常主要集中在當前正在寫入的分片,而不是已經正常關閉的舊分片。
Humble 還提供:
--storage-preset-profile
官方文檔提到可以使用:
resilient
提高對異常崩潰造成損壞的抵抗能力。
但更高的數據安全性也可能帶來一定的性能代價,所以 Storage 配置同樣是在平衡:
写入性能
↕
异常情况下的数据完整性
9.rosbag2的回放控制
最基本的回放命令是:
ros2 bag play my_bag
除此以外,Humble 的 Player 還提供很多控制選項。
9.1.調整回放速度
使用:
-r
--rate
例如:
ros2 bag play my_bag -r 0.5
表示按照原始時間關係的一半速度回放。
ros2 bag play my_bag -r 2.0
表示按照兩倍速度回放。rate 必須大於 0。
9.2.只回放部分Topic
使用:
--topics
例如:
ros2 bag play my_bag \
--topics /topic1 /topic2
如果不指定 --topics,默認回放 bag 中的全部 Topic。
9.3.Topic Remap
Player 支持:
-m
--remap
例如:
ros2 bag play my_bag \
--remap /old_topic:=/new_topic
這樣可以在不修改 bag 本身的情況下,把回放出來的 Topic 映射到新的名稱。
9.4.延遲、起始位置與暫停
--delay 可以讓 Player 啓動後等待一段時間再開始回放:
ros2 bag play my_bag --delay 5
--start-offset 可以從 bag 中間某個時間位置開始:
ros2 bag play my_bag --start-offset 30
-p / --start-paused 可以讓 Player 啓動後先處於暫停狀態。
9.5.循環播放
使用:
-l
--loop
例如:
ros2 bag play my_bag --loop
到達 bag 結尾後,會重新從頭開始播放。
9.6.回放緩存
Humble 提供:
--read-ahead-queue-size
控制 Player 預讀到內存中的消息隊列大小。
隊列更大可能減少因為磁盤讀取不足造成的播放延遲,但也會增加內存佔用。默認情況下通常不需要修改。
9.7.等待Reliable消息確認
Humble 還提供:
--wait-for-all-acked
用於在回放結束前等待 Reliable Publisher 發出的消息被 Subscriber 確認。
這個參數只對 Reliable QoS 有意義,適合某些短時間內快速發送大消息的場景。
9.8.通過Service控制Player
rosbag2 Player 還提供一組 ROS 2 Service,可以在運行期間控制播放狀態,例如:
pause
resume
toggle_paused
play_next
burst
seek
get_rate
set_rate
is_paused
play
因此 Player 並不只是一個“從頭到尾自動播放完”的命令,它也可以被其他程序動態控制。
總體上可以把回放過程理解成:
bag
↓
rosbag2 Player
├── 选择 Topic
├── 控制播放速度
├── 控制起始位置
├── Pause / Resume
├── Remap Topic
├── 发布 /clock
└── 按 QoS 发布消息
↓
ROS 2 节点
到這裏,rosbag2 在實際使用中最常見的錄製、回放和配置能力已經基本覆蓋。
對於一般工程,優先複用官方提供的 ros2 bag record、ros2 bag play 等工具,再通過參數、配置文件和 Launch 進行組織即可,沒有必要為了錄包功能重新實現一套 Recorder 或 Player。
下面的 C++ Writer / Reader 示例主要用於理解 rosbag2_cpp 的程序接口和基本工作原理。
10.rosbag2 C++案例分析及框架搭建


add_executable(demo01_writer src/demo01_writer.cpp)
ament_target_dependencies(
demo01_writer
"rclcpp"
"rosbag2_cpp"
"geometry_msgs"
)
add_executable(demo02_reader src/demo02_reader.cpp)
ament_target_dependencies(
demo02_reader
"rclcpp"
"rosbag2_cpp"
"geometry_msgs"
)
install(TARGETS
demo01_writer
demo02_reader
DESTINATION lib/${PROJECT_NAME})
11.rosbag2 C++ 錄製數據
/*
需求:录制 turtle_teleop_key 节点发布的速度指令。
步骤:
1.包含头文件;
2.初始化 ROS 客户端;
3.定义节点类;
3-1.创建写出对象指针;
3-2.设置写出的目标文件;
3-3.写出消息。
4.调用 spin 函数,并传入对象指针;
5.释放资源。
*/
// 1.包含头文件;
#include "rclcpp/rclcpp.hpp"
#include "rosbag2_cpp/writer.hpp"
#include "geometry_msgs/msg/twist.hpp"
using std::placeholders::_1;
// 3.定义节点类;
class SimpleBagRecorder : public rclcpp::Node
{
public:
SimpleBagRecorder()
: Node("simple_bag_recorder")
{
// 3-1.创建写出对象指针;
writer_ = std::make_unique<rosbag2_cpp::Writer>();
// 3-2.设置写出的目标文件;(目录为ws目录)
writer_->open("src/cpp02_rosbag/my_bag");
subscription_ = create_subscription<geometry_msgs::msg::Twist>(
"/turtle1/cmd_vel", 10, std::bind(&SimpleBagRecorder::topic_callback, this, _1));
}
private:
void topic_callback(std::shared_ptr<rclcpp::SerializedMessage> msg) const
{
rclcpp::Time time_stamp = this->now();
// 3-3.写出消息。
RCLCPP_INFO(this->get_logger(),"数据写出... ...");
writer_->write(msg, "/turtle1/cmd_vel", "geometry_msgs/msg/Twist", time_stamp);
}
rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr subscription_;
std::unique_ptr<rosbag2_cpp::Writer> writer_;
};
int main(int argc, char * argv[])
{
// 2.初始化 ROS 客户端;
rclcpp::init(argc, argv);
// 4.调用 spin 函数,并传入对象指针;
rclcpp::spin(std::make_shared<SimpleBagRecorder>());
// 5.释放资源。
rclcpp::shutdown();
return 0;
}

這是一個相對目錄,目錄位置是工作空間目錄。

寫數據之前,要先創建一個訂閲方,訂閲方要建立一個回調函數。

回調函數入口參數,消息類型用write函數的入口參數。

這裏要用斜槓代替冒號,因為入口是string類型。



創建烏龜節點。

啓動writer節點

運行小烏龜
運行一會兒後,關掉所有節點。

成功生成了文件
驗證錄製文件是否成功。
在驗證前,先創建一個烏龜節點,不用創建控制節點。
ros2 bag play src/cpp02_rosbag/my_bag

可以看到烏龜正常走了。回放成功!

如果已經生成了一遍my_bag,再想生成新的會顯示不能覆蓋。
解決方案,可以把my_bag設置為動態的,加個時間戳或者直接按功能命名。
12.rosbag2 C++ 讀取數據
/*
需求:读取 bag 文件数据。
步骤:
1.包含头文件;
2.初始化 ROS 客户端;
3.定义节点类;
3-1.创建读取对象指针;
3-2.设置读取的目标文件;
3-3.读消息;
3-4.关闭文件。
4.调用 spin 函数,并传入对象指针;
5.释放资源。
*/
// 1.包含头文件;
#include "rclcpp/rclcpp.hpp"
#include "rosbag2_cpp/reader.hpp"
#include "geometry_msgs/msg/twist.hpp"
// 3.定义节点类;
class SimpleBagPlayer: public rclcpp::Node {
public:
SimpleBagPlayer():Node("simple_bag_player"){
// 3-1.创建读取对象指针;
reader_ = std::make_unique<rosbag2_cpp::Reader>();
// 3-2.设置读取的目标文件;
reader_->open("src/cpp02_rosbag/my_bag");
// 3-3.读消息;
while (reader_->has_next())
{
auto twist = reader_->read_next<geometry_msgs::msg::Twist>();
RCLCPP_INFO(this->get_logger(),"线速度:%.2f, 角速度: %.2f",twist.linear.x, twist.angular.z);
}
// 3-4.关闭文件。
reader_->close();
}
private:
std::unique_ptr<rosbag2_cpp::Reader> reader_;
};
int main(int argc, char const *argv[]){
// 2.初始化 ROS 客户端;
rclcpp::init(argc,argv);
// 4.调用 spin 函数,并传入对象指针;
rclcpp::spin(std::make_shared<SimpleBagPlayer>());
// 5.释放资源。
rclcpp::shutdown();
return 0;
}


編譯

這顯示能讀出來幾條信息。能讀出來8條。

正好8條