最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

2.4 動(dòng)作通信

2023-09-20 11:05 作者:猛獅集訓(xùn)營(yíng)  | 我要投稿

場(chǎng)景

關(guān)于action通信,我們先從之前導(dǎo)航中的應(yīng)用場(chǎng)景開(kāi)始介紹,描述如下:

機(jī)器人導(dǎo)航到某個(gè)目標(biāo)點(diǎn),此過(guò)程需要一個(gè)節(jié)點(diǎn)A發(fā)布目標(biāo)信息,然后一個(gè)節(jié)點(diǎn)B接收到請(qǐng)求并控制移動(dòng),最終響應(yīng)目標(biāo)達(dá)成狀態(tài)信息。

乍一看,這好像是服務(wù)通信實(shí)現(xiàn),因?yàn)樾枨笾幸狝發(fā)送目標(biāo),B執(zhí)行并返回結(jié)果,這是一個(gè)典型的基于請(qǐng)求響應(yīng)的應(yīng)答模式,不過(guò),如果只是使用基本的服務(wù)通信實(shí)現(xiàn),存在一個(gè)問(wèn)題:導(dǎo)航是一個(gè)過(guò)程,是耗時(shí)操作,如果使用服務(wù)通信,那么只有在導(dǎo)航結(jié)束時(shí),才會(huì)產(chǎn)生響應(yīng)結(jié)果,而在導(dǎo)航過(guò)程中,節(jié)點(diǎn)A是不會(huì)獲取到任何反饋的,從而可能出現(xiàn)程序"假死"的現(xiàn)象,過(guò)程的不可控意味著不良的用戶體驗(yàn),以及邏輯處理的缺陷(比如:導(dǎo)航中止的需求無(wú)法實(shí)現(xiàn))。更合理的方案應(yīng)該是:導(dǎo)航過(guò)程中,可以連續(xù)反饋當(dāng)前機(jī)器人狀態(tài)信息,當(dāng)導(dǎo)航終止時(shí),再返回最終的執(zhí)行結(jié)果。在ROS中,該實(shí)現(xiàn)策略稱之為:action 通信。

概念

動(dòng)作通信適用于長(zhǎng)時(shí)間運(yùn)行的任務(wù)。就結(jié)構(gòu)而言動(dòng)作通信由目標(biāo)、反饋和結(jié)果三部分組成;就功能而言動(dòng)作通信類(lèi)似于服務(wù)通信,動(dòng)作客戶端可以發(fā)送請(qǐng)求到動(dòng)作服務(wù)端,并接收動(dòng)作服務(wù)端響應(yīng)的最終結(jié)果,不過(guò)動(dòng)作通信可以在請(qǐng)求響應(yīng)過(guò)程中獲取連續(xù)反饋,并且也可以向動(dòng)作服務(wù)端發(fā)送任務(wù)取消請(qǐng)求;就底層實(shí)現(xiàn)而言動(dòng)作通信是建立在話題通信和服務(wù)通信之上的,目標(biāo)發(fā)送實(shí)現(xiàn)是對(duì)服務(wù)通信的封裝,結(jié)果的獲取也是對(duì)服務(wù)通信的封裝,而連續(xù)反饋則是對(duì)話題通信的封裝。


作用

一般適用于耗時(shí)的請(qǐng)求響應(yīng)場(chǎng)景,用以獲取連續(xù)的狀態(tài)反饋。

2.4.1 案例以及案例分析

1.案例需求

需求:編寫(xiě)動(dòng)作通信,動(dòng)作客戶端提交一個(gè)整型數(shù)據(jù)N,動(dòng)作服務(wù)端接收請(qǐng)求數(shù)據(jù)并累加1-N之間的所有整數(shù),將最終結(jié)果返回給動(dòng)作客戶端,且每累加一次都需要計(jì)算當(dāng)前運(yùn)算進(jìn)度并反饋給動(dòng)作客戶端。


2.案例分析

在上述案例中,需要關(guān)注的要素有三個(gè):

  1. 動(dòng)作客戶端;

  2. 動(dòng)作服務(wù)端;

  3. 消息載體。

