之前介绍到的话题和服务是ROS中最重要的两种底层通信机制,但也并不是说能解决所有应用层的问题,举一个例子,如果要让机械臂抓取一个物体,我们不仅要发出指令,还需要获取机械臂的实时反馈,如果直接用话题和服务也可以实现,不过一下得上好几个,有点麻烦。 所以针对类似的场景,ROS推出了一个应用级的通信机制——动作(action),主要结局需要运行一段时间的机器人任务。action也并不是一个全新的机制,而是由底层的三个话题和服务组成:一个任务目标(Goal,服务),一个执行结果(Result,服务),周期数据反馈(Feedback,话题)。 action是可抢占式的,由于需要执行一段时间,比如执行过程中你不想跑了,那可以随时发送取消指令,动作终止,如果执行过程中发送一个新的action目标,则会直接中断上一个目标开始执行最新的任务目标。 总体上来讲,action是一个客户端/服务器的通信模型,客户端发送一个任务目标,服务器端根据收到的目标执行并周期反馈状态,执行完成后反馈一个执行结果。 依然是以小海龟仿真器为例来进一步理解action的概念。
1.启动小海龟仿真器
ros2 run turtlesim turtlesim_node
ros2 run turtlesim turtle_teleop_key
2.使用action
在启动键盘控制节点的终端中,可以看到如下日志提示: 之前我们都是使用键盘的上下左右按键发布话题指令来控制小海龟移动的,以上第二行信息提示的指令,则是通过action来控制海龟转动到指定方向的。 按键 G|B|V|C|D|E|R|T 都是围绕“F”的,以“F”为中心,对应方向的按键就表示控制小海龟的转动到的方向,比如按下“E”,小海龟就会转动到朝向左上方。 仔细观察小海龟仿真器,每当按下以上一个按键,相当于从客户端发送了一个action的任务目标,海龟仿真器后台运行的服务器端接收到之后就会开始执行,执行完成后反馈给客户端类似下边的结果: “F”按键就是用来发送action终止指令的。假设你先按下了“C”,小海龟开始执行action,此时按下“F”,两个终端中都会看到: 再来试试先按下“D”,在完成action前按下“G”,这时终端中会提示: 没错,action是抢占式的,后一个action的执行直接中断了前一个action的执行。
3.查看节点信息
我们来看下海龟仿真器节点有哪些action:
ros2 node info /turtlesim
从反馈的信息列表中,我们可以看到所有仿真器中的订阅者、发布者、服务、动作服务器和客户端。 Action Servers 中可以看到有一个动作服务器 /turtle1/rotate_absolute。 再来看看键盘控制节点的信息:
ros2 node info /teleop_turtle
在Action Clients中有同名的动作客户端/turtle1/rotate_absolute。 可见,键盘控制节点发送action目标,海龟仿真器执行action并反馈,action名为/turtle1/rotate_absolute。
4.查看action列表
action也可以类似话题服务一样查看:
ros2 action list
在海龟仿真器系统中,可以看到: 如果想要看到更详细的action数据类型,需要加入-t参数:
ros2 action list -t
看到的信息就是这样啦: 这里的 turtlesim/action/RotateAbsolute 就是action的数据类型,当我们通过终端发送action指令时,这个数据类型就可以知道我们如何发送具体的数据了。
5.查看action的信息
从list列表中看到的action可以用如下命令查看详情:
ros2 action info /turtle1/rotate_absolute
看到的结果如下: 这里可以看到提供该action的服务器和客户端的数量。
6.查看action数据类型
如果我们想发送一个action的目标goal,就需要知道action的具体数据类型和数据结构,刚才我们已经看到/turtle1/rotate_absolute的数据类型是turtlesim/action/RotateAbsolute ,那这个数据类型的具体数据结构是什么样的呢?可以这样看到:
ros2 interface show turtlesim/action/RotateAbsolute.action
有点像service的数据结构,只不过有两个“—”将数据分成了三段,第一段描述客户端发送的请求目标,第二段描述的是action执行完成后的反馈结果,第三段描述的是action执行过程中的周期反馈。
7.命令行发送action目标
终于可以发布action目标了,了解下命令行下发送goal的格式:
ros2 action send_goal <action_name> <action_type> <values>
<values>同样是YAML格式描述的数据。发送一个试试:
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}"
小海龟开始转动啦,终端中会显示: 从以上信息我们可以看到,每一个action目标都有一个唯一的ID。 如果先要看到action中的周期反馈,以上命令还需要加一个–feedback参数:
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: -1.57}" --feedback
这时的终端信息是这样的: 在action执行完成前,终端中会不断周期刷新类似反馈信息。 好啦,这就是ROS2中的action概念,用于长时间运行某一任务,提供过程中的周期反馈,而且是可以取消或者抢占的。想象一下机械臂抓取、移动机器人导航,是不是都可以用到类似的通信机制呢?