ROS2編程基礎課程–Actions

  • 2019 年 10 月 5 日
  • 筆記

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:https://blog.csdn.net/ZhangRelay/article/details/100773826

Actions 行動

About 關於

Actions are a form of asynchronous communication in ROS. Action clients send goal requests to action servers. Action servers send goal feedback and results to action clients. For more detailed information about ROS actions, please refer to the design article.

行動是ROS中異步通信的一種形式。 Action客戶端將目標請求發送到操作服務器操作服務器將目標反饋和結果發送給操作客戶端。有關ROS操作的更多詳細信息,請參考設計文章

This document contains a list of tutorials related to actions. For reference, after completing all of the tutorials you should expect to have a ROS package that looks like the package action_tutorials.

本文檔包含與操作相關的教程列表。作為參考,在完成所有教程之後,需要有一個類似於action_tutorials的ROS包。

Prequisites 預備基礎

Install ROS (Dashing or later) 安裝ROS(Dashing或更高版本)

Install colcon 安裝colcon

Setup a workspace and create a package named action_tutorials:

設置工作區並創建名為action_tutorials的包:

Remember to source your ROS 2 installation. 記得要安裝ROS 2。

Linux / OSX:

mkdir -p action_ws/src

cd action_ws/src

ros2 pkg create action_tutorials

Windows:

mkdir -p action_wssrccd action_wssrc

ros2 pkg create action_tutorials

Tutorials

在完成文檔閱讀之後,學習源碼:

Fibonacci.action

int32 order

int32[] sequence

int32[] partial_sequence

