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 基于三个核心通信通道构建:

  1. Goal 通道:客户端→服务器,用于发送任务目标
  2. Feedback 通道:服务器→客户端,用于发送进度反馈
  3. 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('取消请求未被接受')
posted @ 2025-09-03 00:19  aaooli  阅读(81)  评论(0)    收藏  举报