ROS话题通信自定义msg

news2024/9/24 1:19:39

从21年至今写过不下10个ROS话题通信的工程,今天系统地记录下自定义msg的过程,让后来者少走弯路。

1、自定义msg简介

在 ROS 通信协议中,数据载体是一个较为重要组成部分,ROS 中通过 std_msgs 封装了一些原生的数据类型,比如:String、Int32、Int64、Char、Bool、Empty… 但是,这些数据一般只包含一个 data 字段,结构的单一意味着功能上的局限性,当传输一些复杂的数据,比如: 激光雷达的信息… std_msgs 由于描述性较差而显得力不从心,这种场景下可以使用自定义的消息类型。

msgs只是简单的文本文件,每行具有字段类型和字段名称,可以使用的字段类型有:

  • int8, int16, int32, int64 (或者无符号类型: uint*)
  • float32, float64
  • string
  • time, duration
  • other msg files
  • variable-length array[] and fixed-length array[C]

ROS中还有一种特殊类型:Header,标头包含时间戳和ROS中常用的坐标帧信息。会经常看到msg文件的第一行具有Header标头。

2、自定义msg示例

需求:创建自定义消息,该消息包含刚体的6自由度坐标(3D坐标+欧拉角):x, y, z, r, p, y。

操作流程:

  1. 按照固定格式创建 msg 文件
  2. 编辑配置文件
  3. 编译生成可以被 Python 或 C++ 调用的中间文件

2.1、定义msg文件

功能包下新建 msg 目录,添加文件 Pose.msg,因为数据属于浮点型,选择32位的float。

float32 axis_x 
float32 axis_y
float32 axis_z
float32 roll
float32 pitch
float32 yaw

2.2、编辑配置文件

package.xml中添加编译依赖时依赖与执行时依赖

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

在这里插入图片描述

CMakeLists.txt编辑 msg 相关配置

# 需要加入 message_generation,必须有 std_msgs
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
## 配置 msg 源文件
add_message_files(
  FILES
  Pose.msg
)
# 生成消息时依赖于 std_msgs
generate_messages(
  DEPENDENCIES
  std_msgs
)
#执行时依赖
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES ros_vo
 CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

2.3、编译工程

进入工作空间目录并catkin_make编译

Scanning dependencies of target _ros_vo_generate_messages_check_deps_Pose
[  0%] Built target std_msgs_generate_messages_lisp
[  0%] Built target std_msgs_generate_messages_py
[  0%] Built target std_msgs_generate_messages_eus
[  0%] Built target std_msgs_generate_messages_nodejs
[  0%] Built target std_msgs_generate_messages_cpp
Scanning dependencies of target run_vo
[  0%] Built target _ros_vo_generate_messages_check_deps_Pose
Scanning dependencies of target ros_vo_generate_messages_py
Scanning dependencies of target ros_vo_generate_messages_eus
Scanning dependencies of target ros_vo_generate_messages_cpp
Scanning dependencies of target ros_vo_generate_messages_nodejs
Scanning dependencies of target ros_vo_generate_messages_lisp
[ 11%] Generating Lisp code from ros_vo/Pose.msg
[ 33%] Generating C++ code from ros_vo/Pose.msg
[ 33%] Generating Python from MSG ros_vo/Pose
[ 44%] Generating EusLisp manifest code for ros_vo
[ 55%] Generating EusLisp code from ros_vo/Pose.msg
[ 66%] Generating Javascript code from ros_vo/Pose.msg
[ 66%] Built target ros_vo_generate_messages_lisp
[ 66%] Built target ros_vo_generate_messages_nodejs
[ 77%] Building CXX object ros_vo/CMakeFiles/run_vo.dir/src/run_vo.cpp.o
[ 88%] Generating Python msg __init__.py for ros_vo
[ 88%] Built target ros_vo_generate_messages_cpp
[ 88%] Built target ros_vo_generate_messages_py
[ 88%] Built target ros_vo_generate_messages_eus
Scanning dependencies of target ros_vo_generate_messages
[ 88%] Built target ros_vo_generate_messages
[100%] Linking CXX executable /home/dzh/Demo/VO/devel/lib/ros_vo/run_vo
[100%] Built target run_vo

