Robot Operating System——自定义订阅/发布的消息结构

news2025/1/11 6:05:42

大纲

  • 初始化环境
  • 生成自定义消息的工程
    • 创建包
    • 自定义消息
    • package.xml
      • 完整文件
    • CMakeLists.txt
      • 完整文件
    • 编译
    • 注册
  • 使用自定义消息的工程
    • 创建包
    • 代码
    • CMakeLists.txt
    • 编译
    • 运行
  • 工程地址
  • 参考资料

在之前的案例中我们订阅/发布之间传递的消息都是ROS2的标准类型。本文我们将讨论如何自定义一个消息类型。

初始化环境

在《Robot Operating System——深度解析自动隐式加载动态库的运行模式》一文中,我们展现了ROS2可执行文件的链接指令。可以看到它依赖了很多ROS2环境相关的动态库,所以我们在创建工程之前也要初始化环境。

source /opt/ros/jazzy/setup.bash

关于环境的安装可以参见《Robot Operating System——Ubuntu上以二进制形式安装环境》。

生成自定义消息的工程

创建包

ros2 pkg create --build-type ament_cmake --license Apache-2.0 custom_msg

在这里插入图片描述
其目录结构如下
在这里插入图片描述

自定义消息

我们使用《Robot Operating System——导航卫星(如 GPS)状态信息》中介绍的sensor_msgs::msg::NavSatStatus、《Robot Operating System——带有协方差矩阵的三维空间中的位姿(位置和方向)》中介绍的geometry_msgs::msg::PoseWithCovariance以及《Robot Operating System——std_msgs消息类型说明和使用》中介绍的std_msgs::msg::Bool来组织一个自定义消息体。
我们创建一个目录,叫做msg,然后在这个目录下创建文件NavSatPoseBool.msg,填入以下内容

sensor_msgs/NavSatStatus nav
geometry_msgs/PoseWithCovariance pose
std_msgs/Bool boolvalue

此时目录结构如下
在这里插入图片描述

package.xml

在该文件中新增如下内容

  <depend>sensor_msgs</depend>
  <depend>geometry_msgs</depend>
  <depend>std_msgs</depend>
  <buildtool_depend>rosidl_default_generators</buildtool_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>
  <member_of_group>rosidl_interface_packages</member_of_group>

sensor_msgs、geometry_msgs和std_msgs是消息体中用的三种ROS2提供的基础消息类型;
rosidl_default_generators用于将上述msg文件生成代码;
rosidl_default_runtime是运行时依赖;
后三者是一定要加的,前面的三个根据自定义消息的类型酌情添加。

完整文件

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>custom_msg</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="f304646673@gmail.com">fangliang</maintainer>
  <license>Apache-2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>sensor_msgs</depend>
  <depend>geometry_msgs</depend>
  <depend>std_msgs</depend>
  <buildtool_depend>rosidl_default_generators</buildtool_depend>
  <exec_depend>rosidl_default_runtime</exec_depend>
  <member_of_group>rosidl_interface_packages</member_of_group>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

CMakeLists.txt

新增如下内容

find_package(sensor_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/NavSatPoseBool.msg"
  DEPENDENCIES sensor_msgs geometry_msgs std_msgs 
)

DEPENDENCIES 中添加的是我们自定义消息的基础类型。

完整文件

cmake_minimum_required(VERSION 3.8)
project(custom_msg)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

find_package(sensor_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/NavSatPoseBool.msg"
  DEPENDENCIES sensor_msgs geometry_msgs std_msgs
)


if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()

编译

colcon build --packages-select custom_msg

在这里插入图片描述

注册

source install/setup.sh 

经过注册后,我们可以在ROS2中查看这个自定义消息

ros2 interface show custom_msg/msg/NavSatPoseBool

在这里插入图片描述

使用自定义消息的工程

创建包

ros2 pkg create --build-type ament_cmake --license Apache-2.0 custom_msg_topic --dependencies rclcpp custom_msg

在这里插入图片描述
–dependencies参数可以帮我们在package.xml和CMakeLists.txt中自动添加相应依赖。此时我们添加上一步创建的custom_msg。

代码

我们在src目录下创建talker.cpp和listener.cpp两个文件,然后分别填入下面的代码:

// Copyright 2014 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <chrono>
#include <cstdio>
#include <memory>
#include <utility>