3.流程簡(jiǎn)介

案例實(shí)現(xiàn)前需要先自定義動(dòng)作接口,接口準(zhǔn)備完畢后,動(dòng)作通信實(shí)現(xiàn)主要步驟如下:

  1. 編寫(xiě)動(dòng)作服務(wù)端實(shí)現(xiàn);

  2. 編寫(xiě)動(dòng)作客戶端實(shí)現(xiàn);

  3. 編輯配置文件;

  4. 編譯;

  5. 執(zhí)行。

案例我們會(huì)采用C++和Python分別實(shí)現(xiàn),二者都遵循上述實(shí)現(xiàn)流程。

4.準(zhǔn)備工作

終端下進(jìn)入工作空間的src目錄,調(diào)用如下兩條命令分別創(chuàng)建C++功能包和Python功能包。

ros2 pkg create cpp03_action --build-type ament_cmake --dependencies rclcpp rclcpp_action base_interfaces_demo?

ros2 pkg create py03_action --build-type ament_python --dependencies rclpy base_interfaces_demo


2.4.2 動(dòng)作通信接口消息

定義動(dòng)作接口消息與定義話題或服務(wù)接口消息流程類(lèi)似,主要步驟如下:

  1. 創(chuàng)建并編輯.action文件;

  2. 編輯配置文件;

  3. 編譯;

  4. 測(cè)試。

接下來(lái),我們可以參考案例編寫(xiě)一個(gè)action文件,該文件中包含請(qǐng)求數(shù)據(jù)(一個(gè)整型字段)、響應(yīng)數(shù)據(jù)(一個(gè)整型字段)和連續(xù)反饋數(shù)據(jù)(一個(gè)浮點(diǎn)型字段)。

1.創(chuàng)建并編輯 .action 文件

功能包base_interfaces_demo下新建action文件夾,action文件夾下新建Progress.action文件,文件中輸入如下內(nèi)容:

int64 num?

---?

int64 sum?

---?

float64 progress

2.編輯配置文件

1.package.xml

如果單獨(dú)構(gòu)建action功能包,需要在package.xml中需要添加一些依賴包,具體內(nèi)容如下:

<buildtool_depend>rosidl_default_generators</buildtool_depend> <depend>action_msgs</depend> <member_of_group>rosidl_interface_packages</member_of_group>

當(dāng)前使用的是 base_interfaces_demo 功能包,已經(jīng)為 msg 、srv 文件添加過(guò)了一些依賴,所以 package.xml 中添加如下內(nèi)容即可:

<buildtool_depend>rosidl_default_generators</buildtool_depend> <depend>action_msgs</depend>

2.CMakeLists.txt

如果是新建的功能包,與之前定義msg、srv文件同理,為了將.action文件轉(zhuǎn)換成對(duì)應(yīng)的C++和Python代碼,還需要在CMakeLists.txt 中添加如下配置:

find_package(rosidl_default_generators REQUIRED)?

rosidl_generate_interfaces(${PROJECT_NAME} ?

? "action/Progress.action"?

)

不過(guò),我們當(dāng)前使用的base_interfaces_demo包,那么只需要修改rosidl_generate_interfaces函數(shù)即可,修改后的內(nèi)容如下:

rosidl_generate_interfaces(${PROJECT_NAME} ?

?"msg/Student.msg" ?

?"srv/AddInts.srv" ?

?"action/Progress.action"?

)

3.編譯

終端中進(jìn)入當(dāng)前工作空間,編譯功能包:

colcon build --packages-select base_interfaces_demo

4.測(cè)試

編譯完成之后,在工作空間下的 install 目錄下將生成Progress.action文件對(duì)應(yīng)的C++和Python文件,我們也可以在終端下進(jìn)入工作空間,通過(guò)如下命令查看文件定義以及編譯是否正常:

. install/setup.bash?

ros2 interface show base_interfaces_demo/action/Progress

正常情況下,終端將會(huì)輸出與Progress.action文件一致的內(nèi)容。

2.4.3 動(dòng)作通信(C++)

