导览
你将从该单元学到:
什么是ROS主题?如何管理它们?
什么是发布器?如何创建一个发布器?
什么是主题消息?它们是如何工作的?
什么是订阅器?如何创建一个消息订阅器?
如何创建自己的消息?
keyword:管理主题,创建发布器,主题消息的工作方式,创建消息订阅器,创建自定义信息
课前总结
主题
- 主题是*ROS节点发布和读取消息的通道*
- 节点使用主题向其他节点 发布信息,进行通信
- 节点创建发布器,发布器在某主题上发布消息,消息具有某种结构(称为类型)
- rostopic info /counter :获取主题的相关信息,包括发布到该主题上的节点,发布到该主题上的消息类型(例如Int32)
- rostopic list | grep ‘/counter’ :过滤出该主题
- rostopic echo /counter ,查看主题的实时输出(即正在发布到该主题的消息)
- rostopic echo -n1 读取发布到主题上的最后一条消息
消息
- 主题通过消息处理信息,消息有各种类型
- 消息定义在 .msg 文件中,该文件位于msg目录
- 获取消息结构(包含哪些变量等) rosmsg show std_msgs/Int32
- Int32消息来自于功能包 std_msgs,它位于 msg目录中
发布器与订阅器
- 发布器是实现向某节点发布信息的节点
- 订阅器是实现从主题读取信息功能的节点
- rostopic pub 向指定的主题发布具有特定数据类型的消息
- 创建自定义消息五步走
- rospy.Publisher(‘/counter’, Int32, queue_size=1)
- sub = rospy.Subscriber(‘/counter’, Int32, callback)
- rospy.Publisher(‘counter’, Int32)
发布器
点击IPython notebook右上角的“play”按钮,运行下面的Python代码
通过[CTRL]+[Enter] 快捷键运行
#! /usr/bin/env python
import rospy
from std_msgs.msg import Int32
rospy.init_node('topic_publisher')
pub = rospy.Publisher('/counter', Int32, queue_size=1)
#创建主题
rate = rospy.Rate(2)
count = Int32()
count.data = 0
while not rospy.is_shutdown():
pub.publish(count)
#发布整数
count.data += 1
rate.sleep()
程序:创建了一个名为/counter 的主题,并通过它发布了一个无限增加的整数
主题就像一个管道。 节点使用主题向其他节点发布信息 ,进行通信
使用rostopic list查看系统中主题的数量。也可以查看某个特定的主题
rostopic list
获取ROS系统中可用的主题列表
查看一个名为 ‘/counter’的主题
rostopic list | grep ‘/counter’
扫描二维码关注公众号,回复: 2748829 查看本文章
解释:列出了所有正在运行的主题,并使用grep命令过滤出/counter的那个主题
rostopic info
获取一个主题的信息(理解为结构)
user ~ $ rostopic info /counter
Type: std_msgs/Int32
Publishers:
* /topic_publisher (http://ip-172-31-16-133:47971/)
Subscribers: None
输出表明,发布信息的类型为(std_msgs/Int32), 发布该信息的节点为 (/topic_publisher),是否有节点在监听该消息(无)
rostopic echo
查看主题的实时输出或称读取一个主题中正在发布的消息
该命令将会输出发布到该主题中的所有消息, 有时这样是很烦人的(例如,当消息很多时,或者消息结构很大时)。在这种情况下,你可以使用下面的命令读取发布到某一主题上的最后一条消息
rostopic echo -n1
code review
#! /usr/bin/env python
import rospy # 导入ROS的Python库
from std_msgs.msg import Int32 # 从std_msgs功能包导入Int32消息
rospy.init_node('topic_publisher') # 初始化一个名为'topic_publisher'的节点
pub = rospy.Publisher('counter', Int32) # 创建一个发布器对象,将在/count主题上发布类型为Int32的消息
rate = rospy.Rate(2) # 设置发布频率为2 Hz
count = Int32() # 创建一个类型为Int32的变量,即创建一个消息的实例
count.data = 0 # 初始化'count' 变量
while not rospy.is_shutdown(): # 创建一个循环,当有人停止程序执行时循环结束
pub.publish(count) # 发布变量 'count'值
count.data += 1 # 变量'count' 值增加
rate.sleep() # 确保发布频率维持在2 Hz
总的来说,这段代码 初始化一个节点并创建一个发布器,该发布器不停地向’/counter’ 主题发布一连串的连续整数。 因此,发布器是一个不停地向某一主题发布消息的节点。 那么,什么是主题?
主题是一个ROS节点发布和读取消息的通道
主题相关命令
查看 rostopic 命令的不同选项
rostopic -h
消息
主题通过消息处理信息。在ROS中,有许多不同类型的消息。
在前面执行的代码中,消息类型为std_msgs/Int32。除了ROS提供的标准消息,你也可以创建自定义的消息,但我们推荐使用ROS默认的消息类型
消息定义在 .msg 文件中,它位于一个功能包的msg目录中
rosmsg show
获取一个消息的信息(属性)
实例
rosmsg show std_msgs/Int32 #获取std_msgs/Int32消息的信息
#输出结果
user ~ $ rosmsg show std_msgs/Int32
[std_msgs/Int32]:
int32 data
该例中,Int32 消息只有一个类型为int32,名为data的变量。Int32消息来自于功能包 std_msgs,它位于 msg目录中。 如果你想查看Int32.msg文件的内容,执行下面的命令:
roscd std_msgs/msg/
创建自己的发布器使机器人移动
待补
订阅器
- 主题是节点发布或读取信息的通道。使用发布器向主题发布数据。
- 发布器实现发布信息
- 订阅器实现读取信息
实现从一个主题读取信息的功能的工具叫做订阅器。 订阅器是一个从某一主题读取信息的节点(发布器是向某主题发布信息的节点)
user ~ $ rostopic echo /counter
WARNING: no messages received and simulated time is active.
Is /clock being published?
意味着 没有人向/counter主题发布消息, 因此没有信息可以读取。接下来,让我们向该主题发布一些信息,看看会发生什么。实现该功能需要一个新的命令:
rostopic pub
该命令将向指定的主题发布具有特定数据的特定类型的消息
rostopic pub /counter std_msgs/Int32 5
user ~ $ rostopic echo /counter
WARNING: no messages received and simulated time is active.
Is /clock being published?
data:
5
---
表明你发布的数据已被你的订阅器程序(该数据值打印在屏幕上)接收
#! /usr/bin/env python
import rospy
from std_msgs.msg import Int32
def callback(msg): # 定义一个名为callback的函数用来接收msg参数
print msg.data # 输出"msg"参数中的"data"值
rospy.init_node('topic_subscriber') # 初始化一个名为'topic_subscriber'的节点
sub = rospy.Subscriber('/counter', Int32, callback) # 创建一个订阅器对象,监听/counter主题。每当从该主题读取到消息时,调用"callback"函数
rospy.spin() # 创建一个使程序保持运行的循环。
- 查看运行的代码输出:
5
创建了一个订阅器对象来监听/counter主题。每当它从该主题读取到消息时,它就调用一个打印msg的函数。刚开始时,由于没有向/counter主题发布消息,所以它什么都没做。当你运行rostopic pub命令后,你向/counter主题发布了一条消息,因此该订阅器在IPython的输出中打印了该消息中的数值,你还可以在 rostopic echo的输出中看到该消息。
创建自定义信息
准备CMakeLists.txt和package.xml 来进行自定义主题和消息的编译
如果我需要发布一些其他类型的数据(非int32),我该使用什么类型的消息? 你可以使用ROS定义的所有消息类型(rosmsg list) 。如果这些消息都不能满足你的需要,你可以自己创建一个新的。
创建步骤
在你的功能包中创建一个名为"msg"的目录
在该目录中,创建一个名为Name_of_your_message.msg的文件(详见下面)
修改 CMakeLists.txt 文件 (详见下面)
修改package.xml 文件 (详见下面)
编译
在程序中使用该消息
S1:
roscd
mkdir msg
S2:
float32 years
float32 months
float32 days
S3:
编辑CMakeLists.txt中的四个函数,如下:
find_package()
add_message_files()
generate_messages()
catkin_package()
- find_package()
为了编译主题、服务和行为的消息,所有功能包都需要该函数。 在package.xml, 你必须把它们声明为 build_depend
find_package(catkin REQUIRED COMPONENTS
rospy
std_msgs
message_generation # 这里添加 message_generation,在其他功能包的后面
)
- add_message_files()
该函数包含了该功能包所要编译的全部消息(在msg文件夹中)。该文件看起来是这样的:
add_message_files(
FILES
Age.msg
) # 别忘了去掉括号和add_message_files前面的注释符号
- generate_messages()
导入消息编译需要的功能包
generate_messages(
DEPENDENCIES
std_msgs
) # 别忘了去掉前面的注释
- catkin_package()
声明所有需要的功能包。 这里声明的所有功能包必须在package.xml设置为run_depend
catkin_package(
CATKIN_DEPENDS rospy message_runtime # This will NOT be the only thing here
)
S4:下方代码添加到package.xml文件
message_generation
message_runtime
S5:
编译该msg文件
roscd; cd ..
catkin_make
source devel/setup.bash
注释:
- 当你编译新的消息以及使用这些消息之前还有一个额外的步骤。你必须在WebShell中切换到 catkin_ws 目录,然后输入命令 source devel/setup.bash。
- 该命令运行bash文件,设置创建的新消息
- source你将使用的ALL the webwhells,以便ROS能够找到该消息
- 如果不这样做,可能会出现python导入错误,说找不到生成的消息。
避免Python文件和它所在的功能包的名称相同
激光扫描仪的消息结构
user ~ $ rosmsg show sensor_msgs/LaserScan
std_msgs/Header header
uint32 seq
time stamp
string frame_id
float32 angle_min
float32 angle_max
float32 angle_increment
float32 time_increment
float32 scan_time
float32 range_min
float32 range_max
float32[] ranges <-- Use only this one
float32[] intensities
避免Python文件和它所在的功能包的名称相同。