[ROS2] --- action

1 action介紹

ROS通信機制也會被常常用到——那就是動作。從這個名字上就可以很好理解這個概念的含義,這種通信機制的目的就是便于對機器人某一完整行為的流程進行管理。

1.1 客戶端/服務器模型

動作和服務類似,使用的也是客戶端和服務器模型,客戶端發送動作的目標,想讓機器人干什么,服務器端執行動作過程, 控制機器人達到運動的目標,同時周期反饋動作執行過程中的狀態。
在這里插入圖片描述
客戶端發送一個運動的目標,想讓機器人動起來,服務器端收到之后,就開始控制機器人運動,一邊運動,一邊反饋當前的狀態,如果是一個導航動作,這個反饋可能是當前所處的坐標,如果是機械臂抓取,這個反饋可能又是機械臂的實時姿態。當運動執行結束后,服務器再反饋一個動作結束的信息。整個通信過程就此結束。

1.2 action通信特點

  • 一對多通信
    和服務一樣,動作通信中的客戶端可以有多個,大家都可以發送運動命令,但是服務器端只能有一個,畢竟只有一個機器人,先執行完成一個動作,才能執行下一個動作。

  • 同步通信
    既然有反饋,那動作也是一種同步通信機制,之前我們也介紹過,動作過程中的數據通信接口,使用.action文件進行定義。

  • 由服務和話題合成
    大家再仔細看下上邊的動圖,是不是還會發現一個隱藏的秘密。
    動作的三個通信模塊,竟然有兩個是服務,一個是話題,當客戶端發送運動目標時,使用的是服務的請求調用,服務器端也會反饋一個應帶,表示收到命令。動作的反饋過程,其實就是一個話題的周期發布,服務器端是發布者,客戶端是訂閱者。
    沒錯,動作是一種應用層的通信機制,其底層就是基于話題和服務來實現的。

2 action自定義通信接口

延續上一講[ROS2] — action,中創建的自定義接口功能包,在src目錄下創建action/Concatenate.action文件
Concatenate.action

int16 num_concatenations
---
string final_concatenation
---
string partial_concatenation

3 action編碼示例

這里創建功能包名為,learning04_action

3.1 class_action_client.cpp

/*** @file class_action_client.cpp** @brief A class defined ROS2 action client node that sends as goal the number of string*        concatenation the action server should perform. *        The server will send back feedbacks and the final result** @author Antonio Mauro Galiano* Contact: https://www.linkedin.com/in/antoniomaurogaliano/**/#include "custom_interface/action/concatenate.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"class ConcatenateActionClient : public rclcpp::Node
{
public:using Concatenate = custom_interface::action::Concatenate;using GoalHandleConcatenate = rclcpp_action::ClientGoalHandle<Concatenate>;explicit ConcatenateActionClient(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions()): Node("class_action_client", node_options), goalDone_(false){this->clientPtr_ = rclcpp_action::create_client<Concatenate>(this->get_node_base_interface(),this->get_node_graph_interface(),this->get_node_logging_interface(),this->get_node_waitables_interface(),"concatenation");this->timer_ = this->create_wall_timer(std::chrono::milliseconds(500),std::bind(&ConcatenateActionClient::SendGoal, this));}bool GoalDone() const;void SendGoal();private:rclcpp_action::Client<Concatenate>::SharedPtr clientPtr_;rclcpp::TimerBase::SharedPtr timer_;bool goalDone_;void FeedbackCallback(GoalHandleConcatenate::SharedPtr,const std::shared_ptr<const Concatenate::Feedback> feedback);void ResultCallback(const GoalHandleConcatenate::WrappedResult & result);// be sure to define the parameter as it's here// more info at the declarationvoid GoalResponseCallback(const GoalHandleConcatenate::SharedPtr &goalHandle);
};bool ConcatenateActionClient::GoalDone() const
{return this->goalDone_;
}void ConcatenateActionClient::SendGoal()
{using namespace std::placeholders;this->timer_->cancel();this->goalDone_ = false;if (!this->clientPtr_){RCLCPP_ERROR(this->get_logger(), "Action client not initialized");}if (!this->clientPtr_->wait_for_action_server(std::chrono::seconds(10))){RCLCPP_ERROR(this->get_logger(), "!!ATTENTION!! Action server not available");this->goalDone_ = true;return;}auto goalMsg = Concatenate::Goal();goalMsg.num_concatenations = 9;RCLCPP_INFO(this->get_logger(), "Sending goal");auto send_goal_options = rclcpp_action::Client<Concatenate>::SendGoalOptions();send_goal_options.feedback_callback =std::bind(&ConcatenateActionClient::FeedbackCallback, this, _1, _2);send_goal_options.result_callback =std::bind(&ConcatenateActionClient::ResultCallback, this, _1);// send_goal_options.goal_response_callback =//   std::bind(&ConcatenateActionClient::GoalResponseCallback, this, _1);auto goal_handle_future = this->clientPtr_->async_send_goal(goalMsg, send_goal_options);
}void ConcatenateActionClient::FeedbackCallback(rclcpp_action::ClientGoalHandle<Concatenate>::SharedPtr,const std::shared_ptr<const Concatenate::Feedback> feedback)
{RCLCPP_INFO(this->get_logger(),"Feedback received: %s",feedback->partial_concatenation.c_str());
}void ConcatenateActionClient::ResultCallback(const GoalHandleConcatenate::WrappedResult & result)
{this->goalDone_ = 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->final_concatenation){RCLCPP_INFO(this->get_logger(), "%d", number);}
}// defining the parameter directly as a GoalHandleConcatenate::SharedPtr goalHandle
// it's wrong for the send_goal_options.goal_response_callback
// so it doesnt compile
void ConcatenateActionClient::GoalResponseCallback(const GoalHandleConcatenate::SharedPtr &goalHandle){if (!goalHandle){RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");} else{RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result");}}int main(int argc, char ** argv)
{rclcpp::init(argc, argv);auto action_client = std::make_shared<ConcatenateActionClient>();while (!action_client->GoalDone()){rclcpp::spin_some(action_client);}rclcpp::shutdown();return 0;
}

