【ROS2】高级:从包文件读取 (C++)

目标:在不使用 CLI 的情况下从包中读取数据。

 教程级别:高级

 时间:10 分钟

 目录

  •  背景

  •  先决条件

  •  任务

    • 1 创建一个包裹

    • 2 编写 C++ 读取器

    • 3 构建并运行

  •  摘要

 背景

rosbag2 不仅提供 ros2 bag 命令行工具。它还提供了一个 C++ API,用于从您自己的源代码中读取和写入包。这使您可以在不播放包的情况下读取包中的内容,这有时会很有用

 先决条件

您应该在常规的 ROS 2 设置中安装 rosbag2 软件包。

如果您需要安装 ROS 2,请查看安装说明。

你应该已经完成了基本的 ROS 2 包教程https://docs.ros.org/en/jazzy/Tutorials/Beginner-CLI-Tools/Recording-And-Playing-Back-Data/Recording-And-Playing-Back-Data.html ,我们将使用你在那里创建的 subset 包。

 任务

1 创建一个包裹

打开一个新的终端并且初始化您的 ROS 2 安装,这样 ros2 命令就会生效。

在新的或现有的工作区中,导航到 src 目录并创建一个新包:

ros2 pkg create --build-type ament_cmake --license Apache-2.0 bag_reading_cpp --dependencies rclcpp rosbag2_transport turtlesim

您的终端将返回一条消息,验证您的包 bag_reading_cpp 及其所有必要的文件和文件夹的创建。 --dependencies 参数将自动添加必要的依赖行到 package.xml 和 CMakeLists.txt 。在这种情况下,该包将使用 rosbag2_transport 包以及 rclcpp 包。要处理自定义的 turtlesim 消息,还需要依赖 turtlesim 包。

 1.1 更新 package.xml 

因为您在创建包时使用了 --dependencies 选项,您无需手动将依赖项添加到 package.xml 或 CMakeLists.txt 。但是,一如既往,请确保将描述、维护者电子邮件和姓名以及许可信息添加到 package.xml 。

<description>C++ bag reading tutorial</description><maintainer email="cxy@126.com">cxy</maintainer><license>Apache-2.0</license>

2 编写 C++ 读取器

在你的包的 src 目录中,创建一个名为 simple_bag_reader.cpp 的新文件,并将以下代码粘贴到其中。