1.動(dòng)作服務(wù)端實(shí)現(xiàn)

功能包c(diǎn)pp03_action的src目錄下,新建C++文件demo01_action_server.cpp,并編輯文件,輸入如下內(nèi)容:

/* ? ?

需求:編寫(xiě)動(dòng)作服務(wù)端實(shí)習(xí),可以提取客戶端請(qǐng)求提交的整型數(shù)據(jù),并累加從1到該數(shù)據(jù)之間的所有整數(shù)以求和, ? ? ?

? ?每累加一次都計(jì)算當(dāng)前運(yùn)算進(jìn)度并連續(xù)反饋回客戶端,最后,在將求和結(jié)果返回給客戶端。 ?

步驟: ? ?

? 1.包含頭文件; ? ?

? 2.初始化 ROS2 客戶端; ? ?

? 3.定義節(jié)點(diǎn)類(lèi); ? ? ?

? ?3-1.創(chuàng)建動(dòng)作服務(wù)端; ? ? ?

? ?3-2.處理請(qǐng)求數(shù)據(jù); ? ? ?

? ?3-3.處理取消任務(wù)請(qǐng)求; ? ? ?

? ?3-4.生成連續(xù)反饋。 ? ?

? 4.調(diào)用spin函數(shù),并傳入節(jié)點(diǎn)對(duì)象指針; ? ?

? 5.釋放資源。


*/

// 1.包含頭文件;

#include "rclcpp/rclcpp.hpp"

#include "rclcpp_action/rclcpp_action.hpp"

#include "base_interfaces_demo/action/progress.hpp"


using namespace std::placeholders;

using base_interfaces_demo::action::Progress;

using GoalHandleProgress = rclcpp_action::ServerGoalHandle<Progress>;


// 3.定義節(jié)點(diǎn)類(lèi);

class MinimalActionServer : public rclcpp::Node

{

public:

explicit MinimalActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions()) ?

: Node("minimal_action_server", options) ?

{ ? ?

// 3-1.創(chuàng)建動(dòng)作服務(wù)端; ?

this->action_server_ = rclcpp_action::create_server<Progress>( ? ? ?

?this, ? ? ?

?"get_sum", ? ? ?

?std::bind(&MinimalActionServer::handle_goal, this, _1, _2), ? ? ?

?std::bind(&MinimalActionServer::handle_cancel, this, _1), ? ? ?

?std::bind(&MinimalActionServer::handle_accepted, this, _1)); ? ?

RCLCPP_INFO(this->get_logger(),"動(dòng)作服務(wù)端創(chuàng)建,等待請(qǐng)求..."); ?

}


private: ?

rclcpp_action::Server<Progress>::SharedPtr action_server_; ?

// 3-2.處理請(qǐng)求數(shù)據(jù); ?

rclcpp_action::GoalResponse handle_goal(const rclcpp_action::GoalUUID & uuid,std::shared_ptr<const Progress::Goal> goal) ?

{ ? ?

(void)uuid; ? ?

RCLCPP_INFO(this->get_logger(), "接收到動(dòng)作客戶端請(qǐng)求,請(qǐng)求數(shù)字為 %ld", goal->num); ? ?

if (goal->num < 1) { ? ? ?

?return rclcpp_action::GoalResponse::REJECT; ? ?

} ? ?

return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE; ?

} ?


// 3-3.處理取消任務(wù)請(qǐng)求; ?

rclcpp_action::CancelResponse handle_cancel( ? ?

?const std::shared_ptr<GoalHandleProgress> goal_handle) ?

{ ? ?

?(void)goal_handle; ? ?

? RCLCPP_INFO(this->get_logger(), "接收到任務(wù)取消請(qǐng)求"); ? ?

? return rclcpp_action::CancelResponse::ACCEPT; ?

} ?


void execute(const std::shared_ptr<GoalHandleProgress> goal_handle) ?