3.2 class_action_server.cpp

/*** @file class_action_server.cpp** @brief A class defined ROS2 action server node that concatenates a string *         based on the number of string concatenation sent by a client within a goal request** @author Antonio Mauro Galiano* Contact: https://www.linkedin.com/in/antoniomaurogaliano/**/#include "custom_interface/action/concatenate.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"class ConcatenateActionServer : public rclcpp::Node
{
public:using Concatenate = custom_interface::action::Concatenate;using GoalHandleConcatenate = rclcpp_action::ServerGoalHandle<Concatenate>;explicit ConcatenateActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions()): Node("class_action_server", options){using namespace std::placeholders;this->actionServer_ = rclcpp_action::create_server<Concatenate>(this->get_node_base_interface(),this->get_node_clock_interface(),this->get_node_logging_interface(),this->get_node_waitables_interface(),"concatenation",std::bind(&ConcatenateActionServer::HandleGoal, this, _1, _2),std::bind(&ConcatenateActionServer::HandleCancel, this, _1),std::bind(&ConcatenateActionServer::HandleAccepted, this, _1));}private:rclcpp_action::Server<Concatenate>::SharedPtr actionServer_;rclcpp_action::GoalResponse HandleGoal(const rclcpp_action::GoalUUID & uuid,std::shared_ptr<const Concatenate::Goal> goal);rclcpp_action::CancelResponse HandleCancel(const std::shared_ptr<GoalHandleConcatenate> goalHandle);void execute(const std::shared_ptr<GoalHandleConcatenate> goalHandle);void HandleAccepted(const std::shared_ptr<ConcatenateActionServer::GoalHandleConcatenate> goalHandle);
};rclcpp_action::GoalResponse ConcatenateActionServer::HandleGoal(const rclcpp_action::GoalUUID & uuid,std::shared_ptr<const Concatenate::Goal> goal)
{RCLCPP_INFO(rclcpp::get_logger("server"),"Got goal request with %d string concatenations",goal->num_concatenations);(void)uuid;// conditional to reject numbers of concatenationsif ((goal->num_concatenations > 10) && (goal->num_concatenations < 2)) {return rclcpp_action::GoalResponse::REJECT;}return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
}rclcpp_action::CancelResponse ConcatenateActionServer::HandleCancel(const std::shared_ptr<GoalHandleConcatenate> goalHandle)
{RCLCPP_INFO(rclcpp::get_logger("server"), "Got request to cancel goal");(void)goalHandle;return rclcpp_action::CancelResponse::ACCEPT;
}void ConcatenateActionServer::execute(const std::shared_ptr<GoalHandleConcatenate> goalHandle)
{RCLCPP_INFO(rclcpp::get_logger("server"), "Executing the concatenation");rclcpp::Rate loop_rate(1);const auto goal = goalHandle->get_goal();auto feedback = std::make_shared<Concatenate::Feedback>();std::string myString = "HELLOWORLD";auto &concatenation = feedback->partial_concatenation;concatenation = myString;concatenation = concatenation + " " + myString;auto result = std::make_shared<Concatenate::Result>();for (int i = 1; (i < goal->num_concatenations) && rclcpp::ok(); ++i){// check if there is a cancel requestif (goalHandle->is_canceling()){result->final_concatenation = concatenation;goalHandle->canceled(result);RCLCPP_INFO(rclcpp::get_logger("server"), "Goal Canceled");return;}// update the final concatenationconcatenation = concatenation + " " + myString;// update and publish feedback of the partial concatenationgoalHandle->publish_feedback(feedback);RCLCPP_INFO(rclcpp::get_logger("server"), "Publish Feedback");loop_rate.sleep();}// check if goal is doneif (rclcpp::ok()){result->final_concatenation = concatenation;goalHandle->succeed(result);RCLCPP_INFO(rclcpp::get_logger("server"), "Goal Succeeded");}
}void ConcatenateActionServer::HandleAccepted(const std::shared_ptr<GoalHandleConcatenate> goal_handle)
{using namespace std::placeholders;// this needs to return quickly to avoid blocking the executor, so spin up a new threadstd::thread{std::bind(&ConcatenateActionServer::execute, this, _1), goal_handle}.detach();
}int main(int argc, char ** argv)
{rclcpp::init(argc, argv);auto action_server = std::make_shared<ConcatenateActionServer>();rclcpp::spin(action_server);rclcpp::shutdown();return 0;
}

3.3 CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(learning04_action)# Default to C99
if(NOT CMAKE_C_STANDARD)set(CMAKE_C_STANDARD 99)
endif()# Default to C++14
if(NOT CMAKE_CXX_STANDARD)set(CMAKE_CXX_STANDARD 14)
endif()if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic)
endif()# find dependencies
find_package(ament_cmake REQUIRED)
find_package(custom_interface REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_action REQUIRED)
find_package(rclcpp_components REQUIRED)# add_executable(simple_action_server src/simple_action_server.cpp)
# ament_target_dependencies(simple_action_server
#   "rclcpp"
#   "rclcpp_action"
#   "custom_interface")add_executable(class_action_server src/class_action_server.cpp)
ament_target_dependencies(class_action_server"rclcpp""rclcpp_action""custom_interface")# add_executable(simple_action_client src/simple_action_client.cpp)
# ament_target_dependencies(simple_action_client
#   "rclcpp"
#   "rclcpp_action"
#   "custom_interface")add_executable(class_action_client src/class_action_client.cpp)
ament_target_dependencies(class_action_client"rclcpp""rclcpp_action""custom_interface")if(BUILD_TESTING)find_package(ament_lint_auto REQUIRED)ament_lint_auto_find_test_dependencies()
endif()install(TARGETS# simple_action_serverclass_action_server# simple_action_clientclass_action_clientDESTINATION lib/${PROJECT_NAME})ament_package()

3.4 package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3"><name>learning04_action</name><version>0.0.0</version><description>Action based tutorial</description><maintainer email="user@todo.todo">Antonio Mauro Galiano</maintainer><license>TODO: License declaration</license><buildtool_depend>ament_cmake</buildtool_depend><depend>custom_interface</depend><depend>rclcpp</depend><depend>rclcpp_action</depend><depend>rclcpp_components</depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><export><build_type>ament_cmake</build_type></export>
</package>

4 編譯運行

# 編譯
colcon build# source環境變量
source install/setup.sh# 運行publisher
ros2 run learning04_action class_action_client# 運行subsriber
ros2 run learning04_action class_action_server

5 action常用指令

# 查看action信息
ros2 action info /turtle/roate_absolute# 設置action通信結構
ros2 interface show /turtle/roate_absolute# 發送action請求
ros2 action send_goal <action_name> <action_type> <values>
ros2 action send_goal /turtle/roate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}"
ros2 action send_goal /turtle/roate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}" --feedback

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/209462.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/209462.shtml
英文地址,請注明出處:http://en.pswp.cn/news/209462.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構中處理散列沖突的四種方法

