ROS2-action通信
ROS2 Action 通信通信指南
1. 概述
1.1 Action 通信机制简介
ROS2 Action 是一种基于客户端-服务器模型的异步通信机制,专为长时间运行、可中断的任务设计。它结合了话题(Topic)和服务(Service)的优点,提供了双向通信、进度反馈和任务管理能力。
1.2 核心价值与适用场景
- 适用场景:导航任务、机械臂轨迹控制、长时间计算任务、可中断流程
- 核心优势:
- 支持任务执行过程中的实时进度反馈
- 允许任务中途取消
- 提供任务结果的异步返回
- 具备任务状态跟踪能力
1.3 Action 与其他通信机制对比
| 特性 | Topic | Service | Action |
|---|---|---|---|
| 通信模式 | 单向发布/订阅 | 同步请求/响应 | 异步请求/进度/结果 |
| 实时反馈 | ❌ | ❌ | ✅ |
| 任务取消 | ❌ | ❌ | ✅ |
| 超时处理 | ❌ | 有限支持 | ✅ |
| 适用任务类型 | 数据流 | 短时任务 | 长时任务 |
2. Action 核心架构
2.1 三元组通信模型
ROS2 Action 基于三个核心通信通道构建:
- Goal 通道:客户端→服务器,用于发送任务目标
- Feedback 通道:服务器→客户端,用于发送进度反馈
- Result 通道:服务器→客户端,用于返回最终结果
2.2 Action 状态机
stateDiagram-v2
[*] --> WAITING: Action Server初始化
WAITING --> ACCEPTED: 收到Goal
ACCEPTED --> EXECUTING: 开始处理
EXECUTING --> CANCELING: 收到取消请求
CANCELING --> CANCELED: 取消完成
EXECUTING --> SUCCEEDED: 执行成功
EXECUTING --> ABORTED: 执行失败
3. Action 定义与接口
3.1 Action 接口文件结构
Action 使用 .action 文件定义,包含三个部分:
# 请求消息定义
int32 order
---
# 结果消息定义
int32[] sequence
---
# 反馈消息定义
int32[] partial_sequence
3.2 Action 接口配置
在CMakeLists.txt中需要添加:
find_package(rclcpp_action REQUIRED)
ament_target_dependencies(可执行文件名 "rclcpp_action")
在package.xml中需要添加:
<depend>rclcpp_action</depend>
4. Action Server 实现详解
4.1 服务器初始化与配置
import rclpy
from rclpy.action import ActionServer
from rclpy.node import Node
from example_interfaces.action import Fibonacci
class FibonacciActionServer(Node):
def __init__(self):
super().__init__('fibonacci_action_server')
self._action_server = ActionServer(
self,
Fibonacci,
'fibonacci',
execute_callback=self.execute_callback,
goal_callback=self.goal_callback,
cancel_callback=self.cancel_callback
)
def goal_callback(self, goal_request):
"""处理Goal请求"""
self.get_logger().info('收到Goal请求')
return rclpy.action.GoalResponse.ACCEPT
def cancel_callback(self, goal_handle):
"""处理取消请求"""
self.get_logger().info('收到取消请求')
return rclpy.action.CancelResponse.ACCEPT
4.2 Goal 请求处理
def execute_callback(self, goal_handle):
"""执行Goal的回调函数"""
self.get_logger().info(f'开始执行Goal: order={goal_handle.request.order}')
# 验证Goal有效性
if goal_handle.request.order <= 0:
goal_handle.abort()
return Fibonacci.Result()
# 执行任务并返回结果
return self.execute_fibonacci(goal_handle)
def execute_fibonacci(self, goal_handle):
"""执行Fibonacci计算"""
sequence = [0, 1]
feedback_msg = Fibonacci.Feedback()
for i in range(1, goal_handle.request.order):
# 检查取消请求
if goal_handle.is_cancel_requested:
goal_handle.canceled()
return Fibonacci.Result()
# 计算下一个数
next_value = sequence[i] + sequence[i-1]
sequence.append(next_value)
# 发布反馈
feedback_msg.partial_sequence = sequence
goal_handle.publish_feedback(feedback_msg)
# 模拟处理时间
time.sleep(1)
# 返回最终结果
goal_handle.succeed()
result = Fibonacci.Result()
result.sequence = sequence
return result
4.3 取消请求处理
def cancel_callback(self, goal_handle):
"""处理取消请求"""
self.get_logger().info('收到取消请求')
return rclpy.action.CancelResponse.ACCEPT
5. Action Client 实现详解
5.1 客户端初始化与Goal发送
import rclpy
from rclpy.action import ActionClient
from rclpy.node import Node
from example_interfaces.action import Fibonacci
import time
class FibonacciActionClient(Node):
def __init__(self):
super().__init__('fibonacci_action_client')
self._action_client = ActionClient(self, Fibonacci, 'fibonacci')
self._goal_handle = None
def send_goal(self, order):
"""发送Goal到Action Server"""
# 等待服务器可用
if not self._action_client.wait_for_server(timeout_sec=10.0):
self.get_logger().error('Action Server不可用')
return False
# 创建并发送Goal
goal_msg = Fibonacci.Goal()
goal_msg.order = order
send_goal_future = self._action_client.send_goal_async(
goal_msg,
feedback_callback=self.feedback_callback)
# 设置回调
send_goal_future.add_done_callback(self.goal_response_callback)
return True
5.2 处理服务器响应与反馈
def goal_response_callback(self, future):
"""处理Goal响应"""
self._goal_handle = future.result()
if not self._goal_handle.accepted:
return
# 获取结果回调
get_result_future = self._goal_handle.get_result_async()
get_result_future.add_done_callback(self.get_result_callback)
5.3 取消Goal实现
def cancel_goal(self):
"""取消当前Goal"""
if self._goal_handle is None:
self.get_logger().warning('没有活动的Goal可取消')
return
self.get_logger().info('发送取消请求')
cancel_future = self._goal_handle.cancel_goal_async()
cancel_future.add_done_callback(self.cancel_done_callback)
def cancel_done_callback(self, future):
"""取消操作完成回调"""
cancel_response = future.result()
if len(cancel_response.goals_canceling) > 0:
self.get_logger().info('取消请求已接受')
else:
self.get_logger().info('取消请求未被接受')

浙公网安备 33010602011771号