#include "rclcpp/rclcpp.hpp"

#include "std_msgs/msg/string.hpp"

#include "custom_msg/msg/nav_sat_pose_bool.hpp"

using namespace std::chrono_literals;

class Talker : public rclcpp::Node
{
public:
  explicit Talker() : Node("talker")
  {
    // Create a function for when messages are to be sent.
    setvbuf(stdout, NULL, _IONBF, BUFSIZ);
    auto publish_message =
      [this]() -> void
      {
        msg_ = std::make_unique<custom_msg::msg::NavSatPoseBool>();
        msg_->nav.service = 1;
        msg_->nav.status = 2;
        msg_->pose.pose.position.x = 1.0;
        msg_->pose.pose.position.y = 2.0;
        msg_->pose.pose.position.z = 3.0;
        msg_->pose.pose.orientation.x = 0.0;
        msg_->pose.pose.orientation.y = 0.0;
        msg_->pose.pose.orientation.z = 0.0;
        msg_->pose.pose.orientation.w = 1.0;
        msg_->boolvalue.data = false;

        RCLCPP_INFO(this->get_logger(), "Publishing: [%s]", serializeNavSatPoseBool(*msg_).c_str());

        // Put the message into a queue to be processed by the middleware.
        // This call is non-blocking.
        pub_->publish(std::move(msg_));
      };
    // Create a publisher with a custom Quality of Service profile.
    // Uniform initialization is suggested so it can be trivially changed to
    // rclcpp::KeepAll{} if the user wishes.
    // (rclcpp::KeepLast(7) -> rclcpp::KeepAll() fails to compile)
    rclcpp::QoS qos(rclcpp::KeepLast{7});
    pub_ = this->create_publisher<custom_msg::msg::NavSatPoseBool>("chatter", qos);

    // Use a timer to schedule periodic message publishing.
    timer_ = this->create_wall_timer(1s, publish_message);
  }

  private :std::string serializeNavSatPoseBool(const custom_msg::msg::NavSatPoseBool &msg) {
    std::ostringstream oss;
    oss << msg.nav.service << " " 
        << msg.nav.status << " " 
        << msg.pose.pose.position.x << " " 
        << msg.pose.pose.position.y << " " 
        << msg.pose.pose.position.z << " " 
        << msg.pose.pose.orientation.x << " " 
        << msg.pose.pose.orientation.y << " " 
        << msg.pose.pose.orientation.z << " " 
        << msg.pose.pose.orientation.w << " " 
        << msg.boolvalue.data;

    return oss.str();
  }

private:
  size_t count_ = 1;
  
  std::unique_ptr<custom_msg::msg::NavSatPoseBool> msg_;
  rclcpp::Publisher<custom_msg::msg::NavSatPoseBool>::SharedPtr pub_;
  rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<Talker>());
  rclcpp::shutdown();
  return 0;
}
// Copyright 2014 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "rclcpp/rclcpp.hpp"

#include "std_msgs/msg/string.hpp"

#include "custom_msg/msg/nav_sat_pose_bool.hpp"
#include <sstream>
#include <string>

class Listener : public rclcpp::Node
{
public:
  explicit Listener() : Node("listener")
  {
    // Create a callback function for when messages are received.
    // Variations of this function also exist using, for example UniquePtr for zero-copy transport.
    setvbuf(stdout, NULL, _IONBF, BUFSIZ);
    auto callback =
      [this](custom_msg::msg::NavSatPoseBool::ConstSharedPtr msg) -> void
      {
        RCLCPP_INFO(this->get_logger(), "I heard: [%s]", serializeNavSatPoseBool(*msg).c_str());
      };
    // Create a subscription to the topic which can be matched with one or more compatible ROS
    // publishers.
    // Note that not all publishers on the same topic with the same type will be compatible:
    // they must have compatible Quality of Service policies.
    sub_ = create_subscription<custom_msg::msg::NavSatPoseBool>("chatter", 10, callback);
  }

