ROS通信机制~话题通信(Publisher&Subscriber)·笔记2

系列文章目录:

ROS开发(ubuntu)笔记·1_嘻·嘻的博客-CSDN博客

ROS通信机制~服务通信(server&client)·笔记3_嘻·嘻的博客-CSDN博客

话题通信·理论模型:(图源:2.1.1 话题通信理论模型 · Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第1张图片                                                 

基本操作:

首先,写发布者Talker要发布的信息的代码:

1. 在右击src创建新的功能包

ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第2张图片

2.然后导入依赖包

ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第3张图片

3.写代码(第6步有详细代码)ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第4张图片 

写完后Ctrl+Shift+B,正常的话,不会出现ERROR,最后有100%

 对于advertise函数,源码如下图:ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第5张图片

topic就是要发布的信息的话题,红色横线处是队列的长度(发布信息的条数),这里直接用queue(队列)的概念去理解,即我设置是10,当我们输入了12条信息时,他会输出后面10条信息。

4.配置一下CMakeListsROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第6张图片 

修改完编译一下,没有问题就不会有Error输出,并且输出100%

5.检查此时发布者Talker要发布的消息能否正常运行ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第7张图片                                具体步骤:

                           1.终端中输入roscore(执行ros的命令都要进行此操作)     

2.打开新的终端,输入 cd 当前工作空间

3.source一下环境,然后输入rosrun 功能包 映射名称(正常会没有东西输出)

4.输入rostopic echo 话题名称 (我写的是"fang")结果就是一直打印hello hello

最后输入 Ctrl+C 就停止该程序运行

6. 在原来的代码上添加发布逻辑

#include "ros/ros.h"
#include "std_msgs/String.h"
#include
int main(int argc,char *argv[])
{    //解决输出中文出现乱码的问题
     setlocale(LC_ALL,"");

     //2.初始化 ROS 节点;
     // 参数1和参数2 后期为节点传值会使用
    // 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一
     ros::init(argc,argv,"talker");

     //3.创建节点句柄;
     ros::NodeHandle nh;

     //4.创建发布者对象;
     //泛型: 发布的消息类型
    //参数1: 要发布到的话题
     ros::Publisher pub =nh.advertise("fang",10);//就是队列的长度,例如有12条信息的话就输出后面10条

     //5.编写发布逻辑并发布数据
     //要求以10HZ的频率发布数据,并且文本后添加编号
     //先创建被发布的消息
     std_msgs::String msg;

     //发布频率
     ros::Rate rate(10);
     //设置编号
     int count =0;
     //编写循环,循环中发布数据
     ros::Duration(3.0).sleep(); //休眠函数,延迟第一条数据的发送
                          //原因:发送第一条数据时,publisher 还未在 roscore 注册完毕
                         //若没有,就算先启动订阅者代码,也可能导致前几条信息丢失
     while(ros::ok())//ok()指只要该节点还活着,就循环
     {   count++;
         //实现字符串拼接数字
         std::stringstream ss;
         ss<<"hello --->"<

   ros::Duration(3.0).sleep(); //休眠函数,延迟第一条数据的发送
   原因:发送第一条数据时,publisher 还未在 roscore 注册完毕
  若没有,就算先启动订阅者代码,也可能导致前几条信息丢失

 运行结果如图:ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第8张图片

接下来是订阅者listener的代码:

#include"ros/ros.h"
#include"std_msgs/String.h"
/* 订阅方实现:
      1.包含头文件
       ROS中文本类型--->std_msgs/String.h
       2.初始化ROS节点
       3.创建节点句柄;
       4。创建订阅者对象;
       5.处理订阅到的数量;
       6.spin()函数
*/
void doMsg(const std_msgs::String::ConstPtr &msg)
{
    //通过msg获取并操作订阅到的消息
    ROS_INFO("listener订阅的数据:%s",msg->data.c_str());
}
int main(int argc,char *argv[])
{
    setlocale(LC_ALL,"");
    //2.初始化ROS节点
    // 参数1和参数2 后期为节点传值会使用
    // 参数3 是节点名称,是一个标识符,需要保证运行后,在 ROS 网络拓扑中唯一
    ros::init(argc,argv,"listener");
    //3.创建节点句柄
    ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能
    //4.创建订阅者对象;
    ros::Subscriber sub =nh.subscribe("fang",10,doMsg);
    //5.处理订阅到的数量
    ros::spin();//循环读取接收的数据,并调用回调函数(doMsg)处理
    return 0;

}

在第4点创建订阅者对象中,分析一下代码

ros::Subscriber sub=nh.subscribe("fang",10,doMsg);

首先是调用ros库中的订阅器Subscriber (类型)创建了一个sub,后面调用句柄nh的subscribe函数(创建订阅者对象)

括号中,"fang"是订阅者的话题,10是消息队列长度(最多缓存10条信息),当发布者发布了该话题时,就会调用doMsg函数(回调函数)

关于回调函数:一般函数是当程序进行到该函数处时,它就立刻实现,可以说是受我们自己控制的 而回调函数,当程序进行到该处时,它不会立刻执行,需要外界给予它一个信号才能运行,就像一个地雷,只有别人踩了才会爆,这就不受我们自己控制,而是受外界控制了。

ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第9张图片

我们传入的消息是 std_msgs::String类型的,而参数的类型是常量指针的引用,即ConstPtr &msg

ros::spin() 重复执行回调函数,即循环接收发布者发布的信息(与回调函数相对应)

还有一步:(记得修改CMakeLists.txt)与之前步骤相似ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第10张图片 

 之后的操作也类似,先ctrl+shift+B看看有没有出问题,再打开终端,rosrun发布者和订阅者            运行如图:ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第11张图片

在发布者的终端上输入Ctrl+C就可以停止发布,此时订阅者也停止接受信息了。

此时,我们可以通过计算图来看看两个节点之间的关系(新开一个终端输入rqt_graphROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第12张图片

进阶(自定义message):发送的信息可以包含各种数据类型

比如:int8, int16, int32, int64 (或者无符号类型: uint*),float32, float64,string,time,duration,

variable-length array[] and fixed-length array[C] ......

【1】定义msg文件(在功能包下创建msg目录,再创建一个后缀为msg的文件)

ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第13张图片

【2】配置编辑文件

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

ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第14张图片

2.在CMakeLists.txt编辑 msg 相关配置

ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第15张图片

下面这步配置msg源文件

ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第16张图片

修改完后,一定要编译一下ctrl+shift+B,没出现ERROR后,就会在devel目录下的include文件夹下出现一个Person.h (Person 就是之前创建的Person.msg中的Person)

下一步:为了方便代码提示以及避免误抛异常,需要先配置 vscode

1.将前面生成的 head 文件路径(在下图红色框中右击生成终端,输入pwd,复制路径)

2.配置进 c_cpp_properties.json 的 includepath属性(粘贴路径,可将后面具体功能包名改为**):

**意味着直接include目录下的所有内容

ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第17张图片

下面的操作就是实现了(代码与之前类似,注意头文件"plumbing_pub_sub/Person.h") 这里插一步,如果之前创建Person.msg时没有编译,而此时头文件已经用到了Person.h,则会发生逻辑上的错误,为了避免这种错误,需要在CMakeLists进行一步修改操作

 

(orag03_pub 和orag02_sub 是下面修改CMakeLists时,我设的映射名称 )

【发布者】

#include "ros/ros.h"
#include"plumbing_pub_sub/Person.h"

int main(int argc,char *argv[])
{   
    setlocale(LC_ALL,"");
    ROS_INFO("这是消息发布方");
    ros::init(argc,argv,"talker_person");
    ros::NodeHandle nh;
    ros::Publisher pub =nh.advertise("chatter_person",10);
    //创建被发布的数据
    plumbing_pub_sub::Person person;
    person.name ="张三";
    person.age=1;
    person.height=1.73;

    ros::Rate rate(1);
    ros::Duration(3).sleep();
    while(ros::ok())
    {  
    // 修改数据
       person.age += 1;
       //数据发布     
       pub.publish(person);
       ROS_INFO("发布的消息:%s,%d,%.2f", person.name.c_str(), person.age, person.height);
       //休眠
       rate.sleep();

       ros::spinOnce();

    }
}

【订阅者】

#include"ros/ros.h"
#include"plumbing_pub_sub/Person.h"
void doPerson(const plumbing_pub_sub::Person::ConstPtr &person)
{
    ROS_INFO("订阅的人的消息:%s,%d,%.2f",person->name.c_str(),person->age,person->height);
}

int main(int argc,char*argv[])
{
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"listener_person");
    ros::NodeHandle nh;
    ros::Subscriber sub=nh.subscribe("chatter_person",10,doPerson);
    ros::spin();
    return 0;
}

【修改CMakeLists】

ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第18张图片

 运行如图:ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第19张图片

 可得到计算图:ROS通信机制~话题通信(Publisher&Subscriber)·笔记2_第20张图片

这次笔记好长QAQ,能全部看完的真的很牛逼了^-^

你可能感兴趣的:(ubuntu,linux,运维)