ROS2編程基礎課程--Actions
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_ws\srccd action_ws\src
ros2 pkg create action_tutorials
Tutorials
Creating an Action
Writing an Action Server (C++)
Writing an Action Client (C++)
Writing an Action Server (Python)
Writing an Action Client (Python)
在完成文檔閱讀之后,學習源碼:
Fibonacci.action
int32 order
---
int32[] sequence
---
int32[] partial_sequence
Server/member_functions.cpp
#include
#include
#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
explicit MinimalActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
: Node("minimal_action_server", options)
{
using namespace std::placeholders;
this->action_server_ = rclcpp_action::create_server
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
rclcpp_action::GoalResponse handle_goal(
const rclcpp_action::GoalUUID & uuid,
std::shared_ptr
{
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
{
RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
(void)goal_handle;
return rclcpp_action::CancelResponse::ACCEPT;
}
void execute(const std::shared_ptr
{
RCLCPP_INFO(this->get_logger(), "Executing goal");
rclcpp::Rate loop_rate(1);
const auto goal = goal_handle->get_goal();
auto feedback = std::make_shared
auto & sequence = feedback->sequence;
sequence.push_back(0);
sequence.push_back(1);
auto result = std::make_shared
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
{
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
rclcpp::spin(action_server);
rclcpp::shutdown();
return 0;
}
Client/member_functions.cpp
#include
#include
#include
#include
#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
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
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
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
rclcpp::TimerBase::SharedPtr timer_;
bool goal_done_;
void goal_response_callback(std::shared_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
{
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
while (!action_client->is_goal_done()) {
rclcpp::spin_some(action_client);
}
rclcpp::shutdown();
return 0;
}
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。