{ ? ?

RCLCPP_INFO(this->get_logger(), "開(kāi)始執(zhí)行任務(wù)"); ? ?

rclcpp::Rate loop_rate(10.0); ? ?

const auto goal = goal_handle->get_goal(); ? ?

auto feedback = std::make_shared<Progress::Feedback>(); ? ?

auto result = std::make_shared<Progress::Result>(); ? ?

int64_t sum= 0; ? ?

for (int i = 1; (i <= goal->num) && rclcpp::ok(); i++) { ? ? ?

? ?sum += i; ? ? ?

? ?// Check if there is a cancel request ? ? ?

? ?if (goal_handle->is_canceling()) { ? ? ? ?

? ? ? result->sum = sum; ? ? ? ?

? ? ? goal_handle->canceled(result); ? ? ? ?

? ? ? RCLCPP_INFO(this->get_logger(), "任務(wù)取消"); ? ? ? ?return; ? ? ?} ? ? ?feedback->progress = (double_t)i / goal->num; ? ? ?goal_handle->publish_feedback(feedback); ? ? ?RCLCPP_INFO(this->get_logger(), "連續(xù)反饋中,進(jìn)度:%.2f", feedback->progress); ? ? ?

? ? ? loop_rate.sleep(); ? ?

? ? ?} ? ?

? ? ? if (rclcpp::ok()) { ? ? ?

? ? ? ? result->sum = sum; ? ? ?

? ? ? ? goal_handle->succeed(result); ? ? ?

? ? ? ? RCLCPP_INFO(this->get_logger(), "任務(wù)完成!"); ? ?

? ? ?} ?

? }

// 3-4.生成連續(xù)反饋。 ?

void handle_accepted(const std::shared_ptr<GoalHandleProgress> goal_handle) ?

{ ? ? ?

std::thread{std::bind(&MinimalActionServer::execute, this, _1), goal_handle}.detach(); ?

}

};


int main(int argc, char ** argv)

{ ?

// 2.初始化 ROS2 客戶端; ?

rclcpp::init(argc, argv); ?

// 4.調(diào)用spin函數(shù),并傳入節(jié)點(diǎn)對(duì)象指針; ?

auto action_server = std::make_shared<MinimalActionServer>(); ? ?

rclcpp::spin(action_server); ?

// 5.釋放資源。 ?

rclcpp::shutdown(); ?

return 0;

}

2.動(dòng)作客戶端實(shí)現(xiàn)

功能包c(diǎn)pp03_action的 src目錄下,新建C++文件demo02_action_client.cpp,并編輯文件,輸入如下內(nèi)容:

/* ? ?

需求:編寫(xiě)動(dòng)作客戶端實(shí)現(xiàn),可以提交一個(gè)整型數(shù)據(jù)到服務(wù)端,并處理服務(wù)端的連續(xù)反饋以及最終返回結(jié)果。 ?

步驟: ? ?

? 1.包含頭文件; ? ?

? 2.初始化 ROS2 客戶端; ? ?

? 3.定義節(jié)點(diǎn)類(lèi); ? ? ?

? ?3-1.創(chuàng)建動(dòng)作客戶端; ? ? ?

? ?3-2.發(fā)送請(qǐng)求; ? ? ?

? ?3-3.處理目標(biāo)發(fā)送后的反饋; ? ? ?

? ?3-4.處理連續(xù)反饋; ? ? ?

? ?3-5.處理最終響應(yīng)。 ? ?

? 4.調(diào)用spin函數(shù),并傳入節(jié)點(diǎn)對(duì)象指針; ? ?

? 5.釋放資源。

*/

// 1.包含頭文件;

#include "rclcpp/rclcpp.hpp"

#include "rclcpp_action/rclcpp_action.hpp"

#include "base_interfaces_demo/action/progress.hpp"


using base_interfaces_demo::action::Progress;

using GoalHandleProgress = rclcpp_action::ClientGoalHandle<Progress>;

using namespace std::placeholders;


// 3.定義節(jié)點(diǎn)類(lèi);

class MinimalActionClient : public rclcpp::Node

