第116篇 ROS2 Action通信——长时任务与三阶段反馈机制
面试被问Action和Service有什么区别为什么不直接用Service我说Action可以反馈进度。面试官说具体说说什么时候必须用Action取消一个正在执行的Action会发生什么这个问题答不好说明你没真正用过Action。今天把Action通信从头到尾讲清楚。为什么需要Action先说一个场景。你让机器人从A点导航到B点这个过程可能要几分钟。如果用Service客户端发一个去B点的请求然后就得一直等到导航完成才能拿到结果。这几分钟里客户端什么都干不了。更糟糕的是如果中途你想取消这个任务Service做不到。请求已经发出去了只能等结果或者干脆关掉连接但服务端可能还在傻傻地执行。Action就是为了解决这个问题设计的。它专门用于长时间运行的任务提供三个关键能力异步执行、实时反馈、可取消。Action的三阶段通信Action的通信模型比Topic和Service都复杂。它有三个阶段目标Goal——客户端向服务端发送一个目标比如导航到坐标(3, 5)。服务端收到后决定接受还是拒绝。反馈Feedback——任务执行过程中服务端持续向客户端发送进度更新比如已走完60%的路径。客户端可以根据反馈更新UI或者做其他决策。结果Result——任务完成后服务端发送最终结果包括是否成功和详细的执行报告。用打电话来类比你打电话给快递公司发送Goal快递说好的我们接单了接受Goal。然后你每隔一会儿查一下物流状态Feedback最后快递送达你签收Result。Action的类型定义Action类型用.action文件定义分三个部分# NavigateToPose.action geometry_msgs/Pose target_pose --- float32 distance_remaining --- bool is_success float32 total_distance第一部分是Goal目标字段第二部分是Feedback反馈字段第三部分是Result结果字段。ROS2内置了一些常用的Action类型比如nav_msgs/NavigateToPose导航到目标点、control_msgs/FollowJointTrajectory机械臂轨迹跟踪。你也可以根据需求自定义。创建一个Action服务端from nav2_msgs.action import NavigateToPose from rclpy.action import ActionServer class NavNode(Node): def __init__(self): super().__init__(navigator) self._action_server ActionServer( self, NavigateToPose, navigate_to_pose, self.execute_callback) async def execute_callback(self, goal_handle): target goal_handle.request.pose self.get_logger().info(f开始导航到目标点) # 模拟导航过程 for i in range(100): if goal_handle.is_cancel_requested: goal_handle.canceled() return NavigateToPose.Result(is_successFalse) # 执行导航计算... # 发送反馈 feedback NavigateToPose.Feedback() feedback.distance_remaining (100 - i) / 100.0 goal_handle.publish_feedback(feedback) goal_handle.succeed() result NavigateToPose.Result() result.is_success True return result关键点execute_callback是异步的执行过程中通过publish_feedback持续发送进度。同时检查is_cancel_requested来响应取消请求。创建一个Action客户端from rclpy.action import ActionClient class ClientNode(Node): def __init__(self): super().__init__(client) self._action_client ActionClient( self, NavigateToPose, navigate_to_pose) def send_goal(self, x, y): goal NavigateToPose.Goal() goal.pose.position.x x goal.pose.position.y y future self._action_client.send_goal_async( goal, feedback_callbackself.feedback_cb) future.add_done_callback(self.goal_response_callback) def feedback_cb, feedback): dist feedback.feedback.distance_remaining self.get_logger().info(f剩余距离: {dist:.2f}m)客户端的流程是发送目标 → 收到接受/拒绝 → 持续接收反馈 → 等待最终结果。goal_response_callback里处理目标是否被接受接受后调用get_result_async()等待最终结果通过回调函数处理。整个过程是异步的不会阻塞主线程。取消Action取消是Action相比Service的一大优势。客户端可以随时发送取消请求self._goal_handle.cancel_goal_async()服务端收到取消请求后is_cancel_requested会变成True。你在execute_callback里检测到这个标志后停止执行并返回canceled()。在机器人项目中取消功能特别重要。操作员发现机器人走错路了按一个按钮就能停掉当前的导航任务。如果用Service你做不到这一点。Action在机器人项目中的应用导航系统是最典型的Action应用。nav2的导航栈全部基于Action实现NavigateToPose导航到目标点、NavigateThroughPoses经过多个路径点、ComputePathToPose计算路径。机械臂控制也是。MoveIt2的轨迹执行用FollowJointTrajectory Action执行过程中持续反馈关节位置和剩余时间。还有抓取任务。发送抓取物体A的目标执行过程中反馈夹爪的开合程度和力反馈完成后返回抓取是否成功。面试中怎么聊面试官问Action你可以说Action是ROS2中用于长时间任务的通信机制支持目标发送、实时反馈和取消操作。和Service的区别在于Service是同步的请求-响应适合快速操作Action是异步的适合导航、抓取这类可能持续几分钟的任务。Action的取消机制在机器人安全控制中非常重要。Action的取消与反馈机制Action的取消功能在实际项目中很重要。比如机器人正在执行一个长时间的导航任务用户突然想中止这时候就可以通过Action的cancel机制来实现。反馈机制则让客户端能实时了解执行进度比如在导航过程中持续获取当前位置和剩余距离。面试时能描述一个完整的Action使用场景包括目标发送、反馈接收和结果处理的完整流程会很有说服力。给你的建议用nav2的NavigateToPose Action跑一次导航任务用ros2 action send_goal命令行工具发送目标观察反馈信息。然后写一个简单的Action客户端实现发送目标、接收反馈、中途取消的完整流程。亲手做过一遍面试的时候说起细节来才有底气。上一篇第115篇 ROS2 Service通信——同步请求响应的适用场景下一篇预告第117篇 ROS2参数服务——在线调参的正确姿势