1 開放定址法 1.1 定義 開放定址法就是一旦發生了沖突&#xff0c;就去尋找下一個空的散列地址 1.2 要求 只要散列表足夠大 空的散列地址總能找到&#xff0c;并將記錄存入 1.3 線性探測法 使用該公式用于解決沖突的開放定址法稱為線性探測法 對于線性探測法&#xff0c…

【異常】SpringBoot3.2.0 Description: Failed to configure a DataSource: ‘url‘ att

mybatisPlus 多數據源導致 異常 Description:Failed to configure a DataSource: url attribute is not specified and no embedded datasource could be configured.Reason: Failed to determine a suitable driver classAction:Consider the following:If you want an embed…

通過kubeadm方式安裝k8s

虛擬機最少是 2 core&#xff0c;master內存最小3G&#xff0c;node內存最小2G. 要求的Docker版本是18.03&#xff0c;如果不是安裝的docker ce&#xff0c;版本是過舊的&#xff0c;可以選擇刪除后重新安裝&#xff1b; 也可以重新創建一個虛擬機執行以下命令。 簡單方法&am…

線性代數基礎【1】行列式

第一節 行列式的基本概念和性質 一、基本概念 ①逆序 1,2和2,1是一對逆序 ②逆序數 1,2,3,5,4的逆序數為1;1,3,2,5,4逆序數為4; ③行列式 ④余子數和代數余子數 行列式挖掉一個數(例如aij),將原行列式去掉i行j列的行列式M,則M為余子數,代數余子數記為Aij,如果(ij)為偶數…