  private :std::string serializeNavSatPoseBool(const custom_msg::msg::NavSatPoseBool &msg) {
    std::ostringstream oss;
    oss << msg.nav.service << " " 
        << msg.nav.status << " " 
        << msg.pose.pose.position.x << " " 
        << msg.pose.pose.position.y << " " 
        << msg.pose.pose.position.z << " " 
        << msg.pose.pose.orientation.x << " " 
        << msg.pose.pose.orientation.y << " " 
        << msg.pose.pose.orientation.z << " " 
        << msg.pose.pose.orientation.w << " " 
        << msg.boolvalue.data;

    return oss.str();
  }

private:
  rclcpp::Subscription<custom_msg::msg::NavSatPoseBool>::SharedPtr sub_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<Listener>());
  rclcpp::shutdown();
  return 0;
}

CMakeLists.txt

然后分别编译这两个文件成为可执行文件。

add_executable(talker src/talker.cpp)
ament_target_dependencies(talker rclcpp custom_msg)

add_executable(listener src/listener.cpp)
ament_target_dependencies(listener rclcpp custom_msg)

编译

colcon build --packages-select custom_msg_topic

在这里插入图片描述

运行

在新的终端中,需要先初始化环境

source custom_msg/install/setup.sh 

然后执行listen和talker。
在这里插入图片描述
在这里插入图片描述

工程地址

  • https://github.com/f304646673/ros2-examples/tree/main/custom_msg
  • https://github.com/f304646673/ros2-examples/tree/main/custom_msg_topic

参考资料

  • https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries/Custom-ROS2-Interfaces.html

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

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

相关文章

【IoTDB 线上小课 06】列式写入=时序数据写入性能“利器”?

【IoTDB 视频小课】更新来啦&#xff01;今天已经是第六期了~ 关于 IoTDB&#xff0c;关于物联网&#xff0c;关于时序数据库&#xff0c;关于开源... 一个问题重点&#xff0c;3-5 分钟&#xff0c;我们讲给你听&#xff1a; 列式写入到底是&#xff1f; 上一期我们详细了解了…

【STM32】写Keil程序的注意事项

看正点原子的资料使用Keil写STM32程序的时候&#xff0c;总是在不断学习&#xff0c;不断探索。后续又学到啥再更新 目录 1 Keil设置 1.1 字体设置 1.2 快捷键设置 1.3 快速前往前一操作位置/后一操作位置 2 宏定义 2.1 宏定义函数时为什么使用do{…}w…

DockerHub解决镜像拉取之困

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

【数据结构篇】~栈和队列(附源码)

