Action通信机制(一) 概念和原理

尽管在ROS中已经提供了service机制来满足请求—响应式的使用场景, 但是假如某个请求执行时间很长,在此期间用户想查看执行的进度或者取消这个请求的话,service机制就不能满足了,但是action通信可满足用户这种需求。例如,控制机器人运动到地图中某一目标位置,这个过程可能复杂而漫长,执行过程中还可能强制中断或反馈信息,这时需要的就是 actionlib 机制

service是阻塞的,action是非阻塞的

通信机制

ROS的Action机制本质上仍然是一种Topic机制,只是通过actionlib进行了封装。ActionClientActionServer 通过ROS Action Protocol进行通信,本质上还是消息的方式,action protocol就是预定义的一组 ROS message。

在服务器和客户端之间通过goal, cancel, status, feedback, result五个主题实现Action机制。

  • goal: 代表一个任务,可以被ActionClient发送到ActionServer。比如在MoveBase中,它的类型是PoseStamped,包含了机器人运动目标位置的信息。

  • cancel: client发送取消请求到server

  • status: server通知client每个goal的当前状态

  • feedback: 向client发送周期性的goall执行过程中的辅助信息。在Move Base中,它表示机器人当前姿态。

  • result: 等goal执行结束,才向client发送一次性辅助信息

类似msg文件,在程序的action文件(文件名后缀为.action)中定义上述goal、result、feedback等消息,依次用---分隔

action通信时,如果双方约定的action名称为do_dishes,那么客户端会发布话题 /do_dishes/goal/do_dishes/cancel;服务端发布话题/do_dishes/feedback, /do_dishes/result, /do_dishes/status

client要么发送goal,要么cancel; result和feedback的取值由用户决定,status的取值是固定的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
uint8 PENDING   = 0   # The goal has yet to be processed by the action server
uint8 ACTIVE = 1 # The goal is currently being processed by the action server

uint8 PREEMPTED = 2 # The goal received a cancel request after it started executing
# and has since completed its execution (Terminal State)
uint8 SUCCEEDED = 3 # The goal was achieved successfully by the action server (Terminal State)
uint8 ABORTED = 4 # The goal was aborted during execution by the action server due
# to some failure (Terminal State)
uint8 REJECTED = 5 # The goal was rejected by the action server without being processed,
# because the goal was unattainable or invalid (Terminal State)

uint8 PREEMPTING = 6 # The goal received a cancel request after it started executing
# and has not yet completed execution
uint8 RECALLING = 7 # The goal received a cancel request before it started executing,
# but the action server has not yet confirmed that the goal is canceled
uint8 RECALLED = 8 # The goal received a cancel request before it started executing
# and was successfully cancelled (Terminal State)
uint8 LOST = 9 # An action client can determine that a goal is LOST. This should not be
# sent over the wire by an action server

server状态机

Goals请求由ActionClient发出,ActionServer接收后会创建一个有限状态机来跟踪goal的状态,而不是server的状态,每个goal都有一个状态机。

server状态机的命令(actionlib::SimpleActionServer的函数)

  • setAccepted: 收到goal后,准备处理
  • setRejected: 收到goal后,拒绝处理
  • setSucceeded: 标志goal已经成功处理
  • setAborted: 处理goal的过程中发现错误,终止处理
  • setCanceled: server取消对goal的处理,与setRejected不同之处在于发出取消请求的是client

从客户端也可以异步地触发状态变换,比如cancelGoal函数

client状态机

server状态机用于追踪goal的状态,client状态机作为补充,追踪server的状态。一般根据goal的情况分成 PENDING,ACTIVE,DONE三部分。

由于可以有多个client连接到一个Action server,有可能第二个client会取消第一个client发的goal

Goal的状态转变

两张图片表示得太复杂了。一般这样记忆:对于MoveBase的client,最开始的状态是LOST。 当前sendGoal后,状态为ACTIVE. 调用cancelGoal后,变为 PREEMPTED,而不是Aborted。客户端实际的操作goal的函数只有sendcancel

车成功到达目标后,状态为SUCCEEDED。彻底失败,为Aborted

对于多个goal的处理策略

高层的client和server只考虑goal的处理情况,所以叫SimpleActionServerSimpleActionClient

Simple Action Client一次只追踪一个goal,它发出goal之后,会disables之前的goal的所有回调函数,也不再追踪之前goal的状态,但是并不cancel之前的 goal

SimpleActionServer在ActionServer类上实现了单一目标策略,就是在某一时刻只能有一个goal是处于active状态,并且新的goal可以抢占先前的goal:

  • 每次只能有一个goal处于active状态
  • 新的goal抢占以前的goal是根据GoalID中的时间戳
  • 新的goal抢占成功后,旧的goal状态会改变


如图,goal A正在被处理,后面等待的是B,此时client又发了C,那么SimpleActionServer会把C放到队列中,B进入RECALLING状态,然后server又调用setCanceled使B进入RECALLED状态,C成了PENDING

actionlib 为每个 goal 设置了一个状态跟踪器,每个目标有一个独有的id,这是状态发布与取消goal的基础。

actionlib 是通过多个话题的形式实现控制,由于它支持多个客户端同时对服务器发指令,内部必须维护一个list来控制多个目标点的实施。

工具

actionlib包自带了一个客户端的工具,可以用来测试与server端的通信:

1
rosrun actionlib axclient.py /do_dishes    // do_dishes是action名称

参考:

actionlibDetailedDescription
actionlib库的介绍
ROS actionlib学习(三)