{

public: ?

explicit MinimalActionClient(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions()) ?

: Node("minimal_action_client", node_options) ?

{ ? ?

?// 3-1.創(chuàng)建動(dòng)作客戶端; ? ?

?this->client_ptr_ = rclcpp_action::create_client<Progress>(this,"get_sum"); ? ?} ?

?// 3-2.發(fā)送請(qǐng)求; ?

?void send_goal(int64_t num) ?

?{ ? ? ?

? ?if (!this->client_ptr_) { ? ?

? ? RCLCPP_ERROR(this->get_logger(), "動(dòng)作客戶端未被初始化。"); ? ?

? ?} ? ?

? ?if (!this->client_ptr_->wait_for_action_server(std::chrono::seconds(10))) { ? ? ?

? ? ?RCLCPP_ERROR(this->get_logger(), "服務(wù)連接失??!"); ? ? ?

? ? ?return; ? ?

? ? } ? ?

? ? ?auto goal_msg = Progress::Goal(); ? ?

? ? ?goal_msg.num = num; ? ?

? ? ?RCLCPP_INFO(this->get_logger(), "發(fā)送請(qǐng)求數(shù)據(jù)!"); ? ?


? ? ? auto send_goal_options = rclcpp_action::Client<Progress>::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<Progress>::SharedPtr client_ptr_;

// 3-3.處理目標(biāo)發(fā)送后的反饋; ?

void goal_response_callback(GoalHandleProgress::SharedPtr goal_handle) ?

{ ? ?

if (!goal_handle) { ? ?

? RCLCPP_ERROR(this->get_logger(), "目標(biāo)請(qǐng)求被服務(wù)器拒絕!"); ? ?} else { ? ? RCLCPP_INFO(this->get_logger(), "目標(biāo)被接收,等待結(jié)果中"); ? ?

? } ?

} ?

// 3-4.處理連續(xù)反饋; ?

void feedback_callback(GoalHandleProgress::SharedPtr,const std::shared_ptr<const Progress::Feedback> feedback) ?

{ ? ?

? int32_t progress = (int32_t)(feedback->progress * 100); ? ? ?

? RCLCPP_INFO(this->get_logger(), "當(dāng)前進(jìn)度: %d%%", progress); ?

?}

// 3-5.處理最終響應(yīng)。 ?

void result_callback(const GoalHandleProgress::WrappedResult & result) ?

{ ? ?

?switch (result.code) { ?

? ? case rclcpp_action::ResultCode::SUCCEEDED: ? ? ? ?

? ? ? ?break; ? ? ?

? ? case rclcpp_action::ResultCode::ABORTED: ? ? ?

? ? ? ?RCLCPP_ERROR(this->get_logger(), "任務(wù)被中止"); ? ? ? ?

? ? ? ?return; ? ? ?

? ? case rclcpp_action::ResultCode::CANCELED: ? ? ? ?

? ? ? ?RCLCPP_ERROR(this->get_logger(), "任務(wù)被取消"); ? ? ? ?

? ? ? ?return; ? ? ?

? ? ?default: ? ? ? ?

? ? ? ?RCLCPP_ERROR(this->get_logger(), "未知異常"); ? ? ? ?

? ? ? ?return; ?

? } ? ?

? ?RCLCPP_INFO(this->get_logger(), "任務(wù)執(zhí)行完畢,最終結(jié)果: %ld", result.result->sum); ?

? }

};


int main(int argc, char ** argv)

{ ?

// 2.初始化 ROS2 客戶端; ?

rclcpp::init(argc, argv); ?

// 4.調(diào)用spin函數(shù),并傳入節(jié)點(diǎn)對(duì)象指針; ?

auto action_client = std::make_shared<MinimalActionClient>(); ?

action_client->send_goal(10); ?

rclcpp::spin(action_client);

// 5.釋放資源。 ?

rclcpp::shutdown();

return 0;

}

3.編輯配置文件

1.packages.xml

在創(chuàng)建功能包時(shí),所依賴的功能包已經(jīng)自動(dòng)配置了,配置內(nèi)容如下:

<depend>rclcpp</depend>

<depend>rclcpp_action</depend>

<depend>base_interfaces_demo</depend>

2.CMakeLists.txt

CMakeLists.txt中服務(wù)端和客戶端程序核心配置如下:

find_package(rclcpp REQUIRED)?

find_package(rclcpp_action REQUIRED)?

find_package(base_interfaces_demo REQUIRED)


add_executable(demo01_action_server src/demo01_action_server.cpp)?

ament_target_dependencies( ?

?demo01_action_server ?

?"rclcpp" ?

?"rclcpp_action" ?

?"base_interfaces_demo"?

)


add_executable(demo02_action_client src/demo02_action_client.cpp)?

ament_target_dependencies( ?

?demo02_action_client ?

?"rclcpp"?

?"rclcpp_action"?

?"base_interfaces_demo"?

)


install(TARGETS?

?demo01_action_server?

?demo02_action_client?

?DESTINATION lib/${PROJECT_NAME})

4.編譯

終端中進(jìn)入當(dāng)前工作空間,編譯功能包:

colcon build --packages-select cpp03_action

5.執(zhí)行

當(dāng)前工作空間下,啟動(dòng)兩個(gè)終端,終端1執(zhí)行動(dòng)作服務(wù)端程序,終端2執(zhí)行動(dòng)作客戶端程序。

終端1輸入如下指令:

. install/setup.bash?

ros2 run cpp03_action demo01_action_server

終端2輸入如下指令:

. install/setup.bash?

ros2 run cpp03_action demo02_action_client

最終運(yùn)行結(jié)果與案例類(lèi)似。


2.4.4 動(dòng)作通信(Python)

1.動(dòng)作服務(wù)端實(shí)現(xiàn)

功能包py03_action的py03_action目錄下,新建Python文件demo01_action_server_py.py,并編輯文件,輸入如下內(nèi)容:

""" ? ?

? 需求:編寫(xiě)動(dòng)作服務(wù)端實(shí)習(xí),可以提取客戶端請(qǐng)求提交的整型數(shù)據(jù),并累加從1到該數(shù)據(jù)之間的所有整數(shù)以求和, ? ? ?

? 每累加一次都計(jì)算當(dāng)前運(yùn)算進(jìn)度并連續(xù)反饋回客戶端,最后,在將求和結(jié)果返回給客戶端。 ? ?

? 步驟: ? ? ? ?

? ? ? 1.導(dǎo)包; ? ? ? ?

? ? ? 2.初始化 ROS2 客戶端; ? ? ? ?

? ? ? 3.定義節(jié)點(diǎn)類(lèi); ? ? ? ? ? ?

? ? ? ? 3-1.創(chuàng)建動(dòng)作服務(wù)端; ? ? ? ? ? ?

? ? ? ? 3-2.生成連續(xù)反饋; ? ? ? ? ? ?

? ? ? ? 3-3.生成最終響應(yīng)。 ? ? ? ?

? ? ? 4.調(diào)用spin函數(shù),并傳入節(jié)點(diǎn)對(duì)象; ? ? ? ?

? ? ? 5.釋放資源。

"""


# 1.導(dǎo)包;

import time

import rclpy

from rclpy.action import ActionServer

from rclpy.node import Node


from base_interfaces_demo.action import Progress


# 3.定義節(jié)點(diǎn)類(lèi);

class ProgressActionServer(Node): ?


?def __init__(self): ? ?

? ? super().__init__('progress_action_server') ? ? ? ?

? ? # 3-1.創(chuàng)建動(dòng)作服務(wù)端; ? ? ? ?

? ? self._action_server = ActionServer( ? ? ? ? ? ?

? ? ? self, ? ? ? ? ? ?

? ? ? Progress, ? ? ? ? ? ?

? ? ? 'get_sum', ? ? ? ? ? ?

? ? ? self.execute_callback) ? ? ? ?

? ? self.get_logger().info('動(dòng)作服務(wù)已經(jīng)啟動(dòng)!') ? ?


? def execute_callback(self, goal_handle): ? ? ? ?

? ? ?self.get_logger().info('開(kāi)始執(zhí)行任務(wù)....') ? ? ? ?


? ? ?# 3-2.生成連續(xù)反饋; ? ? ? ?

? ? ?feedback_msg = Progress.Feedback() ? ? ? ?


? ? ?sum = 0 ? ? ? ?

? ? ?for i in range(1, goal_handle.request.num + 1): ? ? ? ? ? ?

? ? ? ? sum += i ? ? ? ? ? ?

? ? ? ? feedback_msg.progress = i / goal_handle.request.num ? ? ? ? ? ? ? ? ? ? self.get_logger().info('連續(xù)反饋: %.2f' % feedback_msg.progress) ? ? ? ? ? ?goal_handle.publish_feedback(feedback_msg) ? ? ? ? ? ? ?

? ? ? ? time.sleep(1) ? ? ? ?


? ? ? # 3-3.生成最終響應(yīng)。 ? ? ? ?

? ? ? goal_handle.succeed() ? ? ? ?

? ? ? result = Progress.Result() ? ? ? ?

? ? ? result.sum = sum ? ? ? ?

? ? ? self.get_logger().info('任務(wù)完成!') ? ? ? ?


? ? ? return result


def main(args=None): ? ?

? # 2.初始化 ROS2 客戶端; ?

? rclpy.init(args=args) ? ?

? # 4.調(diào)用spin函數(shù),并傳入節(jié)點(diǎn)對(duì)象; ?

? Progress_action_server = ProgressActionServer() ? ?

? rclpy.spin(Progress_action_server) ?

? # 5.釋放資源。 ?

? rclpy.shutdown()


if __name__ == '__main__': ?

main()

2.動(dòng)作客戶端實(shí)現(xiàn)

功能包py03_action的py03_action目錄下,新建Python文件demo02_action_client_py.py,并編輯文件,輸入如下內(nèi)容:

""" ? ?

?需求:編寫(xiě)動(dòng)作客戶端實(shí)現(xiàn),可以提交一個(gè)整型數(shù)據(jù)到服務(wù)端,并處理服務(wù)端的連續(xù)反饋以及最終返回結(jié)果。 ? ?

?步驟: ? ? ?

? ? ?1.導(dǎo)包; ? ? ? ?

? ? ?2.初始化 ROS2 客戶端; ? ? ? ?

? ? ?3.定義節(jié)點(diǎn)類(lèi); ? ? ? ? ? ?

? ? ? ?3-1.創(chuàng)建動(dòng)作客戶端; ? ? ? ? ? ?

? ? ? ?3-2.發(fā)送請(qǐng)求; ? ? ? ? ? ?

? ? ? ?3-3.處理目標(biāo)發(fā)送后的反饋; ? ? ? ? ? ?

? ? ? ?3-4.處理連續(xù)反饋; ? ? ? ? ? ?

? ? ? ?3-5.處理最終響應(yīng)。 ? ? ? ?

? ? ?4.調(diào)用spin函數(shù),并傳入節(jié)點(diǎn)對(duì)象; ? ? ? ?

? ? ?5.釋放資源。


"""

# 1.導(dǎo)包;i

mport rclpy

from rclpy.action import ActionClient

from rclpy.node import Node

from base_interfaces_demo.action import Progress


# 3.定義節(jié)點(diǎn)類(lèi);

class ProgressActionClient(Node):


? def __init__(self): ? ?

? ?super().__init__('progress_action_client') ?

? ?# 3-1.創(chuàng)建動(dòng)作客戶端; ?

? ? self._action_client = ActionClient(self, Progress, 'get_sum') ?


? def send_goal(self, num): ? ?

? ? ?# 3-2.發(fā)送請(qǐng)求; ?

? ? goal_msg = Progress.Goal() ? ?

? ? goal_msg.num = num ? ?

? ? self._action_client.wait_for_server() ? ?

? ? self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback) ? ? ? ?