【数据结构篇】~栈和队列 前言一、栈的实现1.头文件2.源文件3.一个算法题——[有效的括号](https://leetcode.cn/problems/valid-parentheses/description/%E2%80%8B) 二、队列1.头文件2.源文件 前言 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入…

极速文件预览!轻松部署 kkFileView 于 Docker 中!

大家好&#xff0c;这几天闲的难受&#xff0c;决定给自己找点事做。博主的项目中有个文件预览的小需求&#xff0c;原有方案是想将文件转换成 PDF 进行预览。本着能借鉴就绝对不自己写的原则。今天就让我们简单试用一下 kkFileView 文件预览服务&#xff0c;一起探索它的强大功…

先导桌面式教育数控 小型数控车床 C59

桌面式教育数控主要指的是在教育领域中使用桌面型数控机床进行教学和培训。这种设备结合了数控技术和小型化设计&#xff0c;使得数控技术的学习和应用变得更加便捷和经济。 桌面式教育数控的主要特点包括&#xff1a; 小型化&#xff1a;机床体积小&#xff0c;重量轻&#x…

Debezium2.7 数据同步 MySQL/Oracle -- AI生成

Debezium是Red Hat开源的一个工具&#xff0c;用于实时捕获多种数据源&#xff08;包括MySQL、PostgreSQL、SQL Server、Oracle等&#xff09;的变更数据&#xff0c;并将这些数据作为事件流输出到Kafka等消息中间件中。通过Debezium&#xff0c;可以实现数据的实时同步和变更数…

Vue组件库Element和Vue路由

目录 一、Vue组件库Element&#xff08;学会怎么CV&#xff09; 快速入门 ElementUI的常用组件 1.Table表格 &#xff08;1&#xff09;组件演示 &#xff08;2&#xff09;组件属性详解 2.Pagination分页 &#xff08;1&#xff09;组件演示 &#xff08;2&#xff0…

易企秀Html5场景秀系统源码 海量模版可以选择 带源代码包以及搭建部署教程

系统概述 易企秀 HTML5 场景秀系统源码是基于 PHPMySQL 组合开发的一套强大的 H5 页面制作系统。它旨在满足企业和个人对于个性化 H5 页面制作的需求&#xff0c;无论是企业宣传、活动推广、产品展示还是邀请函制作等&#xff0c;都能通过该系统轻松实现。 该系统的核心优势在…

智能优化算法-森林优化算法(FOA)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1.内容介绍 森林优化算法 (Forest Optimization Algorithm, FOA) 是一种基于自然生态系统的元启发式优化算法&#xff0c;它模拟了森林生态系统中的植物生长、竞争和合作等行为&#xff0c;用于解决复杂的优化问题。 FOA的…

uniapp中 使用 VUE3 组合式API 怎么接收上一个页面传递的参数

项目是uniapp &#xff0c;使用了vue3 vite // 使用的组合式API 的 语法糖 <script setup> // 无法使用 onLoad <script> 使用不了下面方法获得上一个页面参数传递 onLoad(options){ } 解决方案1&#xff08;亲测Ok&#xff09;&#xff1a;消息通知与监听…

计算机毕业设计选题推荐-岗位招聘数据可视化分析-Python爬虫

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Android12 显示框架之Transaction----server端

目录&#xff1a;Android显示终极宝典 上篇讲完了在client端Transaction的内容&#xff0c;最后调用setTransactionState()把所有的参数都交给了surfaceflinger&#xff0c;那么任务就交给server来完成了。本节我们一起接着看看下面的内容。 setTransactionState() //framew…

SQL手工注入漏洞测试(MongoDB数据库)

此次靶场地址为&#xff1a;墨者学院 ⼀. 如下给出的源码...可以看到数据库查询的语句如下..构造回显测试... new_list.php?id1});return ({title:1,content:2 ⼆.成功显示“ 1” 和“ 2” 。可以在此来显示想要查询的数据。接下来开始尝试构造payload查询 当前数据库。通过…

Python基础知识学习总结(七)

文章目录 一. 函数1. 定义函数2. 语法及实例3. 函数调用4. 参数传递5. 可更改与不可更改对象6. 传可变对象实例 二. 文件I/O1. 定义2. File对象的属性3. open 函数4. write()方法5. read()方法6. 文件定位 一. 函数 函数是组织好的&#xff0c;可重复使用的&#xff0c;用来实…

【微服务】SpringCloud Alibaba 10-14章

10 SpringCloud Alibaba入门简介 10.1 是什么 诞生 2018.10.31&#xff0c;Spring Cloud Alibaba 正式入驻了 Spring Cloud 官方孵化器&#xff0c;并在 Maven 中央库发布了第一个版本。 Spring Cloud Alibaba 介绍 10.2 能干嘛 https://github.com/alibaba/spring-cloud-al…

芯片后端之 PT 使用 report_timing 产生报告 之 -nets 选项

今天&#xff0c;我们再学习一点点 后仿真相关技能。 那就是&#xff0c;了解 report_timing 中的 -nets 选项 。 如果我们仅仅使用如下命令&#xff0c;执行后会发现&#xff1a; pt_shell> report_timing -from start_point -to end_point -delay_type max report_ti…

JavaScript(31)——内置构造函数

构造函数 构造函数是一种特殊的函数&#xff0c;主要用于快速初始化对象 用大写字母开头只能由new操作符来执行 function Stu(name, age) {this.name namethis.age age}const xiaom new Stu(小明, 18)const xiaoh new Stu(小红, 19)console.log(xiaom);console.log(xiaoh…

catkin_make 编译报错CMake Error at /opt/ros/noetic/share/catkin/cmake/的最全解决办法,包治百病

检索&#xff08;解决安装了Anaconda后catkin_make不能用了&#xff0c;CMake Error at /opt/ros/noetic/share/catkin/cmake/catkinConfig.cmake:83 (find_package):Could not find a package configuration file provided by "serial" with any&#xff0c;Invokin…

Stable Diffusion AI绘画工具的安装与配置(MAC用户)

AI绘画的热潮席卷了整个创意行业&#xff0c;Stable Diffusion作为其中的翘楚&#xff0c;让艺术创作变得前所未有的简单。然而&#xff0c;对于使用Mac电脑用户来说&#xff0c;安装和配置Stable Diffusion可能显得有些棘手。别担心&#xff0c;这份详细的教程将手把手教你如何…