编译后的中间文件查看:

C++ 需要调用的中间文件(…/工作空间/devel/include/包名/xxx.h),后续调用相关 msg 时,是从这些中间文件调用的。

在这里插入图片描述

3、自定义msg调用

需求:

编写发布订阅实现,要求发布方以10HZ(每秒10)的频率发布自定义消息,订阅方订阅自定义消息并将消息内容打印输出。

分析:

在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:

发布方
接收方
数据(此处为自定义消息)

流程:

编写发布方实现;
编写订阅方实现;
编辑配置文件;
编译并执行。

3.1、发布方实现:

// 1.包含头文件 
#include "ros/ros.h"
#include "std_msgs/String.h" 
#include "geometry_msgs/Point.h"
#include "rtsp/Pose.h"

int main(int argc, char  *argv[])
{   
    //设置编码
    setlocale(LC_ALL,"");

    //2.初始化 ROS 节点:命名(唯一)
    // 参数1和参数2 后期为节点传值会使用
    // 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一
    ros::init(argc,  argv, "poseTalker");
    //3.实例化 ROS 句柄
    ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能

    //4.实例化 发布者 对象
    //泛型: 发布的消息类型
    //参数1: 要发布到的话题名称
    //参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁)
    ros::Publisher pub = nh.advertise<rtsp::Pose>("pose", 10);

    //5.组织被发布的数据,并编写逻辑发布数据
    // x方向像素偏移、y方向像素偏移、z方向真实距离(6m内有效,否则为0)
    rtsp::Pose pose;
    // 类型为float64
    pose.axis_x  = 1;
    pose.axis_y = 2;
    pose.axis_z = 3;
    pose.roll = 4;
    pose.pitch = 5;
    pose.yaw = 6;

    //逻辑(一秒1次)
    ros::Rate r(10);

    //节点不死
    while (ros::ok())
    {
        //发布消息
        pub.publish(pose);
        //加入调试,打印发送的消息
        // ROS_INFO("发送的消息:%f %f %f",point.x, point.y, point.z);
        //根据前面制定的发送频率自动休眠 休眠时间 = 1/频率;
        r.sleep();
        //暂无应用
        ros::spinOnce();
    }

    return 0;
}

3.2、订阅方实现:

// 1.包含头文件 
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "geometry_msgs/Point.h"
#include "rtsp/Pose.h"

// 处理pose消息
void dealPose(const rtsp::Pose::ConstPtr &msg_pose){
    ROS_INFO("axis_x: %f, axis_y: %f, axis_z: %f, roll: %f, pitch: %f, yaw: %f", msg_pose.axis_x, msg_pose.axis_y, msg_pose.axis_z, msg_pose.roll, msg_pose.pitch, msg_pose.yaw);
}

int main(int argc, char  *argv[])
{
    setlocale(LC_ALL,"");
    //2.初始化 ROS 节点:命名(唯一)
    ros::init(argc,argv,"listener");
    //3.实例化 ROS 句柄
    ros::NodeHandle nh;
    //4.实例化 订阅者 对象,订阅话题为Point
    ros::Subscriber sub = nh.subscribe<rtsp::Pose>("pose", 10, dealPose);
    //5.处理订阅的消息(回调函数)
    //ros::Subscriber sub2 = nh.subscribe<未知结构体类型>("未知话题名称", 10, recvMsg);
    // 6.设置循环调用回调函数
    ros::spin();//循环读取接收的数据,并调用回调函数处理
    return 0;
}

3.3、配置 CMakeLists.txt

