ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ros之话题通信

2021-10-23 14:03:35  阅读:334  来源: 互联网

标签:std ROS msgs 话题 通信 Listener Talker ros


一、话题通信理论模型
话题通信实现模型是比较复杂的,该模型如下图所示,该模型中涉及到三个角色:

ROS Master (管理者)
Talker (发布者)
Listener (订阅者)
ROS Master 负责保管 Talker 和 Listener 注册的信息,并匹配话题相同的 Talker 与 Listener,帮助 Talker 与 Listener 建立连接,连接建立后,Talker 可以发布消息,且发布的消息会被 Listener 订阅。

整个流程由以下步骤实现:

0.Talker注册

Talker启动后,会通过RPC在 ROS Master 中注册自身信息,其中包含所发布消息的话题名称。ROS Master 会将节点的注册信息加入到注册表中。

1.Listener注册

Listener启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要订阅消息的话题名。ROS Master 会将节点的注册信息加入到注册表中。

2.ROS Master实现信息匹配

ROS Master 会根据注册表中的信息匹配Talker 和 Listener,并通过 RPC 向 Listener 发送 Talker 的 RPC 地址信息。

3.Listener向Talker发送请求

Listener 根据接收到的 RPC 地址,通过 RPC 向 Talker 发送连接请求,传输订阅的话题名称、消息类型以及通信协议(TCP/UDP)。

4.Talker确认请求

Talker 接收到 Listener 的请求后,也是通过 RPC 向 Listener 确认连接信息,并发送自身的 TCP 地址信息。

5.Listener与Talker件里连接

Listener 根据步骤4 返回的消息使用 TCP 与 Talker 建立网络连接。

6.Talker向Listener发送消息

连接建立后,Talker 开始向 Listener 发布消息。

注意1:上述实现流程中,前五步使用的 RPC协议,最后两步使用的是 TCP 协议

注意2: Talker 与 Listener 的启动无先后顺序要求

注意3: Talker 与 Listener 都可以有多个

注意4: Talker 与 Listener 连接建立后,不再需要 ROS Master。也即,即便关闭ROS Master,Talker 与 Listern 照常通信。

二、简单的发布方框架

#include "ros/ros.h"
#include "std_msgs/String.h"
/*
    发布方实现
        1.包含头文件
            ros中的文本类型对应---->"std_msgs/string.h"
        2.初始化ros节点(创建二狗子对象)
        3.创建节点句柄
        4.创建发布者对象
        5.编写发布逻辑并发布数据
*/
int main(int argc, char *argv[])
{
    //2.初始化ros节点
    ros::init(argc,argv,"ergouzi");
    //3.创建节点句柄
    ros::NodeHandle nh;
    //4.创建发布者对象
    ros::Publisher pub = nh.advertise<std_msgs::String>("fang",10);
    //5.编写发布逻辑并发布数据
    //5.1先创建被发布的消息
    std_msgs::String msg;
    //5.2编写循环,循环中发布数据
    while(ros::ok())
    {
        msg.data = "hello";
        pub.publish(msg);
    }
    return 0;
}

注意:通过ros topic echo + 话题可以查看发布的消息

三、要求以每秒10次发布文本并跟上编号

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/*
    发布方实现
        1.包含头文件
            ros中的文本类型对应---->"std_msgs/string.h"
        2.初始化ros节点(创建二狗子对象)
        3.创建节点句柄
        4.创建发布者对象
        5.编写发布逻辑并发布数据
*/
int main(int argc, char *argv[])
{
    //设置编码,解决中文乱码问题
    setlocale(LC_ALL,"");
    //2.初始化ros节点
    ros::init(argc,argv,"ergouzi");
    //3.创建节点句柄
    ros::NodeHandle nh;
    //4.创建发布者对象
    ros::Publisher pub = nh.advertise<std_msgs::String>("fang",10);
    //5.编写发布逻辑并发布数据
    //5.1先创建被发布的消息
    std_msgs::String msg;
    //发布频率
    ros::Rate rate(10);//创建Rate对象
    //设置编号
    int count = 0;
    //为了防止先执行订阅方却还是不能接收前几条消息,因为这时发布方已经开始发送但是还未注册成功
    ros::Duration(3).sleep();
    //5.2编写循环,循环中发布数据
    while(ros::ok())
    {
        count++;
        //msg.data = "hello";
        //实现字符串拼接
        std::stringstream ss;//创建stringstream对象
        ss << "hello -->" << count;//实现拼接
        msg.data = ss.str(); //将拼接好的数据赋值给data并转换成字符串格式
        pub.publish(msg);
        //添加日志
        ROS_INFO("发布的数据是:%s",ss.str().c_str());//转换为c分格的字符串输出
        rate.sleep();//前面调用了Rate10HZ这里相当于睡0.1秒
    }
    return 0;
}

四、订阅方实现

#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 &message)
{
    //通过message获取并操作订阅到的数据
    ROS_INFO("翠花订阅的数据:%s",message->data.c_str());
}
int main(int argc, char *argv[])
{
    //设置编码
    setlocale(LC_ALL,"");
    //2.初始化ros节点(创建翠花对象)
    ros::init(argc,argv,"cuihua");
    //3.创建节点句柄
    ros::NodeHandle nh;
    //4.创建订阅者对象
    ros::Subscriber sub = nh.subscribe("fang",10,domsg);
    //5.处理订阅到的数据
    ros::spin();//循环读取接收的数据,并调用回调函数处理
    return 0;
}

五、ros中的解耦合
(1)用Python和C++写的话题通信程序两者之间可以正常数据通信。

六、话题通信自定义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标头。

(1)在当前功能包下创建msg文件夹,里面创建Person.msg文件包含内容为自己需要的变量类型,譬如:string name、int32 age、float32 height
(2)配置当前功能包的package.xml文件,添加<build_depend>message_generation</build_depend> , <exec_depend>message_runtime</exec_depend>
(3)配置当前功能包的CMakeLists.txt有关message的相关信息

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
# 需要加入 message_generation,必须有 std_msgs

## 配置 msg 源文件
add_message_files(
  FILES
  Person.msg
)

# 生成消息时依赖于 std_msgs
generate_messages(
  DEPENDENCIES
  std_msgs
)

#执行时依赖
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES demo02_talker_listener
  CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

(4)编译后在/home/zzh/demo03_ws/devel/include/plumbing_pub_sub下面生成一个Person.h文件,如果是Python相关的会在/home/zzh/demo03_ws/devel/lib/python3/dist-packages/plumbing_pub_sub/msg生成_Person.py文件

七、自定义msg的发布方实现

(1)配置.vscode下的c_cpp_properties.json加入自定义msg的路径
(2)消息发布方的实现

标签:std,ROS,msgs,话题,通信,Listener,Talker,ros
来源: https://blog.csdn.net/weixin_54989626/article/details/120636780

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有