? ? self._send_goal_future.add_done_callback(self.goal_response_callback) ?


? def goal_response_callback(self, future): ? ?

? ? ? # 3-3.處理目標(biāo)發(fā)送后的反饋; ? ?

? ? ? ?goal_handle = future.result() ? ?

? ? ? ?if not goal_handle.accepted: ? ? ? ? ? ?

? ? ? ? ? self.get_logger().info('請(qǐng)求被拒絕') ? ? ? ? ? ?

? ? ? ? ? return ? ? ?

? ? ? self.get_logger().info('請(qǐng)求被接收,開(kāi)始執(zhí)行任務(wù)!')

? ? ? ?

? ? ? ?self._get_result_future = goal_handle.get_result_async() ? ? ? ? ? ? ? ? ?self._get_result_future.add_done_callback(self.get_result_callback) ? ? ?

? ? ?# 3-5.處理最終響應(yīng)。 ?

? ? def get_result_callback(self, future): ? ?

? ? ? ?result = future.result().result ? ?

? ? ? ?self.get_logger().info('最終計(jì)算結(jié)果:sum = %d' % result.sum) ? ? ? ? ? ? ?# 5.釋放資源。 ? ? ?

? ? ? ?rclpy.shutdown() ? ?

? ? ?# 3-4.處理連續(xù)反饋; ? ?

