Replaying rosbag2
Overview

Method 1: Collect data and generate map information simultaneously.
Method 2 separates data collection from map information generation, achieving decoupling and thus greater flexibility. The same set of data can be processed with different algorithms — in short, it's very flexible.
The process of saving can also be called serialization (converting to a disk file).
Persistence is generally called recording (serialization).
Reading is generally called playback (deserialization).

When saving, files can also be split into volumes, meaning each file can have a maximum size. If that size is exceeded, a new file is created to continue saving (similar to splitting a compressed file into volumes).
In that case, storing too much data would make it too slow to open all at once, so we can open it in segments.


Must depend on rosbag2_cpp or rosbag2_py
We also depend on geometry_msgs, because the data we need to serialize is the velocity command from this package.
ros2 pkg create cpp02_rosbag --build-type ament_cmake --dependencies rclcpp rosbag2_cpp geometry_msgs --node-name cpp01_writer
rosbag2 command-line tools

Generally, ROSBAG2 can be used in two ways: command-line tools and coding. The command-line tools are quite feature-rich and sufficient for most needs.
View the help documentation: ros2 bag -h

There are mainly 6 instructions.



You can check the detailed usage of record.

The record is used to serialize messages. (Recording)
play is used to deserialize messages. (playback)
The info command is used to output relevant information about a bag file, such as how many messages it contains, the recording start and end times, and the duration.
Reindex rebuilds the bag file and can modify the bag source data file.
list is used to output the available plugins in rosbag2 (advanced application).
We can use this to change the file extension of a bag file, or merge multiple bag files into a single file.

Open the turtlesim node and the keyboard control node for the turtle.
We use the keyboard to control the little turtle, and then serialize the velocity commands through rosbag2.
Then we shut down the two nodes, restart the turtle node, and this time, instead of controlling it via the keyboard, we make the turtle move by playing a bag file.
The record command must be followed by a list of topics, but in the operation below, only one topic is used.


Then use output to write the serialized file to a disk directory.

Change directory into the folder where you want to save the bag file, then enter the record command followed by the topic name, and then -o plus the bag file name. You can also choose not to rename the bag file, in which case the default name will be used. The default name is based on the year, month, and day.
This means recording has already started.


Press Ctrl + C to stop. A prompt will appear saying it is writing messages to the bag, which will take a moment.


This yaml file is the source data file.
db3 is an SQLite database, which is a commonly used database on mobile devices (such as smartphones).
This database stores the recorded data.
## rosbag2 C++ Case Analysis and Framework Setup


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})
rosbag2 C++ Recording Data
/*
需求:录制 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;
}

This is a relative directory, located in the workspace directory.

Before writing data, you must first create a subscriber, which needs to establish a callback function.

Callback function entry parameters, with the message type using the entry parameters of the write function.

Here, use a slash instead of a colon, because the entry is of type string.



Create the turtle node.

Start the writer node

Run the little turtle
After running for a while, shut down all nodes.

The file was successfully generated.
Verify whether the recording file was successful.
Before verification, first create a turtle node without creating a control node.
ros2 bag play src/cpp02_rosbag/my_bag

You can see the turtle moving normally. Playback successful!

If you have already generated my_bag once, trying to generate it again will show that it cannot be overwritten.
The solution is to make my_bag dynamic by adding a timestamp or naming it directly based on its function.
rosbag2 C++ reading data
/*
需求:读取 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;
}


Compile

This shows it can read out several pieces of information. It can read out 8.

Exactly 8.