ROS2入门教程—理解动作(Action)
之前介绍到的话题和服务是ROS中最重要的两种底层通信机制,但也并不是说能解决所有应用层的问题,举一个例子,如果要让机械臂抓取一个物体,我们不仅要发出指令,还需要获取机械臂的实时反馈,如果直接用话题和服务也可以实现,不过一下得上好几个,有点麻烦。所以针对类似的场景,ROS推出了一个应用级的通信机制——动作(
action
),主要应用于需要运行一段时间的机器人任务。action也并不是一个全新的机制,而是由底层的三个话题和服务组成:一个任务目标(
Goal
,服务),一个执行结果(
Result
,服务),周期数据反馈(
Feedback
,话题)。action是可抢占式的,由于需要执行一段时间,比如执行过程中你不想跑了,那可以随时发送取消指令,动作终止,如果执行过程中发送一个新的action目标,则会直接中断上一个目标开始执行最新的任务目标。总体上来讲,action是一个客户端/服务器的通信模型,客户端发送一个任务目标,服务器端根据收到的目标执行并周期反馈状态,执行完成后反馈一个执行结果。
1 启动小海龟仿真器
打开新终端并运行:
ros2 run turtlesim turtlesim_node
打开另一个终端并运行:
ros2 run turtlesim turtle_teleop_key
2 使用action
在启动键盘控制节点的终端中,可以看到如下日志提示:
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.
第一条信息提示的指令是使用键盘的上下左右按键发布话题指令来控制小海龟移动的。第二行信息提示的指令,则是通过action
来控制海龟转动到指定方向的。按键G|B|V|C|D|E|R|T
都是围绕“F”
的,以“F”
为中心,对应方向的按键就表示控制小海龟的转动到的方向,比如按下“E”
,小海龟就会转动到朝向左上方。仔细观察小海龟仿真器,每当按下以上一个按键,相当于从客户端发送了一个action
的任务目标,海龟仿真器后台运行的服务器端接收到之后就会开始执行,执行完成后反馈给客户端类似下边的结果:
[INFO] [turtlesim]: Rotation goal completed successfully
“F”
按键就是用来发送action
终止指令的。假设你先按下了“C”
,小海龟开始执行action,在没有完成该action之前,按下“F”
,此时在/turtlesim
节点运行的终端可以看到如下输出信息:
[INFO] [turtlesim]: Rotation goal canceled
再来试试先按下“D”
,在完成action前按下“G”
,这时终端中会提示:
[WARN] [turtlesim]: Rotation goal received before a previous goal finished. Aborting previous goal
可以看出,action是抢占式的,后一个action的执行直接中断了前一个action的执行。
3 ros2 node info
为了查看/turtlesim
节点中的动作,开启新的终端并执行以下命令:
ros2 node info /turtlesim
从反馈的信息列表中,我们可以看到所有仿真器中的订阅者、发布者、服务、动作服务器和动作客户端。
/turtlesim
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
Service Servers:
/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
/turtlesim/describe_parameters: rcl_interfaces/srv/DescribeParameters
/turtlesim/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
/turtlesim/get_parameters: rcl_interfaces/srv/GetParameters
/turtlesim/list_parameters: rcl_interfaces/srv/ListParameters
/turtlesim/set_parameters: rcl_interfaces/srv/SetParameters
/turtlesim/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
Service Clients:
Action Servers:
/turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
Action Clients:
可以看到,Action Servers
中有一个动作服务器/turtle1/rotate_absolute
,这意味着/turtlesim
节点对动作/turtle1/rotate_absolute
作出响应并提供反馈。
再来看看键盘控制节点的信息:
ros2 node info /teleop_turtle
在终端中输入如下信息列表:
/teleop_turtle
Subscribers:
/parameter_events: rcl_interfaces/msg/ParameterEvent
Publishers:
/parameter_events: rcl_interfaces/msg/ParameterEvent
/rosout: rcl_interfaces/msg/Log
/turtle1/cmd_vel: geometry_msgs/msg/Twist
Service Servers:
/teleop_turtle/describe_parameters: rcl_interfaces/srv/DescribeParameters
/teleop_turtle/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
/teleop_turtle/get_parameters: rcl_interfaces/srv/GetParameters
/teleop_turtle/list_parameters: rcl_interfaces/srv/ListParameters
/teleop_turtle/set_parameters: rcl_interfaces/srv/SetParameters
/teleop_turtle/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
Service Clients:
Action Servers:
Action Clients:
/turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
在Action Clients
中有同名的动作客户端/turtle1/rotate_absolute
。可见,键盘控制节点发送action目标,海龟仿真器执行action并反馈,action名为/turtle1/rotate_absolute
。
4 ros2 action list
action也可以类似话题服务一样查看:
ros2 action list
在海龟仿真器系统中,可以看到:
/turtle1/rotate_absolute
如果想要看到更详细的action数据类型,需要加入-t参数:
ros2 action list -t
此时,在终端中将会输出如下信息:
/turtle1/rotate_absolute [turtlesim/action/RotateAbsolute]
这里的turtlesim/action/RotateAbsolute
就是action的数据类型,当我们通过终端发送action指令时,知道这个数据类型就可以知道如何发送具体的数据了。
5 ros2 action info
从list列表中看到的action可以用如下命令查看详情:
ros2 action info /turtle1/rotate_absolute
看到的结果如下:
Action: /turtle1/rotate_absolute
Action clients: 1
/teleop_turtle
Action servers: 1
/turtlesim
这里可以看到提供该action的服务器和客户端的数量。
6 ros2 interface show
如果我们想发送一个action的目标goal,就需要知道action的具体数据类型和数据结构,刚才我们已经看到/turtle1/rotate_absolute
的数据类型是turtlesim/action/RotateAbsolute
,那这个数据类型的具体数据结构是什么样的呢?可以使用如下命令查看:
ros2 interface show turtlesim/action/RotateAbsolute
看到如下结果:
# 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
有点像service的数据结构,只不过有两个“---”
将数据分成了三段,第一段描述客户端发送的请求目标,第二段描述的是action执行完成后的反馈结果,第三段描述的是action执行过程中的周期反馈。
7 ros2 action send_goal
可以使用如下命令发布action目标:
ros2 action send_goal <action_name> <action_type> <values>
<values>
同样是YAML格式描述的数据,如下所示:
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}"
小海龟开始转动啦,终端中会显示:
Waiting for an action server to become available...
Sending goal:
theta: 1.57
Goal accepted with ID: f8db8f44410849eaa93d3feb747dd444
Result:
delta: -1.568000316619873
Goal finished with status: SUCCEEDED
从以上信息我们可以看到,每一个action目标都有一个唯一的ID。如果先要看到action中的周期反馈,以上命令还需要加一个--feedback
参数:
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: -1.57}" --feedback
这时的终端信息是这样的:
Sending goal:
theta: -1.57
Goal accepted with ID: e6092c831f994afda92f0086f220da27
Feedback:
remaining: -3.1268222332000732
Feedback:
remaining: -3.1108222007751465
…
Result:
delta: 3.1200008392333984
Goal finished with status: SUCCEEDED
在action执行完成前,终端中会不断周期刷新类似反馈信息。好啦,这就是ROS2中的action概念,用于长时间运行某一任务,提供过程中的周期反馈,而且是可以取消或者抢占的。