理解ROS话题
开始
roscore
首先确保roscore正在运行, 打开一个新终端:
$ roscore
如果你没有退出在上一篇教程中运行的roscore,则可能会显示错误消息:
- roscore cannot run as another roscore/master is already running.
- Please kill other roscore/master processes before relaunching
这是正常的,因为只需要有一个roscore在运行就够了。
turtlesim
在本教程中我们也会使用到turtlesim,打开一个新终端:
$ rosrun turtlesim turtlesim_node
通过键盘遥控turtle
我们还需要通过键盘来控制turtle,打开一个新终端:
$ rosrun turtlesim turtle_teleop_key
- [ INFO] 1254264546.878445000: Started node [/teleop_turtle], pid [5528], bound on [aqy], xmlrpc port [43918], tcpros port [55936], logging to [~/ros/ros/log/teleop_turtle_5528.log], using [real] time
- Reading from keyboard
- ---------------------------
- Use arrow keys to move the turtle.
现在你可以使用键盘上的方向键来控制turtle运动了。如果不能控制,请选中turtle_teleop_key的终端窗口以确保按键输入能够被捕获。
现在可以让乌龟来回走动了,让我们看看幕后发生的事情。
ROS话题
turtlesim_node节点和turtle_teleop_key节点之间是通过一个ROS话题来相互通信的。turtle_teleop_key在话题上发布键盘按下的消息,turtlesim则订阅该话题以接收消息。让我们使用rqt_graph来显示当前运行的节点和话题。
注意:如果你使用的是ROS electric或早期版本,那么rqt是不可用的,请使用rxgraph代替。
使用rqt_graph
rqt_graph用动态的图显示了系统中正在发生的事情。rqt_graph是rqt程序包中的一部分。如果你发现没有安装,请:
- $ sudo apt-get install ros-<distro>-rqt
- $ sudo apt-get install ros-<distro>-rqt-common-plugins
将<distro>替换成你安装的ROS发行版简称(比如kinetic或noetic等)。
打开一个新终端:
$ rosrun rqt_graph rqt_graph
你会看到一个窗口:
如果把鼠标放在/turtle1/command_velocity上方,相应的ROS节点(这里是蓝色和绿色)和话题(这里是红色)就会高亮显示。可以看到,turtlesim_node和turtle_teleop_key节点正通过一个名为/turtle1/command_velocity的话题来相互通信。
介绍rostopic
rostopic命令工具能让你获取ROS话题的信息。
你可以使用帮助选项查看可用的rostopic的子命令,例如:
$ rostopic -h
- rostopic is a command-line tool for printing information about ROS Topics.
- 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
- Type rostopic <command> -h for more detailed usage, e.g. 'rostopic echo -h'
或者在输入rostopic 之后双击Tab键输出可能的子命令:
$ rostopic
bw echo find hz info list pub type
接下来我们将使用其中的一些子命令来调查turtlesim。
使用rostopic echo
rostopic echo可以显示在某个话题上发布的数据。
用法:
rostopic echo [topic]
让我们看看由turtle_teleop_key节点发布的“指令、速度”数据。
在ROS Hydro及更新版本中,这些数据发布在/turtle1/cmd_vel话题上。打开一个新终端:
$ rostopic echo /turtle1/cmd_vel
在ROS Groovy及早期版本中,这些数据发布在/turtle1/command_velocity话题上。打开一个新终端:
$ rostopic echo /turtle1/command_velocity
你可能会看到什么都没发生,因为现在还没有数据被发布到该话题上。可以通过按下键盘方向键让turtle_teleop_key节点发布数据。记得如果不能控制乌龟,请选中turtle_teleop_key的终端窗口以确保按键输入能够被捕获。
在ROS Hydro及更新版本中,当按下向上键时,应该看到以下内容:
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
---
在ROS Groovy及早期版本中,当按下向上键时,应该看到以下内容:
---
linear: 2.0
angular: 0.0
---
linear: 2.0
angular: 0.0
---
linear: 2.0
angular: 0.0
---
linear: 2.0
angular: 0.0
---
linear: 2.0
angular: 0.0
现在让我们再看一下rqt_graph。先按下左上角的刷新按钮以显示新节点。正如你所看到的,rostopic echo(这里以红色显示)现在也订阅了turtle1/command_velocity话题。
使用rostopic list
rostopic list能够列出当前已被订阅和发布的所有话题。
让我们查看一下list子命令需要的参数。打开一个新终端:
$ rostopic list -h
- Usage: rostopic list [/topic]
- Options:
- -h, --help show this help message and exit
- -b BAGFILE, --bag=BAGFILE
- list topics in .bag file
- -v, --verbose list full details about each topic
- -p list only publishers
- -s list only subscribers
在rostopic list中使用verbose选项:
$ rostopic list -v
会列出所有发布和订阅的主题及其类型的详细信息。
在ROS Hydro及更新版本中,
- Published topics:
- * /turtle1/color_sensor [turtlesim/Color] 1 publisher
- * /turtle1/cmd_vel [geometry_msgs/Twist] 1 publisher
- * /rosout [rosgraph_msgs/Log] 2 publishers
- * /rosout_agg [rosgraph_msgs/Log] 1 publisher
- * /turtle1/pose [turtlesim/Pose] 1 publisher
- Subscribed topics:
- * /turtle1/cmd_vel [geometry_msgs/Twist] 1 subscriber
- * /rosout [rosgraph_msgs/Log] 1 subscriber
在ROS Groovy及早期版本中,
- Published topics:
- * /turtle1/color_sensor [turtlesim/Color] 1 publisher
- * /turtle1/command_velocity [turtlesim/Velocity] 1 publisher
- * /rosout [roslib/Log] 2 publishers
- * /rosout_agg [roslib/Log] 1 publisher
- * /turtle1/pose [turtlesim/Pose] 1 publisher
- Subscribed topics:
- * /turtle1/command_velocity [turtlesim/Velocity] 1 subscriber
- * /rosout [roslib/Log] 1 subscriber
ROS消息
话题的通信是通过节点间发送ROS消息实现的。为了使发布者(turtle_teleop_key)和订阅者(turtulesim_node)进行通信,发布者和订阅者必须发送和接收相同类型的消息。这意味着话题的类型是由发布在它上面消息的类型决定的。使用rostopic type命令可以查看发布在话题上的消息的类型。
使用rostopic type
rostopic type命令用来查看所发布话题的消息类型。
用法:
rostopic type [topic]
在ROS Hydro及更新版本中,
- 运行:
$ rostopic type /turtle1/cmd_vel
-
- 你会看到:
geometry_msgs/Twist
我们可以使用rosmsg查看消息的详细信息:
$ rosmsg show geometry_msgs/Twist
-
- geometry_msgs/Vector3 linear
- float64 x
- float64 y
- float64 z
- geometry_msgs/Vector3 angular
- float64 x
- float64 y
- float64 z
在ROS Groovy及早期版本中,
- 运行:
$ rostopic type /turtle1/command_velocity
-
- 你会看到:
turtlesim/Velocity
我们可以使用rosmsg查看消息的详细信息:
$ rosmsg show turtlesim/Velocity
-
- float32 linear
- float32 angular
现在我们已经知道了turtlesim节点想要的消息类型,然后就可以发布命令给turtle了。
继续学习rostopic
既然我们已经了解了ROS消息,接下来我们结合消息来使用rostopic。
使用rostopic pub
rostopic pub可以把数据发布到当前某个正在广播的话题上。
用法:
rostopic pub [topic] [msg_type] [args]
在ROS Hydro及更新版本中,示例:
$ rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
在ROS Groovy及早期版本中,示例:
$ rostopic pub -1 /turtle1/command_velocity turtlesim/Velocity -- 2.0 1.8
以上命令会发送一条消息给turtlesim,告诉它以2.0大小的线速度和1.8大小的角速度移动。
这是一个十分复杂的例子,因此让我们来详细分析一下其中的每一个参数。
在ROS Hydro及更新版本中,
- 这条命令将消息发布到指定的话题:
rostopic pub
- 这一选项会让rostopic只发布一条消息,然后退出:
-1
- 这是要发布到的话题的名称:
/turtle1/cmd_vel
- 这是发布到话题时要使用的消息的类型:
geometry_msgs/Twist
- 这一选项(两个破折号)用来告诉选项解析器,表明之后的参数都不是选项。如果参数前有破折号(-)比如负数,那么这是必需的。
--
- 如前所述,一个turtlesim/Velocity消息有两个浮点型元素:linear和angular。在本例中,'[2.0, 0.0, 0.0]'表示linear的值为x=2.0, y=0.0, z=0.0,而'[0.0, 0.0, 1.8]'是说angular的值为x=0.0, y=0.0, z=1.8。这些参数实际上使用的是YAML语法,在YAML命令行文档中有描述。
'[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
在ROS Groovy及早期版本中,
- 这条命令将消息发布到指定的话题:
rostopic pub
- 这一选项会让rostopic只发布一条消息,然后退出:
-1
- 这是要发布到的话题的名称:
/turtle1/command_velocity
- 这是发布到话题时要使用的消息的类型:
turtlesim/Velocity
- 这一选项(两个破折号)用来告诉选项解析器,表明之后的参数都不是选项。如果参数前有破折号(-)比如负数,那么这是必需的。
--
- 如前所述,一个turtlesim/Velocity消息有两个浮点型元素:linear和angular。在本例中,2.0是linear的值,而1.8则是angular的值。这些参数实际上使用的是YAML语法,在YAML命令行文档中有描述。
2.0 1.8
你可能已经注意到turtle已经停止移动了。这是因为turtle需要一个稳定的频率为1Hz的指令流才能保持移动状态。我们可以使用rostopic pub -r命令来发布源源不断的命令:
在ROS Hydro及更新版本中,
- $ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'
在ROS Groovy及早期版本中,
- $ rostopic pub /turtle1/command_velocity turtlesim/Velocity -r 1 -- 2.0 -1.8
这将以1 Hz的速度发布velocity指令到velocity话题上。
我们还可以看一下rqt_graph中的情形。按左上角的刷新按钮,可以看到rostopic pub节点(此处为红色)正在与rostopic echo节点(此处为绿色)进行通信:
可以看到,turtle正沿着一个圆形轨迹持续运动。我们可以在新终端中通过rostopic echo命令来查看turtlesim所发布的数据:
rostopic echo /turtle1/pose
使用rostopic hz
rostopic hz报告数据发布的速率。
用法:
rostopic hz [topic]
我们看一下turtlesim_node发布/turtle/pose得有多快:
$ rostopic hz /turtle1/pose
你会看到:
- subscribed to [/turtle1/pose]
- average rate: 59.354
- min: 0.005s max: 0.027s std dev: 0.00284s window: 58
- average rate: 59.459
- min: 0.005s max: 0.027s std dev: 0.00271s window: 118
- average rate: 59.539
- min: 0.004s max: 0.030s std dev: 0.00339s window: 177
- average rate: 59.492
- min: 0.004s max: 0.030s std dev: 0.00380s window: 237
- average rate: 59.463
- min: 0.004s max: 0.030s std dev: 0.00380s window: 290
现在我们可以知道了turtlesim正以大约60Hz的频率发布有关乌龟的数据。我们也可以结合rostopic type和rosmsg show命令来获取关于某个话题的更深层次信息:
在ROS Hydro及更新版本中,
- $ rostopic type /turtle1/cmd_vel | rosmsg show
在ROS Groovy及早期版本中,
- $ rostopic type /turtle1/command_velocity | rosmsg show
到此我们已经使用rostopic调查了这些主题,接下来将使用另一个工具来查看turtlesim发布的数据。
使用rqt_plot
注意:如果你使用的是ROS electric或早期版本,那么rqt是不可用的,请使用rxgraph代替。
rqt_plot命令可以在滚动时间图上显示发布到某个话题上的数据。这里我们将使用rqt_plot命令来绘制正被发布到/turtle1/pose话题上的数据。首先,在一个新终端中输入:
$ rosrun rqt_plot rqt_plot
这会弹出一个新窗口,可以在左上角的文本框里面添加任何想要绘制的话题。在里面输入/turtle1/pose/x后,之前不能按下的加号按钮将会变亮。按一下该按钮,并对/turtle1/pose/y重复相同的过程。现在你会在图中看到turtle的x-y位置。
按下减号按钮会显示一组菜单可以让你在图中隐藏指定的话题。现在隐藏掉你刚才添加的话题并添加/turtle1/pose/theta,你会看到如下所示的图:
本部分教程到此为止,请使用Ctrl+C退出rostopic命令,但要保持turtlesim继续运行。
到此我们已经理解了ROS话题是如何工作的
理解ROS服务和参数
本教程假设上一教程启动的turtlesim_node仍在运行,现在我们来看看turtlesim提供了什么服务:
ROS服务
服务(Services)是节点之间通讯的另一种方式。服务允许节点发送一个请求(request)并获得一个响应(response)。
使用rosservice
rosservice可以很容易地通过服务附加到ROS客户端/服务器框架上。rosservice有许多可用于服务的命令,如下所示:
用法:
rosservice list 输出活跃服务的信息
rosservice call 用给定的参数调用服务
rosservice type 输出服务的类型
rosservice find 按服务的类型查找服务
rosservice uri 输出服务的ROSRPC uri
rosservice list
$ rosservice list
list命令显示turtlesim节点提供了9个服务:reset, clear, spawn, kill, turtle1/set_pen, /turtle1/teleport_absolute, /turtle1/teleport_relative, turtlesim/get_loggers, turtlesim/set_logger_level。同时还有两个与rosout节点有关的服务:/rosout/get_loggers和/rosout/set_logger_level。
- /clear
- /kill
- /reset
- /rosout/get_loggers
- /rosout/set_logger_level
- /spawn
- /teleop_turtle/get_loggers
- /teleop_turtle/set_logger_level
- /turtle1/set_pen
- /turtle1/teleport_absolute
- /turtle1/teleport_relative
- /turtlesim/get_loggers
- /turtlesim/set_logger_level
我们使用rosservice type命令进一步查看clear(清除)服务:
rosservice type
用法:
rosservice type [service]
来看看clear服务的类型:
$ rosservice type /clear
- std_srvs/Empty
服务的类型为empty(空),这表明调用这个服务时不需要参数(即,它在发出请求时不发送数据,在接收响应时也不接收数据)。下面我们使用rosservice call命令调用此服务:
rosservice call
用法:
rosservice call [service] [args]
因为服务的类型为empty,所以进行无参数调用:
$ rosservice call /clear
跟想象的一样,它清除了turtlesim_node背景上的轨迹。
再让我们看看服务具有参数的情况。查看spawn(产卵)服务的信息:
$ rosservice type /spawn | rossrv show
- float32 x
- float32 y
- float32 theta
- string name
- ---
- string name
这个服务能让我们可以在给定的位置和角度生成一只新的乌龟。name字段是可选的,这里我们不设具体的名字,让turtlesim自动创建一个。
$ rosservice call /spawn 2 2 0.2 ""
该调用返回了新产生的乌龟的名字:
- name: turtle2
现在我们的turtlesim应该看起来像这样:
使用rosparam
rosparam能让我们在ROS参数服务器(Parameter Server)上存储和操作数据。参数服务器能够存储整型(integer)、浮点(float)、布尔(boolean)、字典(dictionaries)和列表(list)等数据类型。rosparam使用YAML标记语言的语法。一般而言,YAML的表述很自然:1是整型,1.0是浮点型,one是字符串,true是布尔型,[1, 2, 3]是整型组成的列表,{a: b, c: d}是字典。rosparam有很多命令可以用来操作参数,如下所示:
用法:
rosparam set 设置参数
rosparam get 获取参数
rosparam load 从文件中加载参数
rosparam dump 向文件中转储参数
rosparam delete 删除参数
rosparam list 列出参数名
我们来看看现在参数服务器上都有哪些参数:
rosparam list
$ rosparam list
可以看到turtlesim节点在参数服务器上有3个参数用于设定背景颜色:
- /rosdistro
- /roslaunch/uris/host_nxt__43407
- /rosversion
- /run_id
- /turtlesim/background_b
- /turtlesim/background_g
- /turtlesim/background_r
让我们使用rosparam set来试着改变一个参数值:
rosparam set和rosparam get
用法:
rosparam set [param_name]
rosparam get [param_name]
现在我们修改背景颜色的红色通道值:
$ rosparam set /turtlesim/background_r 150
上述指令修改了参数的值,现在我们需要调用clear服务使得参数的修改能生效:
$ rosservice call /clear
现在我们的turtlesim看起来应该像这样:
然后我们来查看参数服务器上其他参数的值。获取背景的绿色通道的值:
$ rosparam get /turtlesim/background_g
- 86
也可以用rosparam get /来显示参数服务器上的所有内容:
$ rosparam get /
- rosdistro: 'noetic
- '
- roslaunch:
- uris:
- host_nxt__43407: http://nxt:43407/
- rosversion: '1.15.5
- '
- run_id: 7ef687d8-9ab7-11ea-b692-fcaa1494dbf9
- turtlesim:
- background_b: 255
- background_g: 86
- background_r: 69
你可能希望将其存储在一个文件中,以便下次可以重新加载它。这通过rosparam很容易就可以实现:
rosparam dump和rosparam load
用法:
rosparam dump [file_name] [namespace]
rosparam load [file_name] [namespace]
在这里,我们将所有的参数写入params.yaml文件:
$ rosparam dump params.yaml
你甚至可以将yaml文件重载入新的命名空间,例如copy_turtle:
$ rosparam load params.yaml copy_turtle
$ rosparam get /copy_turtle/turtlesim/background_b
- 255
至此,我们已经了解了ROS服务和参数的工作原理。
使用rqt_console和roslaunch
注意:如果您使用的是ROS fuerte或早期版本,它们的rqt并不完善。请同时参考这个页面来使用旧的基于rx的工具。
预备工作
本教程会用到rqt和turtlesim这两个软件包。如果你发现没有安装,请先:
$ sudo apt-get install ros-<distro>-rqt ros-<distro>-rqt-common-plugins ros-<distro>-turtlesim
将<distro>替换成你安装的ROS发行版简称(比如kinetic或noetic等)。
注意:你可能已经在之前的某篇教程中构建过rqt和turtlesim。不过如果不确定的话,再安装一次也不会有什么问题。
使用rqt_console和rqt_logger_level
rqt_console连接到了ROS的日志框架,以显示节点的输出信息。rqt_logger_level允许我们在节点运行时改变输出信息的详细级别,包括Debug、Info、Warn和Error`。
现在让我们来看一下turtlesim在rqt_console中输出的信息,同时在使用turtlesim时切换rqt_logger_level中的日志级别。在启动turtlesim之前先在两个新终端中运行rqt_console和rqt_logger_level:
$ rosrun rqt_console rqt_console
$ rosrun rqt_logger_level rqt_logger_level
你会看到弹出两个窗口:
现在让我们在另一个新终端中启动turtlesim:
$ rosrun turtlesim turtlesim_node
因为默认的日志级别是Info,所以你会看到turtlesim启动后发布的所有信息,如下图所示:
现在让我们在rqt_logger_level窗口中刷新一下节点并选择Warn以修改日志级别,如下图所示:
然后让我们把乌龟撞到墙上,看看rqt_console上会显示什么:
在ROS Hydro及更新版本中,
- rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0,y: 0.0,z: 0.0}}'
在ROS Groovy及早期版本中,
- rostopic pub /turtle1/command_velocity turtlesim/Velocity -r 1 -- 2.0 0.0
日志记录器级别
日志级别的优先级按以下顺序排列:
Fatal (致命)
Error (错误)
Warn (警告)
Info (信息)
Debug (调试)
Fatal是最高优先级,Debug是最低优先级。通过设置日志级别,你可以获得所有优先级级别,或只是更高级别的消息。比如,将日志级别设为Warn时,你会得到Warn、Error和Fatal这三个等级的日志消息。
现在按Ctrl+C退出turtlesim节点。接下来我们将使用roslaunch来启动多个turtlesim节点和一个模仿者节点,来让一个乌龟模仿另一个乌龟。
使用roslaunch
roslaunch可以用来启动定义在launch(启动)文件中的节点。
用法:
$ roslaunch [package] [filename.launch]
先切换到我们之前创建和构建的beginner_tutorials软件包目录下:
$ roscd beginner_tutorials
如果roscd提示类似于roscd: No such package/stack 'beginner_tutorials'的话,你需要按照创建catkin工作空间后面的步骤使环境变量生效:
$ cd ~/catkin_ws
$ source devel/setup.bash
$ roscd beginner_tutorials
然后创建一个launch目录:
$ mkdir launch
$ cd launch
注意:存放launch文件的目录不一定非要命名为launch,事实上都不用非得放在目录中,roslaunch命令会自动查找经过的包并检测可用的启动文件。然而,这种推荐的标准做法被认为是“最佳实践”。
launch文件
现在一起创建一个名为turtlemimic.launch的launch文件并复制粘贴以下内容进去:
1 <launch>
3 <group ns="turtlesim1">
4 <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
5 </group>
7 <group ns="turtlesim2">
8 <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
9 </group>
11 <node pkg="turtlesim" name="mimic" type="mimic">
12 <remap from="input" to="turtlesim1/turtle1"/>
13 <remap from="output" to="turtlesim2/turtle1"/>
14 </node>
16 </launch>
launch解析
下面我们开始拆解launch XML文件。
1 <launch>
首先用launch标签开头,以表明这是一个launch文件。
3 <group ns="turtlesim1">
4 <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
5 </group>
7 <group ns="turtlesim2">
8 <node pkg="turtlesim" name="sim" type="turtlesim_node"/>
9 </group>
此处我们创建了两个分组,并以命名空间(namespace)标签来区分,其中一个名为turtulesim1,另一个名为turtlesim2,两个分组中都有相同的名为sim的turtlesim节点。这样可以让我们同时启动两个turtlesim模拟器,而不会产生命名冲突。
11 <node pkg="turtlesim" name="mimic" type="mimic">
12 <remap from="input" to="turtlesim1/turtle1"/>
13 <remap from="output" to="turtlesim2/turtle1"/>
14 </node>
在这里我们启动模仿节点,话题的输入和输出分别重命名为turtlesim1和turtlesim2,这样就可以让turtlesim2模仿turtlesim1了。
16 </launch>
这一行使得launch文件的XML标签闭合。
使用roslaunch
现在让我们通过roslaunch命令来运行launch文件:
$ roslaunch beginner_tutorials turtlemimic.launch
现在将会有两个turtlesim被启动,然后我们在一个新终端中使用rostopic命令发送:
在ROS Hydro及更新版本中,
- $ rostopic pub /turtlesim1/turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'
在ROS Groovy及早期版本中,
- $ rostopic pub /turtlesim1/turtle1/command_velocity turtlesim/Velocity -r 1 -- 2.0 -1.8
你会看到两个turtlesims同时开始移动,虽然发布命令只发送给了turtlesim1。
我们还可以用rqt_graph来更好地理解launch文件所做的事情。运行rqt并在主窗口中选择Plugins > Introspection > Node Graph:
$ rqt
或者直接运行:
$ rqt_graph
到此,我们算是已经学会了rqt_console和roslaunch命令的使用,接下来我们开始学习使用rosed了解ROS的编辑器选择。现在你可以按Ctrl+C退出所有turtlesims节点了,因为在接下来的教程中你不会再用到它们。