Server/member_functions.cpp  #include <inttypes.h>  #include <memory>  #include "example_interfaces/action/fibonacci.hpp"  #include "rclcpp/rclcpp.hpp"  // TODO(jacobperron): Remove this once it is included as part of 'rclcpp.hpp'  #include "rclcpp_action/rclcpp_action.hpp"  class MinimalActionServer : public rclcpp::Node  {  public:    using Fibonacci = example_interfaces::action::Fibonacci;    using GoalHandleFibonacci = rclcpp_action::ServerGoalHandle<Fibonacci>;    explicit MinimalActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())    : Node("minimal_action_server", options)    {      using namespace std::placeholders;      this->action_server_ = rclcpp_action::create_server<Fibonacci>(        this->get_node_base_interface(),        this->get_node_clock_interface(),        this->get_node_logging_interface(),        this->get_node_waitables_interface(),        "fibonacci",        std::bind(&MinimalActionServer::handle_goal, this, _1, _2),        std::bind(&MinimalActionServer::handle_cancel, this, _1),        std::bind(&MinimalActionServer::handle_accepted, this, _1));    }  private:    rclcpp_action::Server<Fibonacci>::SharedPtr action_server_;    rclcpp_action::GoalResponse handle_goal(      const rclcpp_action::GoalUUID & uuid,      std::shared_ptr<const Fibonacci::Goal> goal)    {      RCLCPP_INFO(this->get_logger(), "Received goal request with order %d", goal->order);      (void)uuid;      // Let's reject sequences that are over 9000      if (goal->order > 9000) {        return rclcpp_action::GoalResponse::REJECT;      }      return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;    }    rclcpp_action::CancelResponse handle_cancel(      const std::shared_ptr<GoalHandleFibonacci> goal_handle)    {      RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");      (void)goal_handle;      return rclcpp_action::CancelResponse::ACCEPT;    }    void execute(const std::shared_ptr<GoalHandleFibonacci> goal_handle)    {      RCLCPP_INFO(this->get_logger(), "Executing goal");      rclcpp::Rate loop_rate(1);      const auto goal = goal_handle->get_goal();      auto feedback = std::make_shared<Fibonacci::Feedback>();      auto & sequence = feedback->sequence;      sequence.push_back(0);      sequence.push_back(1);      auto result = std::make_shared<Fibonacci::Result>();      for (int i = 1; (i < goal->order) && rclcpp::ok(); ++i) {        // Check if there is a cancel request        if (goal_handle->is_canceling()) {          result->sequence = sequence;          goal_handle->canceled(result);          RCLCPP_INFO(this->get_logger(), "Goal Canceled");          return;        }        // Update sequence        sequence.push_back(sequence[i] + sequence[i - 1]);        // Publish feedback        goal_handle->publish_feedback(feedback);        RCLCPP_INFO(this->get_logger(), "Publish Feedback");        loop_rate.sleep();      }      // Check if goal is done      if (rclcpp::ok()) {        result->sequence = sequence;        goal_handle->succeed(result);        RCLCPP_INFO(this->get_logger(), "Goal Suceeded");      }    }    void handle_accepted(const std::shared_ptr<GoalHandleFibonacci> goal_handle)    {      using namespace std::placeholders;      // this needs to return quickly to avoid blocking the executor, so spin up a new thread      std::thread{std::bind(&MinimalActionServer::execute, this, _1), goal_handle}.detach();    }  };  // class MinimalActionServer  int main(int argc, char ** argv)  {    rclcpp::init(argc, argv);    auto action_server = std::make_shared<MinimalActionServer>();    rclcpp::spin(action_server);    rclcpp::shutdown();    return 0;  }  Client/member_functions.cpp  #include <inttypes.h>  #include <memory>  #include <string>  #include <iostream>  #include "example_interfaces/action/fibonacci.hpp"  #include "rclcpp/rclcpp.hpp"  // TODO(jacobperron): Remove this once it is included as part of 'rclcpp.hpp'  #include "rclcpp_action/rclcpp_action.hpp"  class MinimalActionClient : public rclcpp::Node  {  public:    using Fibonacci = example_interfaces::action::Fibonacci;    using GoalHandleFibonacci = rclcpp_action::ClientGoalHandle<Fibonacci>;    explicit MinimalActionClient(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())    : Node("minimal_action_client", node_options), goal_done_(false)    {      this->client_ptr_ = rclcpp_action::create_client<Fibonacci>(        this->get_node_base_interface(),        this->get_node_graph_interface(),        this->get_node_logging_interface(),        this->get_node_waitables_interface(),        "fibonacci");      this->timer_ = this->create_wall_timer(        std::chrono::milliseconds(500),        std::bind(&MinimalActionClient::send_goal, this));    }    bool is_goal_done() const    {      return this->goal_done_;    }    void send_goal()    {      using namespace std::placeholders;      this->timer_->cancel();      this->goal_done_ = false;      if (!this->client_ptr_) {        RCLCPP_ERROR(this->get_logger(), "Action client not initialized");      }      if (!this->client_ptr_->wait_for_action_server(std::chrono::seconds(10))) {        RCLCPP_ERROR(this->get_logger(), "Action server not available after waiting");        this->goal_done_ = true;        return;      }      auto goal_msg = Fibonacci::Goal();      goal_msg.order = 10;      RCLCPP_INFO(this->get_logger(), "Sending goal");      auto send_goal_options = rclcpp_action::Client<Fibonacci>::SendGoalOptions();      send_goal_options.goal_response_callback =        std::bind(&MinimalActionClient::goal_response_callback, this, _1);      send_goal_options.feedback_callback =        std::bind(&MinimalActionClient::feedback_callback, this, _1, _2);      send_goal_options.result_callback =        std::bind(&MinimalActionClient::result_callback, this, _1);      auto goal_handle_future = this->client_ptr_->async_send_goal(goal_msg, send_goal_options);    }  private:    rclcpp_action::Client<Fibonacci>::SharedPtr client_ptr_;    rclcpp::TimerBase::SharedPtr timer_;    bool goal_done_;    void goal_response_callback(std::shared_future<GoalHandleFibonacci::SharedPtr> future)    {      auto goal_handle = future.get();      if (!goal_handle) {        RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");      } else {        RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result");      }    }    void feedback_callback(      GoalHandleFibonacci::SharedPtr,      const std::shared_ptr<const Fibonacci::Feedback> feedback)    {      RCLCPP_INFO(        this->get_logger(),        "Next number in sequence received: %" PRId64,        feedback->sequence.back());    }    void result_callback(const GoalHandleFibonacci::WrappedResult & result)    {      this->goal_done_ = true;      switch (result.code) {        case rclcpp_action::ResultCode::SUCCEEDED:          break;        case rclcpp_action::ResultCode::ABORTED:          RCLCPP_ERROR(this->get_logger(), "Goal was aborted");          return;        case rclcpp_action::ResultCode::CANCELED:          RCLCPP_ERROR(this->get_logger(), "Goal was canceled");          return;        default:          RCLCPP_ERROR(this->get_logger(), "Unknown result code");          return;      }      RCLCPP_INFO(this->get_logger(), "Result received");      for (auto number : result.result->sequence) {        RCLCPP_INFO(this->get_logger(), "%" PRId64, number);      }    }  };  // class MinimalActionClient  int main(int argc, char ** argv)  {    rclcpp::init(argc, argv);    auto action_client = std::make_shared<MinimalActionClient>();    while (!action_client->is_goal_done()) {      rclcpp::spin_some(action_client);    }    rclcpp::shutdown();    return 0;  }