首页 > 编程语言 >ROS通信方式之Topic话题与Message消息的关系与C++实现

ROS通信方式之Topic话题与Message消息的关系与C++实现

时间:2024-10-09 20:53:22浏览次数:11  
标签:发送 订阅 话题 C++ Topic 消息 Message ros 节点

ros由于其分布式模块化的设计理念,会将一个完整任务分解成多个节点去实现,这些节点之间的协作通过topic话题和message消息.相关概念有

 如何通过协作完成一个目标任务,参考教程人工匠阿杰视频深入浅出的讲解:

背景任务,有个执行器需要从超声波节点获取距离信息(此处此执行器为马达)以便进行运动状态的调整,比如底盘电机通过获取超声波测距值来完成一个障碍物规避的动作,此例子是要实现一个跨包的通讯,创建好两个独立的package分别是前文所述的ssr_pkg,以及执行器对应的马达,在ros中对应的node节点叫做ma_node,节点不能脱离软件包独立存在,在此建立一个软件包atr_pkg,如上所示.

相互的关系是

小结:

  1. 话题Topic是节点间进行持续通讯(消息一直在不停的发送和接收)的一种形式
  2. 话题通讯的两个节点通过话题的名称(如上图在群里沟通但是群是有专有的名字的)建立起话题通讯连接
  3. 话题中通讯的内容/数据,叫做消息Message
  4. 消息Message通常会安装一定的频率持续不断的发送,以保证消息数据的实时性
  5. 消息的发送方叫做话题的发布者Publisher,接收方叫做话题的订阅者Subsciber

 以上情况是对系统中两个节点的配合情况做出总结,通常一个系统中会有多个节点相互协作,例如本例中需要通过添加IMU传感器获取机器人的旋转倾斜等姿态信息。

创建IMU节点为yao_node(这个传感器跟瑶妹一样是附着在机器人身上哈哈),这个节点同样放在ssr_pkg包里面,类比上文两个节点的情况,在同一个群里进行发布话题,作为订阅者来说同一个群里接收话题太过杂乱,所以一般不这样做,通常会将不同传感器的消息话题进行分离,例如这里分成两个独立的群聊频道

这样看来在订阅者视角可以对不同情况进行灵活处理,需要测距信息就订阅超声波超哥的话题,需要机器人姿态信息就订阅IMU瑶妹的话题,此时系统中出现两个话题。

注意上文说的是一般情况下不会在一个话题里面产生多个发布者,但是总有不一般的情况,例如下图,这种情况一般要控制好发布者的发言顺序,同一时刻只有一个发布的节点,否则机器人就会面对多个相互冲突的指令无所适从行走困难

 

Message:消息的作用是携带数据从发布者流动到订阅者 ,这个数据有可能是传感器的数值,也可能是速度指令,所以不同的数据类型和大小容量,所以消息的格式分为很多类型,以满足不同的数据传输要求,所以生成消息包的时候通常要指定消息的类型,上文创建package的时候,依赖项中std_msgs标准消息包,具体内容可以在index.ros.org中搜索std_msgs查看不同版本的ros对应的std_msgs的定义。

接下来探究如何具体实现

依旧从前文(ros初学者如何创建node节点ros 初学者如何创建 node 节点-CSDN博客)创建的chao_node节点中继续更改代码,打开Visual Studio 打开节点代码文件,我们需要考虑两个事情1、考虑自己的发布的Message消息的类型,在代码中补充;2、发布的话题名称

本例中,超哥的话题名称是“快上车开黑群”,消息的类型是下面的“国服马超,带飞”所对应的类型,进入index.ros.org搜索std_msgs进入noetic版本,点击website查看ros message types

在这里string(字符串类型)符合要求

回到vscord

补充:

这里的代码相较于之前的内容添加了几行代码

ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::String>("快上车开黑群",10);

第一句NodeHandle对象是节点和ros通讯的关键 ,相当于一位管家,ros相当于管家打理的一所豪宅,有需求是吩咐管家,管家去管理内容

第二句定义一个对象名字叫pub,是发送消息的工具,后面暂时就看做一个adverttise()函数的参数,有两个一个是群名称,一个是消息缓存的长度,这样就完成了一个消息的发布

!注意,关于缓存长度,理想情况下消息发送后会立刻被订阅者接收,但是有的时候订阅者处理消息的时间比较长,之前的消息还没处理完毕,新的发布消息已经来了,此时这个消息会在外面排队等候,后续会一个个排列,当这个排队等候的队伍容量满了以后,排在最前面的消息会被丢弃挪出空位给后面新来的消息能够进入缓存,这个缓存长度太大太小都不合适,最好是根据具体情况计算

   while(ros::ok)
   {
    printf("我要刷屏了!\n");
    std_msgs::String msg;
    msg.data = "国服马超带飞";
    pub.publish(msg);
   }
    return 0;
  • 消息创建std_msgs::String msg; 这行代码创建了一个名为 msg 的字符串类型消息对象。

  • 设置消息内容msg.data = "国服马超带飞"; 这行代码给消息对象的 data 属性赋值为“国服马超带飞”,这是将要发布的实际内容。

  • 发布消息pub.publish(msg); 这行代码将刚创建的消息发布到指定的主题,使其他订阅该主题的节点能够接收到这条消息。