云LIS實驗室信息管理系統源碼——實驗室信息管理解決方案

云LIS&#xff08;Cloud Laboratory Information System&#xff09;是一種為區域醫療提供臨床實驗室信息服務的計算機應用程序&#xff0c;其主要功能是協助區域內所有臨床實驗室相互協調并完成日常檢驗工作&#xff0c;對區域內的檢驗數據進行集中管理和共享&#xff0c;通過…

uniapp引入插件市場echarts圖表(l-echart)實現小程序端圖表,并修改源碼簡化使用

使用的uniapp插件:l-echart https://ext.dcloud.net.cn/plugin?id4899 注意事項 1.因為小程序有主包分包大小限制&#xff0c;并且uni_modules中的包也會算在主包體積中&#xff0c;而我項目中的圖表是在分包中使用的&#xff0c;所以我移動uni_modules中的l-echart圖表組件…

Python 的list是...

對 Python list遺憾 sum 對列表執行正確的操作幾乎是不可能的。 my_list list(range(1, 100001))能夠執行 sum()、min() 和 max() 的情況非常罕見。 sum(my_list)5000050000比如mean(), std() &#xff0c;這些也不行。 mean(my_list)----------------------------------…

高通CRM的v4l2驅動模型

概述下crm中v4l2框架的初始化創建流程&#xff1a; 對于CRM主設備的v4l2框架創建過程&#xff1a; 1、分配和初始化v4l2 device對象 2、分配和初始化media device對象&#xff0c;然后將v4l2 device中mdev綁定到media device上 3、分配和初始化video device對象&#xff0c…

Python:核心知識點整理大全9-筆記

目錄 ?編輯 5.2.4 比較數字 5.2.5 檢查多個條件 1. 使用and檢查多個條件 2. 使用or檢查多個條件 5.2.6 檢查特定值是否包含在列表中 5.2.7 檢查特定值是否不包含在列表中 banned_users.py 5.2.8 布爾表達式 5.3 if 語句 5.3.1 簡單的 if 語句 5.3.2 if-else 語句 …

Java中sleep() 和 wait() 有什么區別?

Java中sleep() 和 wait() 有什么區別&#xff1f; sleep() 和 wait() 是兩個在 Java 中用于線程控制的方法&#xff0c;它們有一些重要的區別&#xff1a; 關聯對象&#xff1a; sleep() 是 Thread 類的靜態方法&#xff0c;它讓當前線程休眠指定的時間&#xff0c;不釋放對象…

