目标:将数据从您自己的 C++ 节点记录到一个包中。
教程级别:高级
时间:20 分钟
目录
背景
先决条件
任务
1. 创建一个包
2. 编写 C++ 节点
3. 建立并运行
4. 从节点记录合成数据
5. 从可执行文件记录合成数据
摘要
背景
rosbag2
不仅提供 ros2 bag
命令行工具,还提供了一个 C++ API,用于从您自己的源代码中读取和写入 bag 文件。这使您可以订阅一个主题,并在对数据进行任何其他处理的同时,将接收到的数据保存到 bag 文件中。
先决条件
您应该在常规的 ROS 2 设置中安装 rosbag2
软件包。
如果您已经从 Linux 上的 Debian 软件包安装,它可能会默认安装。如果没有,您可以使用此命令安装它。
sudo apt install ros-jazzy-rosbag2
本教程讨论了如何使用 ROS 2 包,包括从终端使用。您应该已经完成了基本的 ROS 2 包教程。
任务
1. 创建一个包
打开一个新的终端并且初始化您的 ROS 2 安装,这样 ros2
命令就会生效。
导航到在上一个教程中创建的 ros2_ws
目录。导航到 ros2_ws/src
目录并创建一个新包:
ros2 pkg create --build-type ament_cmake --license Apache-2.0 bag_recorder_nodes --dependencies example_interfaces rclcpp rosbag2_cpp std_msgs
您的终端将返回一条消息,验证包 bag_recorder_nodes
及其所有必要文件和文件夹的创建。 --dependencies
参数将自动添加必要的依赖行到 package.xml
和 CMakeLists.txt
。在这种情况下,该包将使用 rosbag2_cpp
包以及 rclcpp
包。后续部分的教程还需要依赖 example_interfaces
包。
1.1 更新 package.xml
因为您在创建包时使用了 --dependencies
选项,您无需手动将依赖项添加到 package.xml
或 CMakeLists.txt
。但是,一如既往,请确保将描述、维护者电子邮件和姓名以及许可信息添加到 package.xml
。
<description>C++ bag writing tutorial</description>
<maintainer email="cxy@126.com">cxy</maintainer>
<license>Apache-2.0</license>
编写 C++ 节点
在 ros2_ws/src/bag_recorder_nodes/src
目录中,创建一个名为 simple_bag_recorder.cpp
的新文件,并将以下代码粘贴到其中。
#include <rclcpp/rclcpp.hpp> // 包含 ROS 2 的 C++ 客户端库
#include <std_msgs/msg/string.hpp> // 包含 std_msgs/String 消息类型
#include <rosbag2_cpp/writer.hpp> // 包含 rosbag2_cpp 的 Writer 类
class SimpleBagRecorder : public rclcpp::Node // 定义一个继承自 rclcpp::Node 的类,名为 SimpleBagRecorder
{
public:
SimpleBagRecorder() // 类的构造函数
: Node("simple_bag_recorder") // 调用父类构造函数,初始化节点名称为 "simple_bag_recorder"
{
writer_ = std::make_unique<rosbag2_cpp::Writer>(); // 创建一个 rosbag2_cpp::Writer 对象的唯一指针
writer_->open("my_bag"); // 打开一个名为 "my_bag" 的 rosbag 文件
auto subscription_callback_lambda = [this](std::shared_ptr<rclcpp::SerializedMessage> msg){
// 定义一个 lambda 回调函数,当接收到消息时调用
rclcpp::Time time_stamp = this->now(); // 获取当前时间戳
writer_->write(msg, "chatter", "std_msgs/msg/String", time_stamp); // 将消息写入 rosbag 文件
};
subscription_ = create_subscription<std_msgs::msg::String>(
// 创建一个订阅者,订阅 "chatter" 话题,队列大小为 10,并指定回调函数
"chatter", 10, subscription_callback_lambda);
}
private:
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_; // 定义一个订阅者指针
std::unique_ptr<rosbag2_cpp::Writer> writer_; // 定义一个 rosbag2_cpp::Writer 的智能指针
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv); // 初始化 ROS 2
rclcpp::spin(std::make_shared<SimpleBagRecorder>()); // 创建 SimpleBagRecorder 节点并进入事件循环
rclcpp::shutdown(); // 关闭 ROS 2
return 0; // 返回 0 表示程序正常结束
}
检查代码 2.1
顶部的 #include
语句是包依赖项。请注意, rosbag2_cpp
包中的头文件包含了处理包文件所需的函数和结构。
在类构造函数中,我们首先创建将用于写入包的写入器对象。
writer_ = std::m