ROS2教程 04 话题Topic

一、ROS2 话题Topic 示意图

在这里插入图片描述
ROS2的Topic可以是一对一,一对多,多对一,多对多,同一个话题Topic可以被不同的节点Node订阅与发布

二、与ros1区别

topic下有多种命令,以下是ros1的topic命令:
可以看到和ros2的topic没有什么区别

Commands: rostopic bw display bandwidth used by topic rostopic delay
display delay of topic from timestamp in header rostopic echo print
messages to screen rostopic find find topics by type rostopic hz
display publishing rate of topic rostopic info print information about
active topic rostopic list 获取话题列表 list active topics rostopic pub
发布话题数据 publish data to topic rostopic type print topic or field type

三、ros2 topic

① ros2 topic list

输出当前存在的话题Topic列表

ros2 topic list
OUTPUT:
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

输出话题名同时输出话题类型

当添加 -t 后缀时将同时输出话题列表与各个话题的消息类型Message Type

ros2 topic list -t
OUTPUT:
/parameter_events [rcl_interfaces/msg/ParameterEvent]
/rosout [rcl_interfaces/msg/Log]
/turtle1/cmd_vel [geometry_msgs/msg/Twist]
/turtle1/color_sensor [turtlesim/msg/Color]
/turtle1/pose [turtlesim/msg/Pose]

② ros2 topic echo

如果要查看topic list中某个具体的的话题正在发布的内容,可以使用ros2 topic echo + 话题名

ros2 topic echo /turtle1/cmd_vel
OUTPUT:
---
linear:
  x: 2.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0
---
linear:
  x: 2.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0
---

③ ros2 topic pub

pub可以在终端中直接发布命令,这在需要直接在命令行中简单输入即可调试时比较好用

ros2 topic pub <topic_name> <msg_type> '<args>'

不同的发布方式

单次发布
其中–once代表仅循环发布一次,然后退出,输入的结构内容是用yaml语法写的,因此在命令行中看起来比较繁杂。

ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
OUTPUT:
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.8))

循环发布
在pub后加入 --rate 1,代表循环频率为1HZ

ros2 topic pub --rate 1 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
OUTPUT:
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.8))

publishing #2: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.8))

publishing #3: geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=2.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=1.8))

④ ros2 topic info

info可以显示话题Topic的类型与多少个节点Node正在发布它与订阅它

ros2 topic info /turtle1/cmd_vel

获取更详细的信息

扫描二维码关注公众号,回复: 16848412 查看本文章
ros2 topic info /turtle1/cmd_vel -v
# ros2 topic info /turtle1/cmd_vel -verbose
OUTPUT:
Type: geometry_msgs/msg/Twist
Publisher count: 1
Subscription count: 2

⑤ ros2 topic type

查看话题Topic的消息类型Message Type

ros2 topic type /turtle1/cmd_vel
OUTPUT:
geometry_msgs/msg/Twist

以下命令用的不多:

⑥ ros2 topic hz

查看话题Topic发布的平均频率HZ

ros2 topic hz /turtle1/cmd_vel
OUTPUT:
average rate: 1.000
	min: 1.000s max: 1.000s std dev: 0.00001s window: 2
average rate: 1.000
	min: 0.999s max: 1.000s std dev: 0.00030s window: 4
average rate: 1.000
	min: 0.999s max: 1.000s std dev: 0.00025s window: 6
average rate: 1.000
	min: 0.999s max: 1.001s std dev: 0.00042s window: 7

⑦ ros2 topic bw

查看话题所占用的带宽

ros2 topic bw /turtle1/cmd_vel
OUTPUT:
91 B/s from 3 messages
	Message size mean: 52 B min: 52 B max: 52 B
153 B/s from 8 messages
	Message size mean: 52 B min: 52 B max: 52 B
126 B/s from 9 messages
	Message size mean: 52 B min: 52 B max: 52 B
198 B/s from 18 messages
	Message size mean: 52 B min: 52 B max: 52 B
191 B/s from 21 messages
	Message size mean: 52 B min: 52 B max: 52 B
186 B/s from 24 messages
	Message size mean: 52 B min: 52 B max: 52 B

⑧ ros2 topic find

由消息类型Message Type 反查消息类型为该类型Type的话题Topic

ros2 topic find geometry_msgs/msg/Twist
OUTPUT:
/turtle1/cmd_vel

⑨ ros2 topic delay

delay Display delay of topic from timestamp in header

四、查看Message Type的具体结构

当要查看具体消息类型Message Type的结构时,可以使用如下命令:

ros2 interface show geometry_msgs/msg/Twist
OUTPUT:
Vector3  linear
	float64 x
	float64 y
	float64 z
Vector3  angular
	float64 x
	float64 y
	float64 z

五、Topic机制

在ROS2中已经没有了Master的概念,避免master挂了,以提升系统的稳定性

六、发布者Publisher

1.新建功能包

ros2 pkg create --build-type ament_python py_pub_sub

2.新建源码文件

在py_pub_sub功能包的py_pub_sub文件夹下新建源码文件publisher_member_function.py

touch publisher_member_function.py

3.编写源码

ros2中提供的消息接口可以通过以下命令来查看

ros2 interface list

进而查看具体的消息类型的结构

ros2 interface show std_msgs/msg/String
OUTPUT:
# This was originally provided as an example message.
# It is deprecated as of Foxy
# It is recommended to create your own semantically meaningful message.
# However if you would like to continue using this please use the equivalent in example_msgs.