保存ctrl C运行ctrl+shift+B,去终端运行

首先打开终端运行rosecore,运行完成之后重新打开终端

rosrun ssr_pkg chao_node

这里可能会出现报错

大概是说话题名称不合法,只能字母加一些符号组成,我们将代码里面中文的话题名称“快上车开黑群”改成字母组成的即可

调整之后正常运行


 

拓展:rostopic用法1、2、3、

1、查看当前系统中活跃的话题有哪些

rostopic list

 2、查看某活跃话题的消息内容rostopic echo /话题名称

rostopic echo /kuai_shang_che_kai_hei_qun

 显示如下

 对此展开新终端输入

echo -e "\u56FD\u670D\u9A6C\u8D85\u5E26\u98DE"

 

 现行,那一串代码就是中文字符的编码。

3、rostopic hz/话题名称:查看话题里面消息发送的频率

 可以看出一秒发送四万多条消息

如何控制发送频率,回到vscode

ros::Rate loop_rate(10);

这句话表示一秒钟发送10次

loop_rate.sleep();

这个函数会在while循环内做一个短时间的阻塞,以便让循环的执行频率能和刚才给的参数对应上

 此时回到终端运行

 发送频率可以稳定在每秒10次

总结1:发布一个话题和发送消息的操作

  1. 确定话题名称和消息类型,注意话题名称不能使用中文字符
  2. 在代码文件中include消息类型对应的头文件
  3. 在main函数中通过NodeHandler大管家发布一个话题并得到消息发送对象
  4. 生成要发送的消息包并进行发送数据的赋值
  5. 调用消息发送对象的pubilsh()函数将消息包发送到话题中

以上操作并不一定是要在while中进行

学习视频:机器人工匠阿杰

标签:发送,订阅,话题,C++,Topic,消息,Message,ros,节点
From: https://blog.csdn.net/2301_80758686/article/details/142786093

相关文章

  • 【C++】string (STL)
    string介绍字符串是表示字符序列的类标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_s......
  • 【C++】类和对象(3)(默认成员函数--拷贝构造&赋值重载)
    引言前文介绍了C++中默认成员函数中的构造函数和析构函数,相信已经对它们的功能与用法有了基本认识,本文接着介绍也很常见的拷贝构造函数和赋值重载函数,便于对C++进一步的学习。拷贝构造函数补充知识:深浅拷贝深拷贝和浅拷贝是C++中对象拷贝的两种不同方式。浅拷贝是指将......
  • c++基本介绍——std::holds_alternative()的基本介绍
    今天的工作中开发一个新功能,涉及到判断std::variant类型是否等于某个特定的值。就此机会学习一下,std::variant类型和调用std::holds_alternative进行持有值的检查。std::holds_alternative是C++17中引入的标准库函数,用于检查std::variant是否持有特定类型的值。它返回......
  • 实验1 现代C++编程初体验
    task1:1//现代C++标准库、算法库体验2//本例用到以下内容:3//1.字符串string,动态数组容器类vector、迭代器4//2.算法库:反转元素次序、旋转元素5//3.函数模板、const引用作为形参67#include<iostream>8#include<string>9#includ......
  • 实验1 现代C++编程初体验
    任务一源代码1#include<iostream>2#include<string>3#include<vector>4#include<algorithm>56usingnamespacestd;78template<typenameT>9voidoutput(constT&c);1011voidtest1();12voidtest2();13v......
  • 合并、删除区间算法C++代码
    #include<algorithm>#include<iostream>#include<vector>usingnamespacestd;classSolution{public:constintCOMBINE_INT=0;//1表示整数点区间,比如[1:3]和[4:5]会合并为[1:5],0则仅会合并[1:3]和[3:4]这类的区间。vector<pair<int,int>>......
  • 实验1 现代C++编程初体验
    1.实验任务11#include<iostream>2#include<string>3#include<vector>4#include<algorithm>56usingnamespacestd;78//声明9//模板函数声明10template<typenameT>11voidoutput(constT&c);1213//普通函数声明......
  • C++模板与容器
    目录一、 模板1.函数模板2.类模板二、容器1.标准模板库STL2.概念3顺序容器3.1array数组2.3.2vector向量3.3list列表 3.4deque队列4关联容器5迭代器遍历一、 模板        模板可以让类或者函数支持一种通用类型,这种通用数据类型在实......
  • 关于C++中的异常概念理解
    1.基本概念异常,即exception,是C++中的基本概念之一,在某段程序发生无法继续正常执行的情况时,C++允许程序进行所谓抛出异常(有时也被称为吐出异常)的行为,这些被抛出的异常,会自动地从触发点开始向外传播,直到被捕获(有时也被称为吞下异常)或者程序终止。2.语法2.1抛出异常下面用一......
  • C++名字空间
    基本概念名字空间本质上是自定义作用域,由于C++设计的初衷是开发大规模软件,大量的软件库必然会加剧全局符号(变量、函数)的冲突,因此名字空间最基本的作用就是给不同的库和模块拥有自己的独特的作用域,处于不同名字空间中的重名符号相安无事,互不冲突,以此来大大提高编程的便利性。1.1......