ROS2 概念理解
节点
节点(Node): 节点是具有一定功能的模块(如控制机器人手臂电机)。每个节点可通过话题(topic), 服务(service), 动作(action)以及参数(parameter)等来发送(publish)与接收(subscribe)数据,从而实现与其他节点的通信,最终实现机器人的某项能力。
下面我们来看下模拟,打开小乌龟模拟器:
# ros2 run <package_name> <executable_name>
ros2 run turtlesim turtlesim_node
这个命名以后会经常使用: turtlesim
是工作包(package)的名字, turtlesim_node
是可以执行的文件名。
小乌龟窗口会弹出来,类似:
使用如下命令即可查看当前的ros 图中有哪些节点:
ros2 node list
返回的结果应该:
/turtlesim
即只有一个节点, 节点名/turtlesim
。
如果在模拟时,我们想控制小乌龟的移动,可以使用如命令(打开一个新终端)
ros2 run turtlesim turtle_teleop_key
通过这个命令我们就可以使用如方向键等按键来控制小乌龟移动了。然后,我们再查看节点(ros2 node list
):
/turtlesim
/teleop_turtle
发现又多了一个节点,即为刚才我们用以控制小乌龟的节点(/teleop_turtle
).
可以使用如下命令来查看某一节点的相关信息,比如我们查看/turtlesim
节点信息:
# ros2 node info <node_name>
ros2 node info /turtlesim
会显示如下信息:
/my_turtle
Subscribers:
/parameter_events: rcl_interfaces/msg/ParameterEvent
/turtle1/cmd_vel: geometry_msgs/msg/Twist
Publishers:
/parameter_events: rcl_interfaces/msg/ParameterEvent
/rosout: rcl_interfaces/msg/Log
/turtle1/color_sensor: turtlesim/msg/Color
/turtle1/pose: turtlesim/msg/Pose
Services:
/clear: std_srvs/srv/Empty
/kill: turtlesim/srv/Kill
/reset: std_srvs/srv/Empty
/spawn: turtlesim/srv/Spawn
/turtle1/set_pen: turtlesim/srv/SetPen
/turtle1/teleport_absolute: turtlesim/srv/TeleportAbsolute
/turtle1/teleport_relative: turtlesim/srv/TeleportRelative
/my_turtle/describe_parameters: rcl_interfaces/srv/DescribeParameters
/my_turtle/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
/my_turtle/get_parameters: rcl_interfaces/srv/GetParameters
/my_turtle/list_parameters: rcl_interfaces/srv/ListParameters
/my_turtle/set_parameters: rcl_interfaces/srv/SetParameters
/my_turtle/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
Action Servers:
/turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
Action Clients:
话题 topic
topic是各节点间传递信息的媒介。使用如下命令可查年当前活动的topics:
ros2 topic list
会显示:
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
如在后面加上-t
,还可以显示各个topic对应的数据类型:
ros2 topic list -t
/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]
使用rqt_graph
可视化节点及其之间的topic:
rqt_graph
?
上图展示的是节点/teleop_turtle
通过发布数据到 topic/turtle1/cmd_vel
,同时, 节点turtlesim
订阅此topic来获取相应的数据。
通过如下命令可以实时查看某一topic中正在传输的数据,比如topic/turtle1/cmd_vel
:
# ros2 topic echo <topic_name>
ros2 topic echo /turtle1/cmd_vel
每当你按键来操控小乌龟(需让执行ros2 run turtlesim turtle_teleop_key
的终端窗口保持在前面)时, 执行ros2 topic echo /turtle1/cmd_vel
就会打印对应的topic中传输的数据:
linear:
x: 0.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 2.0
---
使用:
ros2 topic info /turtle1/cmd_vel
查看对应的topic的数据类型以及发布与订阅情况:
Type: geometry_msgs/msg/Twist
Publisher count: 1
Subscription count: 1
我们把在topic中传输的数据称为信息(message),message传输需要一定的数据类型,对某一topic发布与订阅均需要使用完全一致的message类型. 回想上面使用ros2 topic list -t
命令输出的信息,如: /turtle1/cmd_vel [geometry_msgs/msg/Twist]
, 中括号内的含义是工作包geometry_msgs
有一个msg
叫做Twist
:
# ros2 interface show <msg type>
ros2 interface show geometry_msgs/msg/Twist
显示:
This expresses velocity in free space broken into its linear and angular parts.
Vector3 linear
Vector3 angular
表明/turtlesim
节点的message是两个向量,每个向量均包含三个元素。
服务 service
service是ROS图的另一种通信方式,相比于topic的持续性信息流,service仅在客户端调用时提供数据。
使用如下命令即可查看当前活跃的服务列表:
ros2 service list
显示:
/clear
/kill
/reset
/spawn
/teleop_turtle/describe_parameters
/teleop_turtle/get_parameter_types
/teleop_turtle/get_parameters
/teleop_turtle/list_parameters
/teleop_turtle/set_parameters
/teleop_turtle/set_parameters_atomically
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/describe_parameters
/turtlesim/get_parameter_types
/turtlesim/get_parameters
/turtlesim/list_parameters
/turtlesim/set_parameters
/turtlesim/set_parameters_atomically
使用如下命令可以查看服务类型, 比如查看/spawn
的服务类型:
# ros2 service type <service_name>
ros2 service type /clear
会显示:
turtlesim/srv/Spawn
类似上面topic的列表命令,加上-t
可以查看所有服务类型:
ros2 service list -t
会显示:
/clear [std_srvs/srv/Empty]
/kill [turtlesim/srv/Kill]
/reset [std_srvs/srv/Empty]
/spawn [turtlesim/srv/Spawn]
...
/turtle1/set_pen [turtlesim/srv/SetPen]
/turtle1/teleport_absolute [turtlesim/srv/TeleportAbsolute]
/turtle1/teleport_relative [turtlesim/srv/TeleportRelative]
...
使用如下命令可以查看某一服务类型的数据结构,比如/spawn
:
# ros2 interface show <service_type_name>
ros2 interface show turtlesim/srv/Spawn
将返回:
float32 x
float32 y
float32 theta
string name # Optional. A unique name will be created and returned if this is empty
---
string name
请求结构(上)与响应结构(下)由---
分开。
参数 parameter
参数是节点的配置,其数据类型可以是整型、浮点数、布尔值、字符串和列表。在ROS2中 所参数都可通过服务来动态配置。
使用如下命令查看当前ROS图中节目的参数:
/teleop_turtle:
scale_angular
scale_linear
use_sim_time
/turtlesim:
background_b
background_g
background_r
use_sim_time
使用如下命令获取参数的数据类型与当前值,比如/turtlesim
的background_r
:
# ros2 param get /turtlesim background_r
显示:
Integer value is: 69
即background_r
的值是整型69
动作 action
另一种通信类型是action, 它适用于运行周期较长的任务,它有目标、反馈与结果三部分组成。相比于service,动作在结果返回之前会一直提供反馈,并且客户端可以根据反馈情况决定是否继续等待结果产生还是中途取消。
当我们使用ros2 run turtlesim turtle_teleop_key
命令时,注意到其显示:
Reading from keyboard
---------------------------
Use arrow keys to move the turtle.
Use G|B|V|C|D|E|R|T keys to rotate to absolute orientations. ‘F‘ to cancel a rotation.
‘Q‘ to quit.
其中Use G|B|V|C...
这句对应一个让小包龟旋转的动作。如果将F
想象成小乌龟,那么围绕F
一圈字母表示的正好是希望旋转的方向,比如C
表示旋转小乌龟让其方向朝向左下角,当我们按下C
时(确保此时活跃窗口为ros2 run turtlesim turtle_teleop_key
), 小如乌龟就会自动旋转向左下角,其间如果没有其他操作,当小乌龟旋转完成时,在ros2 run turtlesim turtlesim_node
命令窗口中会显示类似如下信息:
[INFO] [1630279564.023316728] [turtlesim]: Rotation goal completed successfully
如果在其旋转时按下F
, 小乌龟就会停止,然后上面的窗口会反馈:
[INFO] [1630279898.183500953] [turtlesim]: Rotation goal canceled
如果在其旋转时按下其它旋转方向, 比如R
,那么小乌龟会立即向右上方旋转,然后上面的窗口会发出警告:
[WARN] [1630279914.102848944] [turtlesim]: Rotation goal received before a previous goal finished. Aborting previous goal
使用如下命令可以查看活跃的所有action
ros2 action list -t
返回:
/turtle1/rotate_absolute [turtlesim/action/RotateAbsolute]
使用如下命令可以查看动作的信息:
# ros2 action info <action_name>
ros2 action info /turtle1/rotate_absolute
显示:
Action: /turtle1/rotate_absolute
Action clients: 1
/teleop_turtle
Action servers: 1
/turtlesim
即action服务器只有/turtlesim
, 客户端也只有一个/teleop_turtle
.
使用如下命令查看相应action服务器的数据结构:
ros2 interface show turtlesim/action/RotateAbsolute
显示:
Absolute
# The desired heading in radians
float32 theta
---
# The angular displacement in radians to the starting position
float32 delta
---
# The remaining rotation in radians
float32 remaining
由---
分隔的上面是目标请求结构, 中间是反馈结构,下面是结果返回结构。
rqt_console
rqt_console
可用于查看日志消息,通常相关日志会在对应的终端显示。 不过使用rqt_console
会更加方便。
在新的终端中打开:
ros2 run rqt_console rqt_console
会弹出一个对话框:
如果此时我们操控小乌龟让其不断的撞墙,在rqt_console
容口中就会产生如下消息:
ROS2 提供如下消息等级:
Fatal
Error
Warn
Info
Debug
默认是Info
,如果想要修改, 可以在启动时设置记录级别,比如:
ros2 run turtlesim turtlesim_node --ros-args --log-level WARN
launch 启动
一般来说,机器人系统不只一个节点,而是多个节点的复杂系统。如果每个节点都要分别打开,会非常麻烦,而使用launch 文件可以同时启动和配置多个节点。
先关闭上面的所有窗口,然后,创建一个文件夹并在其中创建如下文件:
mkdir launch
touch launch/turtlesim_mimic_launch.py
turtlesim_mimic_launch.py
的内容:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package=‘turtlesim‘,
namespace=‘turtlesim1‘,
executable=‘turtlesim_node‘,
name=‘sim‘
),
Node(
package=‘turtlesim‘,
namespace=‘turtlesim2‘,
executable=‘turtlesim_node‘,
name=‘sim‘
),
Node(
package=‘turtlesim‘,
executable=‘mimic‘,
name=‘mimic‘,
remappings=[
(‘/input/pose‘, ‘/turtlesim1/turtle1/pose‘),
(‘/output/cmd_vel‘, ‘/turtlesim2/turtle1/cmd_vel‘),
]
)
])
其中:
def generate_launch_description():
return LaunchDescription([...])
返回一个三节点结成的启动系统, 节点均来自包turtlesim
。
首先启动文件中,前两个节点表明是两个小乌龟,仔细查看,发现两只小乌龟的设置几乎一致,只不过namespace
不同(否则会冲突)。最后的节点代表可执行文件mimic
。mimic
的/input/pose
topic被重新映射到/turtlesim1/turtle1/pose
并且它的/output/cmd_vel
topic被重新映射到/turtlesim2/turtle1/cmd_vel
。这意味着mimic
将订阅/turtlesim1/sim
的姿势topic并重新发布它以供/turtlesim2/sim
订阅的速度命令主题。换句话说,turtlesim2
将模仿turtlesim1
的动作。
使用如下命令执行launch文件:
cd launch
ros2 launch turtlesim_mimic_launch.py
窗口会显示类似如下信息:
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [turtlesim_node-1]: process started with pid [18346]
[INFO] [turtlesim_node-2]: process started with pid [18348]
[INFO] [mimic-3]: process started with pid [18350]
可以使用如下命令发布信息,让小乌龟动起来:
ros2 topic pub -r 1 /turtlesim1/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}}"
这样两只小乌龟就开始画圈了。
查看ROS图(如果信息与下面差别较大,可以点击窗口中左上角的刷新(蓝色的旋转箭头)试一下):
rqt_graph
记录与回放数据
ROS2 bag 是一个用于记录topic数据的命令行工具,这些被记录的数据可以回放以便产生记录时一致的实验结果。
关闭上面所有窗口并重新打开:
ros2 run turtlesim turtlesim_node
ros2 run turtlesim turtle_teleop_key
然后为bag创建文件夹以便存储记录的topic数据:
mkdir bag_files
cd bag_files
比如要记录发布于/turtle1/cmd_vel
topic上面的数据:
# ros2 bag record <topic_name>
ros2 bag record /turtle1/cmd_vel
会看到类似如下信息:
[INFO] [1630367261.235190016] [rosbag2_storage]: Opened database ‘rosbag2_2021_08_31-07_47_41/rosbag2_2021_08_31-07_47_41_0.db3‘ for READ_WRITE.
[INFO] [1630367261.242226479] [rosbag2_transport]: Listening for topics...
[INFO] [1630367261.242821059] [rosbag2_transport]: Subscribed to topic ‘/turtle1/cmd_vel‘
[INFO] [1630367261.242918703] [rosbag2_transport]: All requested topics are subscribed. Stopping discovery...
使用Ctrl+C
停止记录,数据将被累积在一个包文件中,其名称格式: rosbag2_year_month_day-hour_minute_second
. 可以使用参数-o
设置文件名称,也可以记录多个topic,如:
ros2 bag record -o subset /turtle1/cmd_vel /turtle1/pose
上面这条命令是将数据保存在subset
文件中, 且本次记录的是两个topic的数据。
使用下面命令查看bag信息:
# ros2 bag info <bag_file_name>
ros2 bag info subset
显示类型似:
Files: subset_0.db3
Bag size: 121.3 KiB
Storage id: sqlite3
Duration: 24.224s
Start: Aug 31 2021 07:51:29.372 (1630367489.372)
End: Aug 31 2021 07:51:53.597 (1630367513.597)
Messages: 1673
Topic information: Topic: /turtle1/cmd_vel | Type: geometry_msgs/msg/Twist | Count: 158 | Serialization Format: cdr
Topic: /turtle1/pose | Type: turtlesim/msg/Pose | Count: 1515 | Serialization Format: cdr
接下来,我们回放记录的topic数据, 在这之前,关闭teleop
窗口,但小乌龟要保留,然后:
ros2 bag play subset
终端会显示类似如下信息:
[INFO] [1630367914.850719273] [rosbag2_storage]: Opened database ‘subset/subset_0.db3‘ for READ_ONLY.
然后,小乌龟会开始按记录时的数据移动(但不是 100% 准确;turtlesim 对系统时间的微小变化很敏感)。
总结,以上通过小乌龟模拟器熟悉ROS2相关概念及常用命令。上面涉及的命令以后一定会经常用到,汇总如下:
命令 | 解释 |
---|---|
rqt | ROS2 的GUI, 其可以查看ROS2中的非常多信息,后面会慢慢介绍 |
ros2 node list | 列出当前所有节点 |
ros2 node info <node_name> | 查看某节点的相关信息 |
rqt_graph | 可以查看相应的ROS2节点图 |
ros2 topic list | 列出当前所有主题,加上-t 还可以查看对应的信息类型 |
ros2 topic echo <topic_name> | 可查看某一topic当前正在传输的数据 |
ros2 topic info <topic_name> | 查看某节点的节点信息 |
ros2 interface show <msg_type> | 查看信息类型的具体数据结构 |
ros2 topic hz <topic_name> | 查看topic 发布频率 |
ros2 service list | 列出当前所有服务,加上-t 还可以查看对应的信息类型 |
ros2 service type <service_name> | 查看服务类型 |
ros2 service find <type_name> | 查看哪些服务使用某一服务类型 |
ros2 interface show <type_name> | 查看服务类型的具体数据结构 |
ros2 param list | 查看各节点对应的参数配置 |
ros2 param get <node_name> <parameter_name> | 获取某一节点的某一参数类型及取值 |
ros2 param set <node_name> <parameter_name> |
设置某一节点的某一参数取值 |
ros2 param dump <node_name> | 保存某一节点的参数配置 |
ros2 param load <node_name> <parameter_file> | 为某一节点加载参数配置 |
ros2 action list | 列出当前所有动作,加上-t 还可以查看对应的信息类型 |
ros2 action info <action_name> | 查看某一action的相关信息 |
ros2 interface show <action_type> | 查看action类型的具体数据结构 |
ros2 run rqt_console rqt_console | 日志查看器 |
ros2 launch <package_name> <launch_file_name> | 启动launch文件 |
ros2 bag record <topic_name> | 记录某一topic的数据,加 -o 可设置保存文件名称 |
ros2 bag info <bag_file_name> | 查看某一bag信息 |
ros2 bag play <bag_file_name> | 回放数据 |