当前位置:网站首页>ROS2——topic话题(八)

ROS2——topic话题(八)

2022-07-05 06:35:00 我与nano

ROS2机器人操作系统


前言

节点实现了机器人各种各样的功能,但这些功能并不是独立的,之间会有千丝万缕的联系,其中最重要的一种联系方式就是话题,它是节点间传递数据的桥梁。

一、topic话题

1.通信模型

在这里插入图片描述
以两个机器人节点为例。A节点的功能是驱动相机这个硬件设备,获取得到相机拍摄的图像信息,B节点的功能是视频监控,将相机拍摄到的图像实时显示给用户查看。此时从节点A到节点B传递图像数据的方式,在ROS中,我们就称之为话题,它作为一个桥梁,实现了节点之间某一个方向上的数据传输。

2.发布订阅模型

从话题本身的实现角度来看,使用了基于DDS的发布/订阅模型,什么叫发布和订阅呢?
在这里插入图片描述
话题数据传输的特性是从一个节点到另外一个节点,发送数据的对象称之为发布者,接收数据的对象称之为订阅者,每一个话题都需要有一个名字,传输的数据也需要有固定的数据类型。在这里插入图片描述
怎么说呢,发布和订阅的关系就类似于,我创建了一个发布者,我把消息发布了出去,你什么订阅我不管,我反正是把消息发送到了一个频道,你订阅了变可以查看我发布的消息,同样也可以很多个人订阅。你没有订阅当然是看不到的

3.多对多通信

在这里插入图片描述
大家再仔细想下这些可以订阅的东西,是不是并不是唯一的,我们每个人可以订阅很多公众号、报纸、杂志,这些公众号、报纸、杂志也可以被很多人订阅,没错,ROS里的话题也是一样,发布者和订阅者的数量并不是唯一的,可以称之为是多对多的通信模型。

因为话题是多对多的模型,发布控制指令的摇杆可以有一个,也可以有2个、3个,订阅控制指令的机器人可以有1个,也可以有2个、3个,大家可以想象一下这个画面,似乎还是挺魔性的,如果存在多个发送指令的节点,建议大家要注意区分优先级,不然机器人可能不知道该听谁的了。

4.异步通信

话题通信还有一个特性,那就是异步,这个词可能有同学是第一次听说?所谓异步,只要是指发布者发出数据后,并不知道订阅者什么时候可以收到,这就叫做异步。
异步的特性也让话题更适合用于一些周期发布的数据,比如传感器的数据,运动控制的指令等等,如果某些逻辑性较强的指令,比如修改某一个参数,用话题传输就不太合适了。

5.消息结构

最后,既然是数据传输,发布者和订阅者就得统一数据的描述格式,不能一个说英文,一个理解成了中文。在ROS中,话题通信数据的描述格式称之为消息,对应编程语言中数据结构的概念。比如这里的一个图像数据,就会包含图像的长宽像素值、每个像素的RGB等等,在ROS中都有标准定义。

消息是ROS中的一种接口定义方式,与编程语言无关,我们也可以通过.msg后缀的文件自行定义,有了这样的接口,各种节点就像积木块一样,通过各种各样的接口进行拼接,组成复杂的机器人系统。

二、话题实例

1.Hello World话题通信

在这里插入图片描述
启动第一个终端,运行话题的发布者节点:

ros2 run learning_topic topic_helloworld_pub

在这里插入图片描述
启动第二个终端,运行话题的订阅者节点:

ros2 run learning_topic topic_helloworld_sub

在这里插入图片描述

发布者代码解析

import rclpy                                     # ROS2 Python接口库
from rclpy.node import Node                      # ROS2 节点类
from std_msgs.msg import String                  # **字符串消息类型**

