ROS | 动作服务器与客户端的内部交互(进阶)


原文链接: http://wiki.ros.org/actionlib/DetailedDescription

1. 动作服务器

goal由action客户端发出,一旦action服务器接收到goal,就会创建一个状态机来跟踪goal的状态,如下图。
在这里插入图片描述

1.1 服务器状态

  • Pending - 该目标尚未由动作服务器处理;
  • Active - 该目标当前正在由操作服务器处理;
  • Recalling - 目标尚未处理,并且已从动作客户端收到取消请求,但是动作服务器尚未确认目标已取消;
  • Preempting - 正在处理目标,并且已从操作客户端收到取消请求,但是操作服务器尚未确认目标已取消;
  • Rejected - 该目标已被动作服务器拒绝,未经处理,也没有动作客户端请求取消;
  • Succeeded - 动作服务器成功完成目标;
  • Aborted - 该目标已由动作服务器中止,而没有来自动作客户端的外部请求取消;
  • Recalled - 在动作服务器开始处理目标之前,该目标已被另一个目标或取消请求而取消;
  • Preempted - 目标的处理被另一个目标,或已发送到动作服务器的取消请求取消;

1.2 状态转换命令

  • setAccepted - 检查目标后,决定开始处理它;
  • setRejected - 检查目标之后,决定不对其进行处理,因为它是无效的请求(超出范围,资源不可用,无效等);
  • setSucceeded – 通知目标已成功处理;
  • setAborted - 通知该目标在处理过程中遇到错误,必须中止;
  • setCanceled - 通知由于取消请求,而不再处理目标;
  • CancelRequest - 客户端通知动作服务器希望服务器停止处理目标;

2. 动作客户端

在actionlib中,我们将服务器状态机视为主状态机,然后将客户端状态机视为试图跟踪服务器状态的辅助状态机,如下图。
在这里插入图片描述

2.1 服务器触发转换

  • Reported [State]:由于客户端尝试跟踪服务器的状态,因此大多数状态的转换都是由服务器向动作客户端报告其状态来触发的;
  • Receive Result Message:在这种情况下,服务器将result发送给客户端。接收到result预示着跟踪目标的结束;

2.2 客户端触发转换

  • Cancel Goal:请求服务器停止处理此目标;

2.3 “跳过”状态

  • 给定我们基于ROS的传输层,客户端可能无法从服务器接收所有状态更新。因此,我们必须允许客户端状态机“跳过”服务器触发的状态。
    示例:如果客户端处于[WAITING FOR GOAL ACK]中,并且从服务器接收到[PREEMPTED]状态更新,则客户端状态可以跳过[ACTIVE]并直接转换为[WAITING FOR RESULT]。
  • 由于多个动作客户端可以连接到单个动作服务器,因此第二个客户端可以取消第一个客户端发送的目标。因此,如果从服务器接收到[RECALLING]状态,则客户端从[PENDING]转换为[RECALLING]是有效的。

3. 动作接口及传输层

Action客户端和服务器使用预定义的动作协议(action protocol)相互进行通信。 此动作协议依靠指定的ROS命名空间中的ROS话题来传输消息。
在这里插入图片描述

ROS消息:

  • goal – 用于发送新的目标(goal)给服务器。
  • cancel – 用于发送取消请求给服务器。
  • status – 用于将系统中每个目标(goal)的当前状态通知给客户端。
  • feedback - 用于定期向客户端发送目标(goal)的辅助信息。
  • result - 用于在目标(goal)完成后向客户发送一次辅助信息。

3.1 数据关联与Goal ID

Goal ID是action message中一个字符串字段,这为动作服务器和客户端提供了一种可靠的方式,可以将通过ROS传输的消息与正在处理的特定goal相关联。 目标ID通常由节点名称,计数器和时间戳组成。
注意:goal ID的格式仍然不稳定,因此用户切勿解析goal ID或依赖其格式。

3.2 消息

3.2.1 goal topic: Sending Goals

Goal topic使用自动生成的ActionGoal消息(例如:actionlib/TestActionGoal),用于将新目标发送到动作服务器。ActionGoal消息将目标消息打包,并将其与目标ID捆绑在一起。
发送目标时,动作客户端通常会生成唯一的goal ID和时间戳,但是客户端也可能会将它们留空,此时动作服务器将会填充它们。

  • Empty stamp:一旦动作服务器接收到,时间戳将设置为now()。
  • Empty id:一旦动作服务器接收到,ID自动随机创建。不过这个ID由于动作客户端无法知道其对应的goal,所以意义不大。

3.2.2 cancel topic: Cancelling Goals

Cancel topic使用actionlib_msgs/GoalID消息,并允许动作客户端将取消请求发送给动作服务器。每个取消请求消息都带有一个时间戳和goal ID,并且如何填充这些消息字段将会影响到要取消的目标,下图是取消请求的处理策略。
在这里插入图片描述

3.2.3 status topic: Server goal state updates

Status topic使用actionlib_msgs / GoalStatusArray,并提供给动作客户端有关服务器当前正在追踪的每个目标的状态信息。这是由服务器以某个固定速率(通常为10Hz)发送的,并且还可以在任何服务器目标状态转换时异步发送。
动作服务器会追踪目标,直到达到终端状态为止。 但是为了提高通信的健壮性,服务器在达到终端状态后,会再次发布此目标的状态几秒钟。

