ros2 action相关

发布于:2024-10-16 ⋅ 阅读:(136) ⋅ 点赞:(0)

ros2 action相关

总体代码参考:
一定要先看这里的示例,后续是对这个示例的说明补充
重点关注execute中,思考action的客户端与服务端联动过程中需要的是,任务执行的一些状态信息交互,就能明补execute为什么这样写了

代码讲解

void execute(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
{
    // 日志:开始执行目标
    RCLCPP_INFO(this->get_logger(), "Executing goal");

    // 设置循环频率为 1Hz(每秒执行一次)
    rclcpp::Rate loop_rate(1);

    // 获取目标参数(目标中的 Fibonacci 序列长度)
    const auto goal = goal_handle->get_goal();

    // 创建用于发送反馈的对象
    auto feedback = std::make_shared<Fibonacci::Feedback>();

    // 获取部分序列引用,初始时只包含两个数字 0 和 1
    auto & sequence = feedback->partial_sequence;
    sequence.push_back(0);
    sequence.push_back(1);

    // 创建结果对象,用于在目标完成时返回整个序列
    auto result = std::make_shared<Fibonacci::Result>();

    // 循环从 1 开始生成 Fibonacci 数列,直到达到目标数列长度或 ROS 停止
    for (int i = 1; (i < goal->order) && rclcpp::ok(); ++i) {
        // 检查是否有取消请求
        if (goal_handle->is_canceling()) {
            // 如果取消请求存在,将当前已生成的部分序列返回,并标记为取消
            result->sequence = sequence;
            goal_handle->canceled(result);
            RCLCPP_INFO(this->get_logger(), "Goal canceled");
            return;  // 退出函数,停止执行
        }

        // 按照 Fibonacci 规则更新序列:每个数字是前两个数字的和
        sequence.push_back(sequence[i] + sequence[i - 1]);

        // 发布当前的反馈,更新部分已生成的 Fibonacci 序列
        goal_handle->publish_feedback(feedback);
        RCLCPP_INFO(this->get_logger(), "Publish feedback");

        // 按照 1Hz 的频率暂停,以保持循环节奏
        loop_rate.sleep();
    }

    // 如果目标完成并且没有被取消,且 ROS 正常运行
    if (rclcpp::ok()) {
        // 将生成的完整序列设置为结果
        result->sequence = sequence;

        // 标记目标完成,返回结果
        goal_handle->succeed(result);
        RCLCPP_INFO(this->get_logger(), "Goal succeeded");
    }
}

代码讲解:

  1. 初始化:goal_handle->get_goal() 获取传入的目标,它包含 Fibonacci 数列的目标长度(即需要生成多少个数字)。
    初始化反馈的部分序列 sequence,最初包含 Fibonacci 数列的前两个元素 0 和 1。
  2. 反馈循环:通过 for 循环,逐步生成 Fibonacci 数列的后续数字。每次计算后,调用 publish_feedback(feedback) 发布当前生成的部分序列作为反馈。
    循环每次睡眠 1 秒(通过 rclcpp::Rate(1) 控制),以模拟逐步计算的过程。
  3. 取消处理:在每次循环开始时,检查是否有取消请求 (goal_handle->is_canceling())。
    如果接收到取消请求,服务器将返回已经计算的部分数列,调用 goal_handle->canceled(result) 标记该目标被取消,并退出执行函数。
  4. 目标完成:循环结束后,检查 ROS 是否在正常运行(rclcpp::ok()),如果是,意味着计算成功完成。
    将最终计算的完整 Fibonacci 序列返回,并调用 goal_handle->succeed(result) 标记目标成功完成。

自带接口说明

get_goal()succeed(result)publish_feedback(feedback) 这些都是 ROS 2 动作接口提供的函数,用于处理动作服务器与客户端之间的通信,尤其是在动作(action)的目标执行、反馈、取消、以及结果返回方面。

我将详细解释这些接口,并讲解哪些是 Fibonacci 动作定义中的变量。

1. 动作接口函数

这些函数是 ROS 2 动作库中的标准接口,用于处理动作请求和响应:

  • get_goal():
    这个函数用于获取客户端发送给动作服务器的目标(goal)。目标通常包含需要服务器执行的动作的参数。在你的例子中,目标就是 Fibonacci 数列的长度(order),即客户端要求生成的数列长度。

  • succeed(result):
    这个函数用于通知动作服务器,目标执行已成功完成,并返回最终的结果。result 包含的是动作完成后的最终数据。在 Fibonacci 的例子中,result->sequence 是生成的完整 Fibonacci 序列。

  • publish_feedback(feedback):
    这个函数用于发送反馈信息给客户端。在执行长时间任务时,服务器可以定期通过反馈将当前的状态或中间结果发送给客户端。在这个例子中,feedback->partial_sequence 是已经计算出的 Fibonacci 序列的部分数据。

这些接口函数是动作库的一部分,适用于任何 ROS 2 动作,不仅限于 Fibonacci 示例。

2. Fibonacci 动作中的定义变量

在 ROS 2 动作中,消息定义文件通常包含 三个部分goal(目标)、feedback(反馈)、result(结果)。在 Fibonacci 动作中,它们可能被定义如下:

# Fibonacci.action

# Goal definition (目标)
int32 order  # 要生成的 Fibonacci 数列的长度

---
# Result definition (结果)
int32[] sequence  # 完整的 Fibonacci 数列

---
# Feedback definition (反馈)
int32[] partial_sequence  # 部分生成的 Fibonacci 数列

具体来说:

  1. Goal 部分:

    • int32 order: 这是客户端传递给服务器的目标数据,表示要生成的 Fibonacci 数列长度。在代码中,使用 goal_handle->get_goal()->order 获取这个值。
  2. Result 部分:

    • int32[] sequence: 最终的 Fibonacci 数列,服务器在成功完成目标后返回给客户端。它在代码中通过 result->sequence 进行访问,并在目标完成时通过 goal_handle->succeed(result) 返回。
  3. Feedback 部分:

    • int32[] partial_sequence: 当前生成的部分 Fibonacci 数列,服务器在执行过程中不断更新并通过 goal_handle->publish_feedback(feedback) 发送反馈给客户端。在代码中,它通过 feedback->partial_sequence 来访问和更新。

总结

  • get_goal(): 从 Goal 获取动作的目标(如 Fibonacci 数列长度)。
  • succeed(result): 当动作成功完成时返回 Result(如完整的 Fibonacci 序列)。
  • publish_feedback(feedback): 在执行过程中发送 Feedback(如部分生成的 Fibonacci 序列)。

Fibonacci 动作中的变量是 GoalorderResultsequenceFeedbackpartial_sequence,这些都在代码中分别用于获取目标、生成反馈和返回结果。


网站公告

今日签到

点亮在社区的每一天
去签到