add_executable(pose_pub src/pose_pub.cpp)
add_executable(pose_sub src/pose_sub.cpp)

target_link_libraries(pose_pub
  ${catkin_LIBRARIES}
)
target_link_libraries(pose_sub
  ${catkin_LIBRARIES}
)

3.4、执行

  1. 启动 roscore;

  2. 启动发布节点;

  3. 启动订阅节点。

在这里插入图片描述

PS:可以在终端中使用 rqt_graph 查看节点关系;使用rostopic list查看话题列表;使用rostopic echo pose订阅话题内容。记住使用前先source ./devel/setup.bash

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

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

相关文章

redis7单节点、主从、哨兵、集群的安装和配置

redis7安装和配置 2022年4月份正式发布的redis 7.0&#xff0c;是目前历史上变化最大的版本&#xff0c;有超过50个以上的新增命令 官网&#xff1a; https://redis.io中文镜像 http://redis.cn中文学习网&#xff1a; https://redis.com.cn/redis版本&#xff0c;建议升级…

Spring初识(一)

一.Spring 是什么&#xff1f; 首先我们来看看官网的解释 Spring 使每个人都可以更快、更轻松、更安全地进行 Java 编程。Spring 对速度、简单性和生产力的关注使其成为 世界上最受欢迎的 Java框架。 这里我简单的说明一下什么是spring? 我们通常所说的 Spring 指的是 Sprin…

纯CSS实现的卡片切换效果

纯CSS实现的卡片切换效果 无需JS就可以实现限于纯静态页面产品展示不需要轮播,自动切换 示例代码 <template><div class"example-css-tab"><div class"container dwo"><div class"card"><input type"radio"…

(续2)选择屏幕

分页签组件 表单控件 双击空白处----出现右侧编辑框 其中 fixed的意思是固定几列。 可修改 回车会自动复原 回车会自动复原 原因 在pai中检查字段却没有做任何操作。 打算新建一个表单 表单中指定选择行. 按钮扩展. 执行后 修改列名. 创建一个moudle 修改后不会复原. …

前端卷算法系列(七)

前端卷算法系列&#xff08;六&#xff09; 删除有序数组中的重复项 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯…

用 pesq 给 soundfile 读取的录音数据打分

音频文件来源 NOIZEUS: Noisy speech corpus - Univ. Texas-Dallas 很多python库都能计算pesq分数&#xff0c;如pypesq跟pesq两个库&#xff0c;这里讲的的是pesq的库 import soundfile as sf from pesq import pesq# 读取音频文件 audio_clean, src sf.read(./audio/NOIZE…

[南京大学]-[软件分析]课程学习笔记(三)-数据流分析

Data Flow Analysis Overview of Data Flow Analysis may analysis: outputs information that may be true(over-approximation) 可能正确&#xff0c;超出近似over-approximationmust analysis: outputs information that must be true (under-approximation) 必须正确&…

WPF RadioButton单选失效

文章目录 前言解决方案 前言 我最近在照着教程敲代码&#xff0c;WPF深入讲解第8集。发现RadioButton按钮点击触发器不是单选的。WPF中单选和复选通过RadioButton和CheckButton来进行区分。我点击另一个RadioButton之后&#xff0c;之前的Radiobutton没有取消选择。 解决方案 …

文件上传下载概述

So Easy系列之文件上传下载教程 文件上传下载概述 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端&#xff0c;从服务器端下载文件到本地的过程。例如目前网站需要上传头像、上传下载图片或网盘等功能都是利用文件上传下载功能实现的。 文件上传下载实际上…

Shell运行原理以及Linux中的权限问题

目录 一、shell的运行原理 二、Linux权限的概念 2.1 用户账号切换 2.2 仅提升当前指令的权限 2.3 将普通用户添加到信任列表 三、Linux权限管理 3.1 文件访问者的分类 3.2 文件类型和访问权限 3.3 字符权限值的表示方法 3.3.1 字符表示方法 3.3.2 八进制表示法 3.4…