string data

编写步骤

编写步骤:
1.编程接口初始化
2.创建节点并初始化
3.创建发布者对象
4.创建话题并填充话题消息
5.发布话题消息
6.销毁节点并关闭接口

示例源码

import rclpy # rclpy是ROS Client Library for Python的缩写,与Node有关的内容在这个库中
from rclpy.node import Node 
from std_msgs.msg import String # std_msgs是ROS内置的数据类型库,里面有msg、srv等一系列基础的数据类型 


class MinimalPublisher(Node): # Node为这个类的父类

    def __init__(self):
        super().__init__('minimal_publisher') # 调用父类中Node的构造函数,在此处直接为其赋名minimal_publisher
        # 创建publisher,数据类型为String,话题名为topic_name, 队列长度为10,它是QoS (quality of service) setting之一
        self.example_publisher = self.create_publisher(String, 'topic_name', 10)   # 创建发布者对象     
        timer_period = 0.5  # 定时器周期 in seconds
        self.timer = self.create_timer(timer_period, self.timer_callback) # 创建定时器 每个周期调用一次回调函数self.timer_callback
        self.i = 0 # 用于回调函数的一个计数器counter

    def timer_callback(self): # 定时器的回调函数
        msg = String() # 定义消息类型为String类
        msg.data = 'Hello World: %d' % self.i # 添加消息内容
        self.example_publisher.publish(msg) # 发布消息
        self.get_logger().info('Publishing: "%s"' % msg.data) # 可选的打印日志到控制台console
        self.i += 1

# 上面的部分为类内容
# 下面的部分是main函数
def main(args=None): # 主函数
    rclpy.init(args=args) # 初始化 rclpy

    minimal_publisher = MinimalPublisher() # 定义MinimalPublisher类

    rclpy.spin(minimal_publisher) # 循环

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_publisher.destroy_node() # 可以不写,会自动执行
    rclpy.shutdown() #关闭


if __name__ == '__main__': # 该条下的所有代码仅当本脚本直接执行时会触发,如果在其他文件引用本文件,则不会触发以下的代码
    main()

4.添加依赖

在功能包目录下打开package.xml,修改以下内容[可选,不影响使用]
例子:

<description>Examples of minimal publisher/subscriber using rclpy</description>
<maintainer email="[email protected]">Herman Ye</maintainer>
<license>Apache License 2.0</license>

继续添加内容[必须]
当功能包里的代码被执行时,这些语句声明了功能包的依赖

<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>

5.添加入口点

打开setup.py,添加入口点

maintainer='Herman Ye',
maintainer_email='[email protected]',
description='Examples of minimal publisher/subscriber using rclpy',
license='Apache License 2.0',

在entry_points下的这个位置添加以下命令

'talker = py_pub_sub.publisher_member_function:main',

最终效果:

entry_points={
    
    
    'console_scripts': [
    'talker = py_pub_sub.publisher_member_function:main',
    ],
},

6.检查setup.cfg

setup.cfg是自动填写的,它将功能包的可执行文件放入lib中,ros2 run将会在lib中查找这些执行性文件是否存在并调用

[develop]
script_dir=$base/lib/py_pub_sub
[install]
install_scripts=$base/lib/py_pub_sub

七、订阅 subscription

1.新建源码文件

在功能包src文件夹下新建源码文件pose_subscriber.cpp

touch pose_subscriber.cpp

2.编写源码

编写步骤

1.编程接口初始化
2.创建节点并初始化
3.创建订阅者对象
4.通过回调函数处理话题数据
5.销毁节点、关闭接口
源码部分注释同publisher

示例源码

import rclpy 
from rclpy.node import Node

from std_msgs.msg import String 


class MinimalSubscriber(Node):

    def __init__(self):
        super().__init__('minimal_subscriber')
        # 订阅者的构造函数和回调函数不需要定时器Timer,因为当收到Message时,就已经启动回调函数了
        # 注意此处不是subscriber,而是subscription
        # 数据类型,话题名,回调函数名,队列长度
        self.subscription = self.create_subscription(String,'topic_name',self.listener_callback,10)
        self.subscription  # prevent unused variable warning

    def listener_callback(self, msg):
        self.get_logger().info('I heard: "%s"' % msg.data) #回调函数内容为打印msg.data里的内容


def main(args=None):
    rclpy.init(args=args)

    minimal_subscriber = MinimalSubscriber()

    rclpy.spin(minimal_subscriber)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_subscriber.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

3.添加依赖

因为之前添加过了,所以不用再添加,如果subscriber有额外要使用的库,则需要添加新增的库

4.添加入口点

打开setup.py,添加入口点
在entry_points下的这个位置添加以下命令

'listener = py_pub_sub.subscriber_member_function:main',

最终效果:

    entry_points={
    
    
        'console_scripts': [
        'talker = py_pub_sub.publisher_member_function:main',
        'listener = py_pub_sub.subscriber_member_function:main',
        ],
    },

ros2 run 在功能包中所能观测到的可执行文件的名字即此处设置的talker与listener

八、测试发布-话题-订阅通信

1.编译

colcon build --packages-select py_pub_sub

2.运行测试

ros2 run py_pub_sub listener
ros2 run py_pub_sub talker

猜你喜欢

转载自blog.csdn.net/m0_56661101/article/details/124863457