ROS 的通信机制之话题订阅模型详解

ROS 的通信机制之话题订阅模型

1.基础概念

  1. 话题(Topic):话题表示的是一个定义了类型的消息流。例如,摄像机产生的数据可能会被发送到一个名为“image”的话题上,其消息类型是Image。
  2. 发布与订阅
    • 发布(Publish):节点可以将数据发布到特定的话题上。在发布数据之前,节点需要先声明话题名和消息类型,并与roscore(ROS的核心)建立连接。roscore会共享其订阅者与发布者的列表,然后节点就可以将数据发布到该话题上了。
    • 订阅(Subscribe):想要从话题上接收数据的节点,需要向roscore发出请求以订阅该话题。订阅后,该话题上所有的消息都会被转发到这个请求的节点上,从而建立了发布者与订阅者之间的直接连接。
  3. 消息类型:同一个话题上的所有消息必须是同一类型的。ROS提供了多种基础的消息类型,如std_msgs(标准的数据类型)、geometry_msgs(几何数据型)和sensor_msgs(传感器数据型)。但在实际应用中,很多时候还需要设计特定的消息类型。

2.通信流程

  • 发布者创建并发布特定主题上的数据。
  • 订阅者向roscore请求订阅该主题。
  • roscore将主题上的数据转发给订阅者。

3.本质原理

话题订阅模型在ROS中的实现本质上依赖于底层的通信机制和网络编程。

3.1节点注册和发现

  • ROS节点在启动时,会向ROS Master(roscore的一部分)注册自己,并声明它们将要发布或订阅的话题。
  • ROS Master维护一个全局的话题和节点注册表,它知道哪些节点正在运行,以及这些节点正在发布或订阅哪些话题。

3.2话题匹配

  • 当一个节点想要订阅某个话题时,它会向ROS Master发送一个请求,询问有哪些节点正在发布该话题。
  • ROS Master将发布该话题的节点信息返回给订阅者节点。
  • 订阅者节点随后直接与发布者节点建立连接,开始接收数据。

3.3通信协议

  • ROS使用TCPROS或UDPROS等协议作为底层的通信协议。TCPROS提供了可靠的数据传输,而UDPROS则提供了更高效的通信,但牺牲了一定的可靠性。
  • 发布者节点将消息序列化后,通过选定的通信协议发送给订阅者节点。
  • 订阅者节点接收到消息后,将其反序列化,并转换成对应的ROS消息类型,以供本地处理。
  • 话题订阅模型支持异步通信,即发布者和订阅者不需要同步运行。发布者可以在任何时候发布消息,而订阅者则在自己的节奏下接收和处理这些消息。

3.4 消息序列化与反序列化

ROS消息在传输之前需要进行序列化,即将消息对象转换为字节流,以便在网络中传输。接收端接收到字节流后,需要进行反序列化,即将字节流转换回原始的ROS消息对象

4. 简单通信举例

4.1 简单话题消息发布

示例代码CPP:

#include "ros/ros.h"
#include "std_msgs/String.h" //普通文本类型的消息
#include <sstream>
int main(int argc, char  *argv[]){


      //设置编码
    setlocale(LC_ALL,"");
    ros::init(argc,argv,"talker");
     //3.实例化 ROS 句柄
    ros::NodeHandle nh;//该类封装了 ROS 中的一些常用功能
      //参数2: 队列中最大保存的消息数,超出此阀值时,先进的先销毁(时间早的先销毁)
    ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);

    std_msgs::String msg;  
    //数据类型为 String

      std::string msg_front = "Hello 你好!"; //消息前缀
    int  count = 10;

     ros::Rate r(1); // 设置频率为1Hz  ,1s 一次
  
    while (ros::ok())  
    {  
        std::stringstream ss;
        ss << msg_front << count;
        msg.data = ss.str();
        pub.publish(msg);
        ros::spinOnce(); // 处理ROS回调  
        ROS_INFO("发送的消息:%s",msg.data.c_str()); //打印发送的消息
        count++;
        r.sleep(); // 根据设定的频率暂停,以确保不会执行得太快  
    }  
  
    return 0;  
}

4.2简单话题消息订阅

示例代码CPP:

#include "ros/ros.h"
#include "std_msgs/String.h"


//接受到信息的回调函数
void doMsg(const std_msgs::String::ConstPtr& msg_p){
    ROS_INFO("我听见:%s",msg_p->data.c_str());
    // ROS_INFO("我听见:%s",(*msg_p).data.c_str());
}

int main(int argc, char  *argv[]){
    setlocale(LC_ALL,"");
      //2.初始化 ROS 节点:命名(唯一)
    ros::init(argc,argv,"listener");
     //3.实例化 ROS 句柄
    ros::NodeHandle nh;

    ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter",10,doMsg);

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

4.3CmakeLists.txt编写

add_executable(publisher
  src/publisher.cpp
)

add_executable(sub
  src/sub.cpp
)

target_link_libraries(publisher
  ${catkin_LIBRARIES}
)

target_link_libraries(sub
  ${catkin_LIBRARIES}
)

如果编译通过,但是rosrun 提示找不到节点,请检查是否有catkin_package()

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
)
catkin_package()

4.4 运行效果

在这里插入图片描述

相关推荐

  1. ros收发话题通信测试

    2024-04-22 05:48:03       32 阅读
  2. ROS-ROS通信机制-常用API

    2024-04-22 05:48:03       55 阅读
  3. Redis发布-订阅模式Channel发布订阅

    2024-04-22 05:48:03       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-22 05:48:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-22 05:48:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-22 05:48:03       87 阅读
  4. Python语言-面向对象

    2024-04-22 05:48:03       96 阅读

热门阅读

  1. Git:远程仓库名称变更本地无法提交解决

    2024-04-22 05:48:03       33 阅读
  2. 一文掌握面阵相机

    2024-04-22 05:48:03       34 阅读
  3. Ubuntu 中如何高效的使用grep命令

    2024-04-22 05:48:03       30 阅读
  4. Cordova Common Command

    2024-04-22 05:48:03       36 阅读
  5. Storm详细配置

    2024-04-22 05:48:03       25 阅读
  6. ELK 与 EFK的介绍和对比

    2024-04-22 05:48:03       37 阅读
  7. Cesium之汉化

    2024-04-22 05:48:03       38 阅读