#include <chrono>  // 用于时间处理的库
#include <functional>  // 用于函数对象的库
#include <iostream>  // 用于输入输出流的库
#include <memory>  // 用于智能指针的库
#include <string>  // 用于字符串处理的库#include "rclcpp/rclcpp.hpp"  // ROS 2 的 C++ 客户端库
#include "rclcpp/serialization.hpp"  // ROS 2 的序列化库
#include "rosbag2_transport/reader_writer_factory.hpp"  // 用于读写 rosbag2 的工厂
#include "turtlesim/msg/pose.hpp"  // turtlesim 包中的 Pose 消息类型using namespace std::chrono_literals;  // 使用 chrono 的字面量class PlaybackNode : public rclcpp::Node  // 定义 PlaybackNode 类,继承自 rclcpp::Node
{public:PlaybackNode(const std::string & bag_filename)  // 构造函数,接受一个 bag 文件名作为参数: Node("playback_node")  // 调用基类构造函数,设置节点名称为 "playback_node"{publisher_ = this->create_publisher<turtlesim::msg::Pose>("/turtle1/pose", 10);  // 创建一个发布者,发布到 "/turtle1/pose" 话题,队列大小为 10timer_ = this->create_wall_timer(100ms,  // 创建一个定时器,每 100 毫秒触发一次[this](){return this->timer_callback();}  // 定时器的回调函数);rosbag2_storage::StorageOptions storage_options;  // 创建存储选项实例storage_options.uri = bag_filename;  // 设置存储选项的 URI 为 bag 文件名reader_ = rosbag2_transport::ReaderWriterFactory::make_reader(storage_options);  // 通过工厂创建一个 rosbag2 读取器reader_->open(storage_options);  // 打开读取器}private:void timer_callback()  // 定时器的回调函数
{while (reader_->has_next()) {  // 如果读取器有下一条消息rosbag2_storage::SerializedBagMessageSharedPtr msg = reader_->read_next();  // 读取下一条消息if (msg->topic_name != "/turtle1/pose") {  // 如果消息的主题不是 "/turtle1/pose"continue;  // 跳过本次循环}rclcpp::SerializedMessage serialized_msg(*msg->serialized_data);  // 创建一个序列化消息turtlesim::msg::Pose::SharedPtr ros_msg = std::make_shared<turtlesim::msg::Pose>();  // 创建一个 Pose 消息的共享指针serialization_.deserialize_message(&serialized_msg, ros_msg.get());  // 反序列化消息publisher_->publish(*ros_msg);  // 发布消息std::cout << '(' << ros_msg->x << ", " << ros_msg->y << ")\n";  // 输出消息的位置信息break;  // 退出循环}}rclcpp::TimerBase::SharedPtr timer_;  // 定时器的共享指针rclcpp::Publisher<turtlesim::msg::Pose>::SharedPtr publisher_;  // 发布者的共享指针rclcpp::Serialization<turtlesim::msg::Pose> serialization_;  // 序列化实例std::unique_ptr<rosbag2_cpp::Reader> reader_;  // 读取器的唯一指针
};int main(int argc, char ** argv)  // 主函数
{if (argc != 2) {  // 如果参数数量不等于 2std::cerr << "Usage: " << argv[0] << " <bag>" << std::endl;  // 输出用法提示return 1;  // 返回错误码 1}rclcpp::init(argc, argv);  // 初始化 ROS 2rclcpp::spin(std::make_shared<PlaybackNode>(argv[1]));  // 创建 PlaybackNode 实例并进入事件循环rclcpp::shutdown();  // 关闭 ROS 2return 0;  // 返回 0
}
2.1 检查代码 

顶部的 #include 语句是包依赖项。请注意, rosbag2_transport 包中的头文件包含了处理包文件所需的函数和结构。

下一行创建将从包文件读取并回放数据的节点。

class PlaybackNode : public rclcpp::Node

现在,我们可以创建一个以 10 赫兹运行的定时器回调。我们的目标是在每次运行回调时向 /turtle1/pose 主题重放一条消息。请注意,构造函数将路径作为参数传递给包文件。

public:PlaybackNode(const std::string & bag_filename): Node("playback_node"){publisher_ = this->create_publisher<turtlesim::msg::Pose>("/turtle1/pose", 10);timer_ = this->create_wall_timer(100ms,[this](){return this->timer_callback();});

我们还在构造函数中打开bag。 rosbag2_transport::ReaderWriterFactory 是一个类,可以根据存储选项构造压缩或未压缩的读取器或写入器

rosbag2_storage::StorageOptions storage_options;
storage_options.uri = bag_filename;
reader_ = rosbag2_transport::ReaderWriterFactory::make_reader(storage_options);
reader_->open(storage_options);

现在,在我们的计时器回调中,我们循环遍历包中的消息,直到读取到从我们所需主题记录的消息。请注意,序列化消息除了主题名称外还有时间戳元数据。

void timer_callback()
{while (reader_->has_next()) {rosbag2_storage::SerializedBagMessageSharedPtr msg = reader_->read_next();if (msg->topic_name != "/turtle1/pose") {continue;}

然后,我们从刚刚读取的序列化数据构建一个 rclcpp::SerializedMessage 对象。此外,我们需要创建一个 ROS 2 反序列化消息,该消息将保存我们的反序列化结果。然后,我们可以将这两个对象传递给 rclcpp::Serialization::deserialize_message 方法。

rclcpp::SerializedMessage serialized_msg(*msg->serialized_data);
turtlesim::msg::Pose::SharedPtr ros_msg = std::make_shared<turtlesim::msg::Pose>();serialization_.deserialize_message(&serialized_msg, ros_msg.get());

最后,我们发布反序列化的消息并将 xy 坐标打印到终端。我们还会跳出循环,以便在下一个计时器回调期间发布下一条消息。

publisher_->publish(*ros_msg);std::cout << '(' << ros_msg->x << ", " << ros_msg->y << ")\n";break;
}

我们还必须声明在整个节点中使用的私有变量。

rclcpp::TimerBase::SharedPtr timer_;rclcpp::Publisher<turtlesim::msg::Pose>::SharedPtr publisher_;rclcpp::Serialization<turtlesim::msg::Pose> serialization_;std::unique_ptr<rosbag2_cpp::Reader> reader_;
};

最后,我们创建主函数,该函数将检查用户是否传递了包文件路径的参数并启动我们的节点。

int main(int argc, char ** argv)
{if (argc != 2) {std::cerr << "Usage: " << argv[0] << " <bag>" << std::endl;return 1;}rclcpp::init(argc, argv);rclcpp::spin(std::make_shared<PlaybackNode>(argv[1]));rclcpp::shutdown();return 0;
}
 2.2 添加可执行文件

现在打开 CMakeLists.txt 文件。

在包含 find_package(rosbag2_transport REQUIRED) 的依赖块下面,添加以下代码行。

add_executable(simple_bag_reader src/simple_bag_reader.cpp)
ament_target_dependencies(simple_bag_reader rclcpp rosbag2_transport turtlesim)install(TARGETSsimple_bag_readerDESTINATION lib/${PROJECT_NAME}
)

3. 构建并运行

导航回到工作区的根目录并构建您的新包。

colcon build --packages-select bag_reading_cpp

接下来,获取安装文件

source install/setup.bash

现在运行脚本。确保将 /path/to/subset 替换为 subset 包的路径。

ros2 run bag_reading_cpp simple_bag_reader ~/ros2_ws/subset

你应该看到乌龟的 (x, y) 坐标打印到控制台。

bd7154d8099209f8be0899bd06e798c5.png

摘要

你创建了一个读取包中数据的 C++可执行文件。然后你编译并运行了该可执行文件,它将包中的一些信息打印到控制台。

附录:

bbfe199a26286b5703defc2e18d379c6.png

记录的包内容:  ~/ros2_ws/subset/metadata.yaml

8a07cd020897b5c8f6c77d4a2ff4a23e.png

rosbag2_bagfile_information:version: 9storage_identifier: mcapduration:nanoseconds: 8911648921starting_time:nanoseconds_since_epoch: 1721184333150957762message_count: 640topics_with_message_count:- topic_metadata:name: /turtle1/cmd_veltype: geometry_msgs/msg/Twistserialization_format: cdroffered_qos_profiles:- history: unknowndepth: 0reliability: reliabledurability: volatiledeadline:sec: 9223372036nsec: 854775807lifespan:sec: 9223372036nsec: 854775807liveliness: automaticliveliness_lease_duration:sec: 9223372036nsec: 854775807avoid_ros_namespace_conventions: falsetype_description_hash: RIHS01_9c45bf16fe0983d80e3cfe750d6835843d265a9a6c46bd2e609fcddde6fb8d2amessage_count: 82- topic_metadata:name: /turtle1/posetype: turtlesim/msg/Poseserialization_format: cdroffered_qos_profiles:- history: unknowndepth: 0reliability: reliabledurability: volatiledeadline:sec: 9223372036nsec: 854775807lifespan:sec: 9223372036nsec: 854775807liveliness: automaticliveliness_lease_duration:sec: 9223372036nsec: 854775807avoid_ros_namespace_conventions: falsetype_description_hash: RIHS01_739beba26bcba6920404ba722b7b8321348512f92ea5be235c47251940dd8aa9message_count: 558compression_format: ""compression_mode: ""relative_file_paths:- subset_0.mcapfiles:- path: subset_0.mcapstarting_time:nanoseconds_since_epoch: 1721184333150957762duration:nanoseconds: 8911648921message_count: 640custom_data: ~ros_distro: jazzy

记录多个主题:

ros2 bag record -o subset /turtle1/cmd_vel /turtle1/pose

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3249800.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

基于JAVA+SpringBoot+uniapp的心理小程序(小程序版本)

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、SpringCloud、Layui、Echarts图表、Nodejs、爬…

5G mmWave PAAM 开发平台

Avnet-Fujikura-AMD 5G 毫米波相控阵天线模块开发平台 Avnet 和 Fujikura 为毫米波频段创建了一个领先的 5G FR2 相控阵天线开发平台。该平台使开发人员能够使用 AMD Xilinx 的 Zynq UltraScale™ RFSoC Gen3 和 Fujikura 的 FutureAcess™ 相控阵天线模块 (PAAM) 快速创建和制…

上海理工大学24计算机考研考情分析!初复试分值比55:45,复试逆袭人数不算多!

上海理工大学&#xff08;University of Shanghai for Science and Technology&#xff09;&#xff0c;位于上海市&#xff0c;是一所以工学为主&#xff0c;工学、理学、经济学、管理学、文学、法学、艺术学等多学科协调发展的应用研究型大学&#xff1b;是上海市属重点建设大…

Amisco供应汽车线圈与Husco是一家私营公司高性能液压和机电部件在汽车和非公路应用的组件设计和制造方面拥有超过 75 年的经验10于年的合作

Amisco和Husco在汽车线圈和高性能液压和机电部件的设计和制造方面合作已经超过10年。 Amisco是一家供应汽车线圈的公司&#xff0c;而Husco则专注于高性能液压和机电部件的设计和制造。 这两家公司在汽车和非公路应用领域拥有超过75年的经验。通过合作&#xff0c;Amisco和Husc…

【开源 Mac 工具推荐之 2】洛雪音乐(lx-music-desktop):免费良心的音乐平台

旧版文章&#xff1a;【macOS免费软件推荐】第6期&#xff1a;洛雪音乐 Note&#xff1a;本文在旧版文章的基础上&#xff0c;新更新展示了一些洛雪音乐的新功能&#xff0c;并且描述更为详细。 简介 洛雪音乐&#xff08;GitHub 名&#xff1a;lx-music-desktop &#xff09;…

将iPad 作为Windows电脑副屏的几种方法(二)

将iPad 作为Windows电脑副屏的几种方法&#xff08;二&#xff09; 1. 前言2. EV 扩展屏2.1 概述2.2 下载、安装、连接教程2.3 遇到的问题和解决方法2.3.1 平板连接不上电脑 3. Twomon SE3.1 概述3.2 下载安装教程 4. 多屏中心&#xff08;GlideX&#xff09;4.1 概述4.2 下载安…

LeetCode 算法:单词搜索 c++

原题链接&#x1f517;&#xff1a;单词搜索 难度&#xff1a;中等⭐️⭐️ 题目 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通…

解决npm install(‘proxy‘ config is set properly. See: ‘npm help config‘)失败问题

摘要 重装电脑系统后&#xff0c;使用npm install初始化项目依赖失败了&#xff0c;错误提示&#xff1a;‘proxy’ config is set properly…&#xff0c;具体的错误提示如下图所示&#xff1a; 解决方案 经过报错信息查询解决办法&#xff0c;最终找到了两个比较好的方案&a…

vscode+wsl2+anaconda环境的配置与使用

目录 下载anaconda Anaconda使用参考 vscodeubuntuanaconda 先用vscode连接本地ubuntu。 如果没有安装wsl2与ubuntu&#xff0c;可点击下面的链接。 问题&#xff1a;wsl install 无法解析服务器 成功记录&#xff1a; 在vscode终端用ubuntu安装anaconda。 创建pytho…

学习008-02-01 Define the Data Model and Set the Initial Data(定义数据模型并设置初始数据)

Define the Data Model and Set the Initial Data&#xff08;定义数据模型并设置初始数据&#xff09; This section explains how to design a business model (database) for an application built with Cross-Platform .NET App UI (XAF) and Entity Framework Core. 本节…

Python简化命令行界面库之fire使用详解

概要 在开发命令行工具时,开发者通常需要编写大量代码来解析命令行参数,这既耗时又容易出错。Python Fire 是 Google 开源的一个库,旨在简化命令行界面的开发。它可以将任何 Python 对象自动生成一个命令行界面,从而大大减少了开发时间和代码复杂度。本文将详细介绍 Pytho…

HiFi-GAN——基于 GAN 的声码器,能在单 GPU 上生成 22 KHz 音频

拟议的 HiFiGAN 可从中间表征生成原始波形 源码地址&#xff1a;https://github.com/NVIDIA/DeepLearningExamples 论文地址&#xff1a;https://arxiv.org/pdf/2010.05646.pdf 研究要点包括 **挑战&#xff1a;**基于 GAN 的语音波形生成方法在质量上不及自回归模型和基于流…

排序系列 之 选择排序

&#xff01;&#xff01;&#xff01;排序仅针对于数组哦本次排序是按照升序来的哦 介绍 快速排序英文名为SelectSort从数组中找到最小的放到前边 基本思路 1、默认待排序数组中第一个作为最小值2、找待排序数组&#xff08;注意不是整个数组哦&#xff09;中真正的最小值3…

Web前端Promise

Promise介绍与使用 Promise是什么&#xff1f; 1.抽象表达&#xff1a; Promise是一门新的技术&#xff08;ES6规范&#xff09;Promise是JS中进行异步编程的新解决方案备注&#xff1a;旧方案是单纯使用回调函数 2.具体表达&#xff1a; 从语法上来说&#xff1a;Promise…

基于语音识别的会议记录系统

文章目录 核心功能页面展示使用技术方案功能结构设计数据库表展示 核心功能页面展示 视频展示功能 1.创建会议 在开始会议之前需要管理员先创建一个会议&#xff0c;为了能够快速开始会议&#xff0c;仅需填写会议的名称、会议举办小组、会议背景等简要会议信息即可成功创建。…

Apache BookKeeper 一致性协议解析

导语 Apache Pulsar 是一个多租户、高性能的服务间消息传输解决方案&#xff0c;支持多租户、低延时、读写分离、跨地域复制&#xff08;GEO replication&#xff09;、快速扩容、灵活容错等特性。Pulsar 存储层依托于 BookKeeper 组件&#xff0c;所以本文简单探讨一下 BookK…

利用patch-package补丁,解决H5预览PDF时电子签章不显示问题

利用patch-package补丁&#xff0c;解决H5预览PDF时电子签章不显示问题 一、问题描述 在生产环境中&#xff0c;遇到了一个紧急的技术问题&#xff1a;用户在移动端H5页面上查看电子票时&#xff0c;PDF文件预览功能正常&#xff0c;但其中的电子签章未能正常显示。这一问题直…

人工智能算法工程师高级课程1-单类目标识别之人脸检测识别技术MTCNN模型介绍与代码详解

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师高级课程1-单类目标识别之人脸检测识别技术MTCNN模型介绍与代码详解。本文深入探讨了基于PyTorch的人脸检测与识别技术&#xff0c;详细介绍了MTCNN模型、Siamese network以及center loss、softm…

【操作系统】文件管理——文件共享与保护,文件系统的结构(个人笔记)

学习日期&#xff1a;2024.7.18 内容摘要&#xff1a;文件共享&#xff0c;文件保护&#xff0c;文件系统的层级结构和全局结构&#xff0c;虚拟文件系统 文件共享 操作系统提供的文件共享功能&#xff0c;可以让多个用户共享使用同一个文件。文件共享和文件复制是不一样的&a…

mac docker no space left on device

mac 上 docker 拉取镜像报错 Error response from daemon: write /var/lib/docker/tmp/docker-export-3995807640/b8464f52498789c4ebbc063d508f04e8d2586567fbffa475e3cd9afd3c5a7cf2/layer.tar: no space left on device解决&#xff1a; 增加 docker 虚拟磁盘大小。如下图