"""
创建一个发布者节点
"""
class PublisherNode(Node):

    def __init__(self, name):
        super().__init__(name)                                    # ROS2节点父类初始化
        self.pub = self.create_publisher(String, "chatter", 10)   # **创建发布者对象(消息类型、话题名、队列长度)**
        self.timer = self.create_timer(0.5, self.timer_callback)  # 创建一个定时器(单位为秒的周期,定时执行的回调函数)

    def timer_callback(self):                                     # 创建定时器周期执行的回调函数
        msg = String()                                            # **创建一个String类型的消息对象**
        msg.data = 'Hello World'                                  # **填充消息对象中的消息数据**
        self.pub.publish(msg)                                     # 发布话题消息
        self.get_logger().info('Publishing: "%s"' % msg.data)     # 输出日志信息,提示已经完成话题发布

def main(args=None):                                 # ROS2节点主入口main函数
    rclpy.init(args=args)                            # ROS2 Python接口初始化
    node = PublisherNode("topic_helloworld_pub")     # 创建ROS2节点对象并进行初始化
    rclpy.spin(node)                                 # 循环等待ROS2退出
    node.destroy_node()                              # 销毁节点对象
    rclpy.shutdown()                                 # 关闭ROS2 Python接口

完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:

    entry_points={
    
        'console_scripts': [
         'topic_helloworld_pub  = learning_topic.topic_helloworld_pub:main',
        ],
    },

流程总结
对以上程序进行分析,如果我们想要实现一个发布者,流程如下:

编程接口初始化
创建节点并初始化
创建发布者对象
创建并填充话题消息
发布话题消息
销毁节点并关闭接口

订阅者代码解析

import rclpy                      # ROS2 Python接口库
from rclpy.node   import Node     # ROS2 节点类
from std_msgs.msg import String   # ROS2标准定义的String消息

"""
创建一个订阅者节点
"""
class SubscriberNode(Node):

    def __init__(self, name):
        super().__init__(name)                             # ROS2节点父类初始化
        self.sub = self.create_subscription(\
            String, "chatter", self.listener_callback, 10) # 创建订阅者对象(消息类型、话题名、订阅者回调函数、队列长度)

    def listener_callback(self, msg):                      # 创建回调函数,执行收到话题消息后对数据的处理
        self.get_logger().info('I heard: "%s"' % msg.data) # 输出日志信息,提示订阅收到的话题消息

def main(args=None):                               # ROS2节点主入口main函数
    rclpy.init(args=args)                          # ROS2 Python接口初始化
    node = SubscriberNode("topic_helloworld_sub")  # 创建ROS2节点对象并进行初始化
    rclpy.spin(node)                               # 循环等待ROS2退出
    node.destroy_node()                            # 销毁节点对象
    rclpy.shutdown()                               # 关闭ROS2 Python接口

完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:

    entry_points={
    
        'console_scripts': [
         'topic_helloworld_pub  = learning_topic.topic_helloworld_pub:main',
         'topic_helloworld_sub  = learning_topic.topic_helloworld_sub:main',
        ],
    },

流程总结
对以上程序进行分析,如果我们想要实现一个订阅者,流程如下:

编程接口初始化
创建节点并初始化
创建订阅者对象
回调函数处理话题数据
销毁节点并关闭接口

同样也可以用机器视觉来解释,这里就不过多赘述了,可以去看古月的视频。

2.话题命令行操作

ros2 topic list                # 查看话题列表
ros2 topic info <topic_name>   # 查看话题信息
ros2 topic hz <topic_name>     # 查看话题发布频率
ros2 topic bw <topic_name>     # 查看话题传输带宽
ros2 topic echo <topic_name>   # 查看话题数据
ros2 topic pub <topic_name> <msg_type> <msg_data>   # 发布话题消息

总结

话题通信的特性是单向传输、异步通信,适合周期性的数据传递,对于一个复杂的机器人系统来讲,这种特性肯定无法满足所有数据传输的需求.

原网站

版权声明
本文为[我与nano]所创,转载请带上原文链接,感谢
https://qichenxi.blog.csdn.net/article/details/125586259