0 專欄介紹
本專欄旨在通過對(duì)ROS2的系統(tǒng)學(xué)習(xí),掌握ROS2底層基本分布式原理,并具有機(jī)器人建模和應(yīng)用ROS2進(jìn)行實(shí)際項(xiàng)目的開發(fā)和調(diào)試的工程能力。
??詳情:《ROS2從入門到精通》
1 服務(wù)通信模型
服務(wù)是 ROS 圖中節(jié)點(diǎn)之間的另一種通信方法。服務(wù)基于服務(wù)器-客戶端模型,不同于話題的發(fā)布者-訂閱者模型。話題允許節(jié)點(diǎn)訂閱數(shù)據(jù)流并獲取持續(xù)更新,而服務(wù)只在客戶端特別調(diào)用時(shí)才提供數(shù)據(jù)。二者更詳細(xì)的對(duì)比請(qǐng)參考第5節(jié)
2 服務(wù)模型實(shí)現(xiàn)(C++)
實(shí)驗(yàn)?zāi)繕?biāo):客戶端提交請(qǐng)求給
turtlesim
功能包的/spawn
服務(wù),在界面上生成新的烏龜。
-
服務(wù)器
本實(shí)驗(yàn)中無需編程,為
turtlesim::Spawn
定義的/spwan
服務(wù) -
客戶端
void OnResultCallBack(rclcpp::Client<turtlesim::srv::Spawn>::SharedFuture result) { auto response = result.get(); RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Request service successfully! [turtle id: %s]", response->name.c_str()); } void request() { auto spawn = std::make_shared<turtlesim::srv::Spawn::Request>(); spawn->name = "winter_turtle"; spawn->x = 1.0; spawn->y = 1.0; spawn->theta = 1.57; while (!client_->wait_for_service(std::chrono::seconds(1))) { if (!rclcpp::ok()) { RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting."); return; } RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again..."); } auto result = client_->async_send_request(spawn, std::bind(&ClientNode::OnResultCallBack, this, std::placeholders::_1)); }
服務(wù)通信的效果如下所示:
3 服務(wù)模型實(shí)現(xiàn)(Python)
實(shí)驗(yàn)?zāi)繕?biāo):客戶端提交請(qǐng)求給
turtlesim
功能包的/spawn
服務(wù),在界面上生成新的烏龜。
-
服務(wù)器
本實(shí)驗(yàn)中無需編程,為
turtlesim::Spawn
定義的/spwan
服務(wù) -
客戶端
class ClientNode(Node): def __init__(self, name): super().__init__(name) self.client = self.create_client(Spawn, '/spawn') while not self.client.wait_for_service(timeout_sec=1.0): self.get_logger().info('service not available, waiting again...') self.request = Spawn.Request() def sendRequest(self): self.request.name = "winter_turtle" self.request.x = 1.0 self.request.y = 1.0 self.request.theta = 1.57 self.future = self.client.call_async(self.request)
服務(wù)通信的效果如下所示:
4 自定義服務(wù)
自定義服務(wù)的通用流程如下:
- 功能包下新建
srv
文件夾,在其中添加自定義服務(wù)xxx.srv
,注意請(qǐng)求和響應(yīng)數(shù)據(jù)結(jié)構(gòu)使用---
分割- 功能包
package.xml
中添加編譯依賴與執(zhí)行依賴<buildtool_depend>rosidl_default_generators</buildtool_depend> <exec_depend>rosidl_default_runtime</exec_depend> <member_of_group>rosidl_interface_packages</member_of_group>
- 功能包
CMakeLists.txt
中添加編譯消息相關(guān)依賴find_package(rosidl_default_generators REQUIRED) rosidl_generate_interfaces(${PROJECT_NAME} "xxx.srv" DEPENDENCIES xxx_srvs ) ament_export_dependencies(rosidl_default_runtime)
- 編譯自定義消息,在
install/<pkg_name>/include
中生成由xxx.srv
編譯的C++可識(shí)別的xxx.hpp
頭文件- 引入
xxx.hpp
即可調(diào)用自定義服務(wù)
下面給出一個(gè)實(shí)例
添加如下自定義服務(wù)實(shí)現(xiàn)一個(gè)加法服務(wù),并按上面步驟配置依賴
# client
int32 a
int32 b
---
# server
int32 sum
定義一個(gè)服務(wù)器、一個(gè)客戶端,限于篇幅只貼出部分代碼,完整代碼見文末。
-
服務(wù)器
class ServerNode : public rclcpp::Node { public: ServerNode() : Node("lab_srv_server_own") { server_ = create_service<own_srv_lab::srv::Add>( "/add_service", std::bind(&ServerNode::OnAddSrvCallBack, this, std::placeholders::_1, std::placeholders::_2) ); } private: rclcpp::Service<own_srv_lab::srv::Add>::SharedPtr server_; void OnAddSrvCallBack( const std::shared_ptr<own_srv_lab::srv::Add::Request> request, std::shared_ptr<own_srv_lab::srv::Add::Response> response ) { response->sum = request->a + request->b; RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Incoming request\na: %d" " b: %d", request->a, request->b); RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "sending back response: [%d]", response->sum); } };
-
客戶端
ClientNode() : Node("lab_srv_client_own") { client_ = create_client<own_srv_lab::srv::Add>("/add_service"); } void request(int a, int b) { auto add_srv = std::make_shared<own_srv_lab::srv::Add::Request>(); add_srv->a = a; add_srv->b = b; while (!client_->wait_for_service(std::chrono::seconds(1))) { if (!rclcpp::ok()) { RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting."); return; } RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again..."); } auto result = client_->async_send_request(add_srv, std::bind(&ClientNode::OnResultCallBack, this, std::placeholders::_1)); }
服務(wù)通信效果如下所示:
5 話題、服務(wù)通信的異同
對(duì)比 | 話題 | 服務(wù) |
---|---|---|
通信模式 | 發(fā)布-訂閱 | 請(qǐng)求-響應(yīng) |
同步性 | 異步 | 同步 |
緩沖區(qū) | 有 | 無 |
實(shí)時(shí)性 | 弱 | 強(qiáng) |
節(jié)點(diǎn)關(guān)系 | 多對(duì)多 | 一對(duì)多(1個(gè)server對(duì)應(yīng)一個(gè)服務(wù)) |
通信格式 | .msg |
.srv |
使用場景 | 連續(xù)高頻的數(shù)據(jù)傳輸,例如激光雷達(dá)、里程計(jì)傳輸數(shù)據(jù) | 偶爾調(diào)用的功能,例如圖像識(shí)別 |
完整代碼通過下方博主名片聯(lián)系獲取文章來源:http://www.zghlxwxcb.cn/news/detail-844989.html
?? 更多精彩專欄:文章來源地址http://www.zghlxwxcb.cn/news/detail-844989.html
- 《ROS從入門到精通》
- 《Pytorch深度學(xué)習(xí)實(shí)戰(zhàn)》
- 《機(jī)器學(xué)習(xí)強(qiáng)基計(jì)劃》
- 《運(yùn)動(dòng)規(guī)劃實(shí)戰(zhàn)精講》
- …
到了這里,關(guān)于ROS2從入門到精通1-2:詳解ROS2服務(wù)通信機(jī)制與自定義服務(wù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!