? ? def feedback_callback(self, feedback_msg): ? ? ?

? ? ? ?feedback = (int)(feedback_msg.feedback.progress * 100) ? ? ? ?

? ? ? ?self.get_logger().info('當(dāng)前進(jìn)度: %d%%' % feedback)


def main(args=None): ?


? # 2.初始化 ROS2 客戶端; ?

? rclpy.init(args=args) ?

? # 4.調(diào)用spin函數(shù),并傳入節(jié)點(diǎn)對(duì)象; ?

?

? ?action_client = ProgressActionClient() ?

? ?action_client.send_goal(10) ?

? ?rclpy.spin(action_client) ?


? ?# rclpy.shutdown()


if __name__ == '__main__': ?

main()

3.編輯配置文件

1.package.xml

在創(chuàng)建功能包時(shí),所依賴的功能包已經(jīng)自動(dòng)配置了,配置內(nèi)容如下:

<depend>rclpy</depend>

<depend>base_interfaces_demo</depend>

2.setup.py

entry_points字段的console_scripts中添加如下內(nèi)容:

entry_points={ ?

?'console_scripts': [ ? ?

? ?'demo01_action_server_py = py03_action.demo01_action_server_py:main', ? ? ? ?'demo02_action_client_py = py03_action.demo02_action_client_py:main' ? ?

? ],?

},