3.2.4 feedback topic: Asynchronous goal information

Feedback topic使用自动生成的ActionFeedback消息(例如:todo),并为服务器提供了一种在处理目标期间向动作客户端定期发布更新的方法。由于ActionFeedback具有goal ID,因此动作客户端可以决定它是否使用还是丢弃所收到的反馈消息,因此发送反馈完全是可选的。

3.2.5 result topic: Goal information upon completion

Result topic使用自动生成的ActionResult消息(例如:actionlib/TestActionResult),并为服务器实现者提供了一种在目标完成后向操作客户端发送信息的方法。由于ActionResult具有goal ID,因此动作客户端可以决定它是否使用还是丢弃result消息。尽管reslt可能是空消息,但它是action接口的必需部分,并且必须始终在目标完成后发送,因此必须在转换到终端状态(Rejected, Recalled, Preempted, Aborted, Succeeded)时发送结果。

4. 机制

4.1 Simple Action Client

通常,高层次的应用工程师和管理人员仅仅关心的是,目标是否正在处理或目标是否完成,他们很少关心所有中间状态。Simple action client将原始的客户端状态机分为三个状态:Pending,Active和Done。
在这里插入图片描述

4.1.1 客户端状态歧义

仅客户端状态不足以确定Simple client状态,但是,这可以通过查看客户端状态转换轻松解决。如果客户端状态转换未在任何Simple client状态之间交叉,则不会更新Simple client状态。
示例:如果客户端从RECALLING转换为WAITING FOR RESULT,则简单客户端状态仍将保持PENDING状态。

4.1.2 多目标策略

为简单起见,Simple Action Client一次仅跟踪一个目标。当用户通过Simple client发送目标时,它会禁用与先前目标相关的所有回调函数,并且还会停止跟踪其状态,但是它不会取消先前的目标。

4.1.3 线程模型(C++)

在构造Simple Action Client时,用户可决定是否扩展额外的线程。

  • 无多余的线程(推荐)
    动作客户端中的所有订阅者都向全局回调队列注册。从ros::spin()内部调用用户的action回调,因此阻止用户的action回调将阻止为全局回调队列提供服务。
  • 扩展线程
    在动作客户端中的所有订阅者都注册有一个回调队列,该队列与全局回调队列分开,并且由扩展的线程进行服务。
    从所扩展的线程中调用用户的action回调,尽管阻止action回调不会阻止其他ROS消息得到服务,但这仍然不是一个好主意,因为该服务的status,feedback和result消息无法得到服务。
    扩展额外线程的好处是,用户可以避免在其应用程序中调用ros::spin()。

4.2 Simple Action Server

很多动作服务器都遵循类似的模式,一次只能激活一个目标,而每个新目标都将优先于前一个目标。Simple Action Server是基于动作服务器的包装,旨在为执行目标而实施此简化策略。
在这里插入图片描述

在接收到从动作客户端发出的新目标后,Simple Action Server将该目标挂起。如果一个目标已经占用了挂起位置,则Simple Action Server将这个已占用的目标设置为取消,并将其替换为通过网络传入的目标。
在这里插入图片描述

一旦Simple Action Server接收到一个新目标并将其挂起,就会向Simple Action Server的用户通知有一个新目标可用。如以下目标通知一节所述,此通知以两种方式中的其中一种方式发生。在接收到通知后,用户可以接收使被挂起的目标移动到当前目标的目标,并允许用户修改与新接收的目标相关联的状态机。

4.2.1 目标通知

用户可以通过两种方式去接收Simple Action Server已接收到新目标的通知。

  • 回调通知(Callback Notification):用户在构造中向Simple Action Server注册了一个回调,当新目标被Simple Action Server挂起时,将调用该回调函数。用户可以在回调中接收新目标,或者在准备就绪时通知另一个线程接收目标。
  • 轮询通知(Polling Notification):用户明确询问Simple Action Server是否有新的目标可用。Simple Action Server根据从上一次进行新目标查询以来是否有新的目标被挂起,从而对此查询进行回应。

4.2.2 线程模型(C++)

在构造Simple Action Server时,用户决定是否增加一个额外的线程以允许在目标回调函数中执行长时间运行的动作。

  • 无多余的线程(推荐)
    在为接收新目标的回调中进行的任何操作都不应长期运行,用户可以通知另一个线程进行工作,但不应阻塞。用户也可以使用轮询来检查新目标的有效性,并完全可以避免回调。
  • 扩展线程
    创建一个独立的线程以允许用户当新目标有效时,能够在接收到的回调函数中执行长时间的运行或被阻止的动作。在此回调中,用户还可以轮询Simple Action Server以检查是否有新目标。
    Simple Action Server为用户扩展线程的好处是,用户不必处理用于管理另一个线程的开销。但是对于用户而言,重要的是要意识到此线程的存在,以便它们遵循诸如锁定之类的标准线程安全规定。

猜你喜欢

转载自blog.csdn.net/baoli8425/article/details/117168902