一、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
获取更详细的信息
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="hermanye233@icloud.com">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='hermanye233@icloud.com',
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