4.編譯

終端中進(jìn)入當(dāng)前工作空間,編譯功能包:

colcon build --packages-select py03_action

5.執(zhí)行

當(dāng)前工作空間下,啟動(dòng)兩個(gè)終端,終端1執(zhí)行動(dòng)作服務(wù)端程序,終端2執(zhí)行動(dòng)作客戶端程序。

終端1輸入如下指令:

. install/setup.bash

ros2 run py03_action demo01_action_server_py

終端2輸入如下指令:

. install/setup.bash?

ros2 run py03_action demo02_action_client_py

最終運(yùn)行結(jié)果與案例類(lèi)似。

B站有完整的ros系列教程視頻,可以觀看完整內(nèi)容ros課程ROS2理論與實(shí)踐

更多內(nèi)容將在猛獅知識(shí)星球社區(qū)更新最新課程,后續(xù)將推出更多優(yōu)質(zhì)內(nèi)容——詳情可關(guān)注猛獅集訓(xùn)營(yíng)公眾號(hào)和猛獅集訓(xùn)營(yíng)官方網(wǎng)站。



2.4 動(dòng)作通信的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
疏附县| 万荣县| 凉山| 白朗县| 名山县| 临澧县| 湖北省| 滁州市| 石家庄市| 齐河县| 富宁县| 连平县| 天长市| 开江县| 买车| 德兴市| 尚义县| 开阳县| 祁门县| 沁阳市| 福海县| 房产| 周口市| 巴马| 嘉祥县| 佛教| 镇赉县| 盐亭县| 邢台市| 钟祥市| 类乌齐县| 四平市| 赤水市| 时尚| 富裕县| 金乡县| 云浮市| 绥德县| 博客| 新津县| 布拖县|