YOLOv8改進 | 2023 | RCS-OSA替換C2f實現暴力漲點(減少通道的空間對象注意力機制)

一、本文介紹 本文給大家帶來的改進機制是RCS-YOLO提出的RCS-OSA模塊&#xff0c;其全稱是"Reduced Channel Spatial Object Attention"&#xff0c;意即"減少通道的空間對象注意力"。這個模塊的主要功能是通過減少特征圖的通道數量&#xff0c;同時關注空…

Android Studio APK打包指定包名

在最近寫的一個案列中嘗試用最新版的Android studio對項目進行打包測試&#xff0c;想要指定打包的包名這樣便于區分的時候發現以前的許多方法都過時了&#xff0c;查了很多資料才弄明白each被拋棄了。本教程建議先看第三步。 目錄 一、配置根目錄下gradle.build 二、通過bui…

Billu_b0x

信息收集 #正常進行信息收集就好Starting Nmap 7.94 ( https://nmap.org ) at 2023-11-18 22:07 CST Nmap scan report for 192.168.182.142 (192.168.182.142) Host is up (0.00073s latency).PORT STATE SERVICE 22/tcp open ssh 80/tcp open http | http-cookie-flags:…

VSC改造MD編輯器及圖床方案分享

VSC改造MD編輯器及圖床方案分享 用了那么多md編輯器&#xff0c;到頭來還是覺得VSC最好用。這次就來分享一下我的blog文件編輯流吧。 這篇文章包括&#xff1a;VSC下md功能擴展插件推薦、圖床方案、blog文章管理方案 VSC插件 Markdown All in One Markdown Image - 粘粘圖片…

【電子通識】為什么電阻都是2.2、3.3、4.7、5.1這樣的小數,而不是整數?

剛開始接觸電路設計可能會對市面上已經有的電阻值如&#xff1a;2.2Ω、4.7Ω、5.1Ω、22Ω、47Ω、51Ω&#xff0c;通常都不是整數覺得非常困惑&#xff0c;所以查閱了一些資料&#xff0c;總結如下&#xff1a; 電阻是使用指數分布來設計生產的&#xff0c;即遵循國際電工委…

【CSP】202303-2_墾田計劃Python實現

文章目錄 [toc]試題編號試題名稱時間限制內存限制問題描述輸入格式輸出格式樣例輸入1樣例輸出1樣例解釋樣例輸入2樣例輸出2樣例解釋子任務Python實現 試題編號 202303-2 試題名稱 墾田計劃 時間限制 1.0s 內存限制 512.0MB 問題描述 頓頓總共選中了 n n n塊區域準備開墾田地&a…

基于STM32 + DMA介紹,應用和步驟詳解(ADC多通道)

前言 本篇博客主要學習了解DMA的工作原理和部分寄存器解析&#xff0c;針對ADC多通道來對代碼部分&#xff0c;應用部分作詳細講解&#xff0c;掌握代碼編程原理。本篇博客大部分是自己收集和整理&#xff0c;如有侵權請聯系我刪除。 本次博客開發板使用的是正點原子精英版&am…

23種策略模式之策略模式

文章目錄 前言優缺點使用場景角色定義UML模擬示例小結 前言 在軟件開發中&#xff0c;設計模式是為了解決常見問題而提供的一套可重用的解決方案。策略模式&#xff08;Strategy Pattern&#xff09;是其中一種常見的設計模式&#xff0c;它屬于行為型模式。該模式的核心思想是…

Java程序設計實驗6 | 集合類

*本文是博主對Java各種實驗的再整理與詳解&#xff0c;除了代碼部分和解析部分&#xff0c;一些題目還增加了拓展部分&#xff08;?&#xff09;。拓展部分不是實驗報告中原有的內容&#xff0c;而是博主本人自己的補充&#xff0c;以方便大家額外學習、參考。 &#xff08;解…

基于ssm的大型商場會員管理系統論文

摘 要 進入信息時代以來&#xff0c;很多數據都需要配套軟件協助處理&#xff0c;這樣可以解決傳統方式帶來的管理困擾。比如耗時長&#xff0c;成本高&#xff0c;維護數據困難&#xff0c;數據易丟失等缺點。本次使用數據庫工具MySQL和編程框架SSM開發的大型商場會員管理系統…