CSS学习04

文章目录 1.精灵图1.1 为什么需要精灵图1.2 精灵图&#xff08;sprites&#xff09;的使用 2.字体图标2.1 字体图标的产生2.2 字体图标的优点**2.3** **字体图标的下载****2.4** **字体图标的引入**2.5 字体图标的追加 3.CSS 三角3.1 介绍 4.CSS 用户界面样式4.1 鼠标样式 curs…

openGauss学习笔记-11 openGauss 简单数据管理-INSERT INTO语句

文章目录 openGauss学习笔记-11 openGauss 简单数据管理-INSERT INTO语句11.1 语法格式11.2 参数说明11.3 示例 openGauss学习笔记-11 openGauss 简单数据管理-INSERT INTO语句 在创建一个表后&#xff0c;表中并没有数据&#xff0c;使用这个表之前&#xff0c;需要向表中插入…

【Go|第8期】Lorca读取HTML的三种方式

日期&#xff1a;2023年7月16日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

【云原生】K8S单节点搭建

Kubernetes Kubernetes基础概念架构1、基础环境2、安装kubelet、kubeadm、kubectl 2、使用kubeadm引导集群1、下载各个机器需要的镜像2、初始化主节点 Kubernetes核心实战Pod Kubernetes基础概念 kubernetes具有以下特性&#xff1a; ● 服务发现和负载均衡 Kubernetes 可以使…

leetcode 669. 修剪二叉搜索树

2023.7.15 知道了如何删除二叉树节点的逻辑之后&#xff0c;这题就不难了。 可以参考删除二叉搜索树中的节点这篇文章。 下面直接上代码&#xff1a; class Solution { public:TreeNode* trimBST(TreeNode* root, int low, int high) {if(root nullptr) return root;root->…

MacOS使用USB接口与IPhone进行Socket通信

演示效果如下: 开源地址: GitHub - rsms/peertalk: iOS and Mac Cocoa library for communicating over USB 克隆源码: git clone https://github.com/rsms/peertalk.git 克隆后打开peertalk然后启动xcode工程 先启动MacOS服务端工程,再启动iOS客户端工程 客户端 服务端

[java安全]URLDNS

文章目录 [java安全]URLDNS前言HashMapURLURLStreamHandler调用过程调用链流程图POC [java安全]URLDNS 前言 URLDNS利用链是一条很简单的链子&#xff0c;可以用来查看java反序列化是否存在反序列化漏洞&#xff0c;如果存在&#xff0c;就会触发dns查询请求 它有如下优点&a…

spring复习:(35)在getBean时,在哪里根据普通bean和工厂bean进行区分处理来返回的?

在AbstractBeanFactory的doGetBean方法&#xff1a; 调用的getObjectForBeanInstance方法部分代码如下&#xff1a; 如果不是工厂bean,则直接将实例返回&#xff0c;否则调用getObjectFromFactoryBean方法获取工厂bean的getObject方法返回的对象 protected Object getObjectF…

Gradle和Aritifactory

Gradle和Aritifactory 本文链接&#xff1a;https://blog.csdn.net/feather_wch/article/details/131746580 文章目录 Gradle和AritifactoryGradle基本介绍Gradle插件开发流程本地仓库artifactory搭建添加仓库使用本地仓库gradle插件仓库引入 Gradle基本介绍 1、Gradle是一种…

node使用fluent-ffmpeg把webm格式的音频转成mp3

下载并安装ffmpeg http://ffmpeg.org/download.html?aemtntg-on https://www.gyan.dev/ffmpeg/builds/ 配置环境变量&#xff1a; 查询版本 装包&#xff1a; yarn add fluent-ffmpeg const ffmpeg require(fluent-ffmpeg)ffmpeg(/temp/ai/hello.webm).output(/temp/ai/h…