ROS学习笔记4——ROS通信机制(话题通信)

发布时间:2024年01月20日

话题通信是ROS中使用频率最高的一种通信模式,话题通信是基于发布订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息。一般用于不断更新的、少逻辑处理的数据传输场景。以相机信息的采集处理为例,在 ROS 中有一个节点需要时时的发布当前相机采集到的数据,另一个节点会订阅并解析相机数据。

一、话题通信理论模型图

二、角色

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

  • ROS Master (管理者)
  • Talker (发布者)
  • Listener (订阅者)

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

三、流程

0、Talker在ROS Master中注册

advertise("bar",foo:1234)

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

1、Listener在ROS Master注册

subscribe("bar")

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

2、ROS Master实现信息匹配

{foo:1234}

ROS Master 会根据注册表中的信息匹配Talker 和 Listener,如果Talker和Listener的话题一致,就会 Listener 发送 Talker 的 RPC 地址信息。

3、Listener向Talker发送请求

connect("scan",TCP)

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

4、Talker确认请求

TCP server:foo:2345

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

5、Listener与Talker建立连接

connect(foo:2345)

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

6、Talker向Listener发送消息

data messages

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

四、注意:

0、从流程0-4通信都是使用的RCP,5-6使用的是TCP协议

1、Talker 与 Listener 的启动注册无先后顺序要求

2、Talker 与 Listener 都可以有多个

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

4、上述实现流程是做好封装的,可以直接调用。(编写Talker 与 Listener、设置双方话题及实现等等)

五、C++实现消息的发布、订阅

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

流程:

  1. 编写发布方实现;
  2. 编写订阅方实现;
  3. 编辑配置文件;
  4. 编译并执行.

5.1 发布方

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/*

    发布方实现流程:
        1.包含头文件 
        2.初始化 ROS 节点:命名(在整个ros系统中唯一)
        3.创建 ROS 句柄
        4.创建 发布者 对象
        5.组织被发布的数据,并编写逻辑发布数据

    要求:
        以10HZ的频率发布数据,并且文本后添加编号
*/

int main(int argc, char *argv[]) 
{
    setlocale(LC_ALL,"");

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

    //3.创建节点句柄
    ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能

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

    //5.组织被发布的数据,并编写逻辑发布数据
    //创建被发布的消息
    std_msgs::String msg;
    //发布频率
    ros::Rate rate(10);//10HZ
    //设置编号
    int count = 0;
    //编写循环,循环中发布数据
    while(ros::ok())//如果节点活着
    {
        //实现数据拼接
        std::stringstream ss;
        ss << "hello " << count;
        msg.data = ss.str();

        pub.publish(msg);

        //添加日志输出
        ROS_INFO("发布的消息:%s",msg.data.c_str());
        
        rate.sleep();
        count++;
        //ros::spinOnce();//官方建议,处理回调函数
    }
    return 0;
}

5.2 订阅方

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/*

    订阅方实现流程:
        1.包含头文件 
        2.初始化 ROS 节点:命名(唯一)
        3.创建 ROS 句柄
        4.创建 订阅方 对象
        5.处理订阅到的数据
        6.ros::spin();

    要求:
        订阅数据
*/

//回调函数
void doMsg(const std_msgs::String::ConstPtr &msg)
{
    //通过msg参数,获取并操作订阅到的数据
    ROS_INFO("订阅的数据:%s",msg->data.c_str());
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    // 2.初始化 ROS 节点:命名(唯一)
    ros::init(argc,argv,"Listener");

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

    // 4.创建 订阅方 对象
    泛型<>: 发布的消息类型
    //参数1: 要订阅到的话题,需要与发布话题一致
    //参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁)
    //参数3: 回调函数
    ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);

    // 5.处理订阅到的数据

    //循环读取接收的数据,并调用回调函数处理
    ros::spin();

    return 0;
}

5.3 配置 CMakeLists.txt

add_executable(topic_pub src/topic_pub.cpp)
add_executable(topic_sub src/topic_sub.cpp)

target_link_libraries(topic_pub ${catkin_LIBRARIES})
target_link_libraries(topic_sub ${catkin_LIBRARIES})

5.4 执行

????????1.启动 roscore;

??????? 2.启动发布节点;

????????3.启动订阅节点。

5.5 结果

?注:订阅的时候,即使先开启订阅节点,依旧会出现前几条消息丢失的情况,这是因为在前几条消息发布的时候,publisher还没在ROS Master中注册完毕。

解决方法:加入ros::Duration(3.0).sleep();? 延迟第一条消息的发送。

六、解耦合

分别通过C++和Python实现了发布者和订阅者。比如c++的发布者,用python创建订阅者来订阅,即便语言不通,仍然可以进行数据通信。但前提是任须保持话题一致!!

文章来源:https://blog.csdn.net/Simulink_/article/details/135581212
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。