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條