ROS2入门系列:理解ROS 2的动作(action)

目标: 介绍ROS 2中的动作。

背景知识

动作是ROS 2 中用来沟通的类型之一。 他是为长时间运行的任务准备的。 它包括三个部分:目标,反馈以及结果。

动作是在话题和服务的基础上构建的。 它的功能类似于服务,但是动作是可以抢占的,意思是, 你可以在节点运行时,取消动作。 他同时能够提供稳定的反馈,不像服务,每次都只返回一个回复。

动作同样使用的是客户端+服务器的模式,类似于发布器与订阅器的模式。 一个动作的客户端节点发送一个目标到一个动作的服务器节点, 服务器节点会确认收到这个目标并且返回一个反馈流和一个结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IcKjdApJ-1625492770548)(https://docs.ros.org/en/foxy/_images/Action-SingleActionClient.gif)]

前提条件

这个教程建立在一些概念上,比如说,节点话题以及服务。这个教程会使用到turtlesim package,并且不要忘记在启动的每个新的终端上source ROS 2。如何你对上面的内容还没看过的,可以戳一下,过去了解一下。

任务

1. 设置

启动两个turtlesim的节点, /turtlesim/teleop_turtle

打开一个新的终端,并且运行下面的指令:

ros2 run turtlesim turtlesim_node

打开另一个终端,并且运行下面的指令:

ros2 run turtlesim turtle_teleop_key

2. 使用动作

当你启动这个节点,你会看到你的终端上会打印出下面的信息:

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.

让我们关注第二行,第二行是跟一个动作有关系的,(第一行是跟“cmd_vel”这个话题相关的,我们在之前的教程里面提到过)。

Let’s focus on the second line, which corresponds to an action. (The first instruction corresponds to the “cmd_vel” topic, discussed previously in the topics tutorial.)

我们可以看到: G|B|V|C|D|E|R|T 这几个字母围绕着F ,在键盘上形成了一个“盒子”。每一个按钮相对按键F的位置跟小海龟在turtlesim中运动的方向有关系。比如,按下E小海龟会沿着左上角的方向转圈。

注意看运行/turtlesim节点的终端,每当你按下上面的按键之一时,你会向/turtlesim节点的动作服务器发送一个目标。这个目标时将小海龟旋转到朝向一个特定的方向。当小海龟完成了旋转之后,一条显示这个目标的执行结果的消息会打印一次。

[INFO] [turtlesim]: Rotation goal completed successfully

F按钮会在一个目标执行期间取消它的执行,可以用来演示动作的抢占功能。

试试在按下C按钮之后,在小海龟完成它的旋转之前,按下F按钮。在运行/turtlesim节点的终端上会打印出下面的消息:

[INFO] [turtlesim]: Rotation goal canceled

不仅仅是客户端,也就是你输入指令的节点,可以抢占目标,服务器端,也就是/turtlesim节点,也可以进行抢占。当服务器段抢占一个动作,它会终止一个目标。

尝试按下D键,然后在第一个旋转完成之前按下G键。这时,你可以在运行/turtlesim节点的终端上看到下面的消息:

[WARN] [turtlesim]: Rotation goal received before a previous goal finished. Aborting previous goal

服务器端放弃了第一个目标,因为它被中断了。

3. ros2 node info

为了看到 /turtlesim 节点的动作,打开一个新的终端并且运行下面的命令:

ros2 node info /turtlesim

它将会返回一个列表,里面包括 /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
  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
    /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
  Action Servers:
    /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
  Action Clients:

注意到 /turtlesim/turtle1/rotate_absolute 这个动作是在动作服务器下面的。这就意味着, /turtlesim 会响应并持续回复 /turtle1/rotate_absolute 这个动作。

而在/teleop_turtle这个节点,在Action Clients的下面有一个 /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
  Services:
    /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
  Action Servers:

  Action Clients:
    /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute

4. ros2 action list

为了找到ROS图中所有的action,可以运行下面的命令:

ros2 action list

会看到下面的输出:

/turtle1/rotate_absolute

这个也是当前的ROS图中的唯一一个动作。就像你在前面看到的一样,它控制这小海龟的旋转。通过 ros2 node info <node_name> 这个命令,你已经知道了这里有关于这个动作的一个动作客户端以及一个动作服务器端。

This is the only action in the ROS graph right now. It controls the turtle’s rotation, as you saw earlier. You also already know that there is one action client (part of /teleop_turtle) and one action server (part of /turtlesim) for this action from using the ros2 node info <node_name> command.

4.1 ros2 action list -t

动作都有类型,类似于话题和服务。为了找到 /turtle1/rotate_absolute的类型,可以运行下面的命令:

ros2 action list -t

它会返回下面的内容:

/turtle1/rotate_absolute [turtlesim/action/RotateAbsolute]

动作名称右边的中括号里面的就是动作的类型。当你需要从命令行或者代码中执行动作的的时候,你就需要知道这个类型。

5. ros2 action info

你可以通过下面的命令进一步了解/turtle1/rotate_absolute这个动作:

ros2 action info /turtle1/rotate_absolute

它会返回:

Action: /turtle1/rotate_absolute
Action clients: 1
    /teleop_turtle
Action servers: 1
    /turtlesim

这也可以了解到之前我们通过 ros2 node info 了解到的信息: /teleop_turtle 这个节点有一个动作客户端, /turtlesim 这个节点有一个动作的服务器。

6. ros2 interface show

在你准备发送或者执行一个动作的目标之前,还有一个信息你需要知道,那就是动作类型的数据结构。

回想起,前面已经通过命令: ros2 action list -t确认了 /turtle1/rotate_absolute的类型。在你的终端输入下面的命令:

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

这个信息的第一个部分,也就是在---上面的部分,是请求目标的数据类型,包括了类型和名字。接下来的部分是返回的结果的数据结构。最后一个部分是持续的反馈的数据结构。

7. ros2 action send goal

现在,让我们使用下面的语法通过命令行发送一个动作的目标:

ros2 action send_goal <action_name> <action_type> <values>

<values> 需要使用YAML格式。

注意看turtlesim的窗口,然后输入下面的命令:

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

所有的目标都有一个独特的ID,显示在返回的消息中。你还可以看到结果中有一个叫delta的部分,显示的是起始位置。

为了看到这个目标的持续反馈,在你最后运行的一个命令加上--feedback的参数。首先,确保你已经改变了theta的值。在运行了之前的一条命令之后,小海龟已经处于1.57这个弧度的方向上了,所以在你给它传递一个新的theta值之前,它是不会运动的。

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

在目标完成之前,你将会持续收到反馈:还有多少弧度需要转。

总结

动作很像服务,但是他允许你执行长时间运行的任务,提供规律的反馈,以及他们是可以被取消的。

一个机器人系统可以使用动作来进行导航。动作的目标可以是告诉机器人到某一个位置,当机器人导航到。这个位置, 它可以一路上发送更新,也就是反馈。 最后当他到达目标点的时候会返回一个结果,这就是他的目的地。

下一步

现在你已经了解了核心的概念了。剩下的几个教程会给你介绍一些工具以及技术使得ROS 2的使用更容易。

你可以在接下来的教程里面,学习到更多关于ROS图的连接相关的内容。可以关注我或者订阅我的专栏:ROS 2专栏

上一篇:**SpringBoot分布式微服务b2b2c电子商务*


下一篇:Windows中将nginx添加到服务(转)