In this tutorial you’ll learn how to use ROS2 bags, with the ros2 bag command line tool, in order to save and replay data from your ROS2 topics.
Why and when to use ROS2 bags?
Imagine you’re working on your real – physical – robot, and you are developing an obstacle algorithm for the robot. Every time you want to test the algorithm you have to run the robot, and every time (as we’re in the real physical world, not a simulated one), some external conditions may be different. So it can be quite hard to compare the quality of 2 different results using 2 different data sets. With ROS2 bags, you can run your robot, record a sample (bag) of what’s happening, and then use this sample again and again.
Also, you can play back a ROS2 bag so you can skip starting some parts of your robot application. Thus, you can gain a lot of development time. If you’re experimenting on a not-so-stable hardware prototype for example, you can record a bag when things work the way you want, so you can use this sample to develop the software, while the hardware team focuses on improving the stability of the physical prototype.
One other case is when you use ROS2 as a tool for scientific research. If you need, let’s say, a sample of what’s happening when you send 10 drones outside in a rainy day, well, it’s possible with ROS2 bags.
So, there are many cases when ROS2 bags can be useful for you. Note that ROS2 bags only work for topics (data streams), not services.
ros2 bag record – Record Topic(s) and save data into a bag
Let’s start recording some topics with
ros2 bag. What you can do first is create a new folder named “bags” to put all your ROS2 bags into, so it won’t be a mess later.
You are learning ROS2...
As a complete beginner? Check out ROS2 For Beginners and learn ROS2 in 1 week.
As a ROS1 developer? Check out Learn ROS2 as a ROS1 Developer and Migrate Your ROS Projects.
Start some publishers
Before you can record topics, well you need to publish data with publishers.
Here we won’t write a new node, we’ll use the talker node from the demo_nodes_py package, which should be already installed (if not:
sudo apt install ros-<distro_name>-demo-nodes-py).
Start the node with
ros2 run demo_nodes_py talker in one terminal, and you can keep this node running for the duration of this tutorial.
ros2 topic list, you’ll see that we have 3 topics in our ROS2 graph.
$ ros2 topic list /chatter /parameter_events /rosout
That is the list of all topics we can record with ROS2 bags.
Record 1 topic
Let’s record the /chatter topic.
To record a topic into a bag, use: “ros2 bag record” + name of the topic.
$ ros2 bag record /chatter [INFO] [1593610018.395023411] [rosbag2_storage]: Opened database 'rosbag2_2020_07_01-15_26_58/rosbag2_2020_07_01-15_26_58_0.db3' for READ_WRITE. [INFO] [1593610018.400892775] [rosbag2_transport]: Listening for topics... [INFO] [1593610018.503442323] [rosbag2_transport]: Subscribed to topic '/chatter' [INFO] [1593610018.503503738] [rosbag2_transport]: All requested topics are subscribed. Stopping discovery...
As you can see, the /chatter topic was found and the bag is subscribing to it. All messages published on this topic will be recorded.
When you press CTRL+C the bag will stop all subscribers and no more message will be added to the bag.
ros2 bag record will create a SQLite3 database (database inside a file) and put it inside a folder, which name is the name of the bag.
Change the name of the ROS2 bag when recording
By default the name of the bag will be “rosbag2_” + current date and time. This is quite handy when you want to record multiple samples and easily sort them by the time when they were recorded.
However if you want to give another (meaningful) name to your bag, add an argument: “-o” + name of the bag.
$ ros2 bag record /chatter -o my_bag1 [INFO] [1593610057.356615405] [rosbag2_storage]: Opened database 'my_bag1/my_bag1_0.db3' for READ_WRITE. [INFO] [1593610057.361745739] [rosbag2_transport]: Listening for topics... [INFO] [1593610059.082524279] [rosbag2_transport]: Subscribed to topic '/chatter' [INFO] [1593610059.082558997] [rosbag2_transport]: All requested topics are subscribed. Stopping discovery...
Note: you can’t create 2 bags with the same name. If you try to do that you will get this kind of error:
[ERROR] [ros2bag]: Output folder 'bag_name' already exists. You won’t have this issue when using the default name (timestamp) but if you provide a custom name, make sure to modify it for every new bag.
Record multiple topics
You can of course record any number of topics inside a ROS2 bag. Simply add all the topics you want as additional arguments.
$ ros2 bag record /chatter /rosout -o my_bag2 [INFO] [1593610100.897299450] [rosbag2_storage]: Opened database 'my_bag2/my_bag2_0.db3' for READ_WRITE. [INFO] [1593610100.903099986] [rosbag2_transport]: Listening for topics... [INFO] [1593610100.903640580] [rosbag2_transport]: Subscribed to topic '/rosout' [INFO] [1593610101.005902954] [rosbag2_transport]: Subscribed to topic '/chatter' [INFO] [1593610101.005937045] [rosbag2_transport]: All requested topics are subscribed. Stopping discovery...
Here we chose to record /chatter as well as /rosout. All messages from both topics will be saved in the same database.
Record all the topics
If you simply want to record all the topics in your graph, use the “-a” option.
$ ros2 bag record -a -o my_bag3 [INFO] [1593610852.326754453] [rosbag2_storage]: Opened database 'my_bag3/my_bag3_0.db3' for READ_WRITE. [INFO] [1593610852.334258726] [rosbag2_transport]: Listening for topics... [INFO] [1593610852.335043030] [rosbag2_transport]: Subscribed to topic '/rosout' [INFO] [1593610852.335619377] [rosbag2_transport]: Subscribed to topic '/parameter_events' [INFO] [1593610852.438503884] [rosbag2_transport]: Subscribed to topic '/chatter'
Those 3 topics are the 3 topics we saw when executing
ros2 topic list. If you have 25 topics on your graph, the bag will record all 25 topics. Thus make sure you know what you’re doing when using the “-a” option.
ros2 bag info – Get a quick scan of the bag you created
OK, now you have created a few ROS2 bags, and each one is stored inside a different folder.
~/bags$ ls my_bag1 my_bag2 my_bag3 rosbag2_2020_07_01-15_26_58
You don’t need to worry about what’s inside the folders (metadata.yaml and SQLite3 files), the
ros2 bag info command gives you all the info you need.
Go to the folder where the bags are saved, and use “ros2 bag info” + name of the folder (=name of the bag).
$ ros2 bag info my_bag1/ Files: my_bag1_0.db3 Bag size: 16.8 KiB Storage id: sqlite3 Duration: 16.0s Start: Jul 1 2020 15:27:39.532 (1593610059.532) End: Jul 1 2020 15:27:55.533 (1593610075.533) Messages: 17 Topic information: Topic: /chatter | Type: std_msgs/msg/String | Count: 17 | Serialization Format: cdr
This gives you a few useful info:
- Name of the file(s) where the messages are stored + size and type of the database (here sqlite3).
- Duration: simply how long you let the
ros2 bag recordcommand run before pressing CTRL+C.
- Start and End time: when you created the bag.
- Messages: number of total messages in this bag.
- Topic information: for each recorded topic, you’ll get the topic name, topic type (interface), and number of messages for this topic that were recorded and saved inside the bag.
Here’s what you’ll see if you recorded multiple topics:
$ ros2 bag info my_bag3 Files: my_bag3_0.db3 Bag size: 25.7 KiB Storage id: sqlite3 Duration: 10.47s Start: Jul 1 2020 15:40:52.483 (1593610852.483) End: Jul 1 2020 15:41:02.531 (1593610862.531) Messages: 32 Topic information: Topic: /chatter | Type: std_msgs/msg/String | Count: 11 | Serialization Format: cdr Topic: /parameter_events | Type: rcl_interfaces/msg/ParameterEvent | Count: 0 | Serialization Format: cdr Topic: /rosout | Type: rcl_interfaces/msg/Log | Count: 21 | Serialization Format: cdr
This gives you a good idea of what’s inside. Here, we recorded for a little bit more than 10 seconds, and we have 11 messages from /chatter + 21 messages from /rosout (logs) + 0 message from /parameter_events (because there were no parameter event).
ros2 bag play – Replay data exactly like it was first published
To replay a bag, use: “ros2 bag play” + name of the folder (bag).
$ ros2 bag play my_bag3/ [INFO] [1593612209.740592952] [rosbag2_storage]: Opened database 'my_bag3//my_bag3_0.db3' for READ_ONLY.
ros2 bag record command created subscribers for each topic, the
ros2 bag play command will create a publisher for each recorded topic.
All the messages will be played exactly like they were recorded, with the same data and same time between messages.
What you can do is to stop the talker node you’ve launched at the beginning, and make sure you have no other node running. Then, replay the bag, open a new terminal, and see the data with
ros2 topic echo.
$ ros2 topic echo /chatter data: 'Hello World: 1297' --- data: 'Hello World: 1298' --- data: 'Hello World: 1299' --- data: 'Hello World: 1300' ---
The 3 topics are all here, and messages will be published on the topic just like when they were recorded, as you can see with /chatter.
And then, when all messages from the bag have been published, the bag will stop all its publishers and exit. So, if you recorded for 10.47 seconds, then the bag will publish messages for 10.47 seconds, no more. After that you can replay the bag again if you want to.
Conclusion on ROS2 bags
ROS2 bags is a powerful feature of ROS2. Thanks to the
ros2 bag command line tool you can easily use it with 3 simple commands: record, info and play.
Bags will allow you to save time on development, and possibly get better samples for testing your algorithms.
Final tip: make sure you record topics for long enough so that when you play the bag, you have the time to run your other nodes and your experiment.