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

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

2.3 服務(wù)通信

2023-09-19 14:19 作者:猛獅集訓營  | 我要投稿

場景

服務(wù)通信也是ROS中一種極其常用的通信模式,服務(wù)通信是基于請求響應(yīng)模式的,是一種應(yīng)答機制。也即:一個節(jié)點A向另一個節(jié)點B發(fā)送請求,B接收處理請求并產(chǎn)生響應(yīng)結(jié)果返回給A。比如如下場景:

機器人巡邏過程中,控制系統(tǒng)分析傳感器數(shù)據(jù)發(fā)現(xiàn)可疑物體或人... 此時需要拍攝照片并留存。

在上述場景中,就使用到了服務(wù)通信。

  • 數(shù)據(jù)分析節(jié)點A需要向相機相關(guān)節(jié)點B發(fā)送圖片存儲請求,節(jié)點B處理請求,并返回處理結(jié)果。

與上述應(yīng)用類似的,服務(wù)通信更適用于對實時性有要求、具有一定邏輯處理的應(yīng)用場景。

概念

服務(wù)通信是以請求響應(yīng)的方式實現(xiàn)不同節(jié)點之間數(shù)據(jù)傳輸?shù)耐ㄐ拍J?。發(fā)送請求數(shù)據(jù)的對象稱為客戶端,接收請求并發(fā)送響應(yīng)的對象稱之為服務(wù)端,同話題通信一樣,客戶端和服務(wù)端也通過話題相關(guān)聯(lián),不同的是服務(wù)通信的數(shù)據(jù)傳輸是雙向交互式的。


服務(wù)通信中,服務(wù)端與客戶端是一對多的關(guān)系,也即,同一服務(wù)話題下,存在多個客戶端,每個客戶端都可以向服務(wù)端發(fā)送請求。


作用

用于偶然的、對實時性有要求、有一定邏輯處理需求的數(shù)據(jù)傳輸場景。



2.3.1 案例以及案例分析

1.案例需求

需求:編寫服務(wù)通信,客戶端可以提交兩個整數(shù)到服務(wù)端,服務(wù)端接收請求并解析兩個整數(shù)求和,然后將結(jié)果響應(yīng)回客戶端。


2.案例分析

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

  1. 客戶端;

  2. 服務(wù)端;

  3. 消息載體。

3.流程簡介

案例實現(xiàn)前需要先自定義服務(wù)接口,接口準備完畢后,服務(wù)實現(xiàn)主要步驟如下:

  1. 編寫服務(wù)端實現(xiàn);

  2. 編寫客戶端實現(xiàn);

  3. 編輯配置文件;

  4. 編譯;

  5. 執(zhí)行。

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

4.準備工作

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

ros2 pkg create cpp02_service --build-type ament_cmake --dependencies rclcpp base_interfaces_demo?

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


2.3.2 服務(wù)通信接口消息

定義服務(wù)接口消息與定義話題接口消息流程類似,主要步驟如下:

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

  2. 編輯配置文件;

  3. 編譯;

  4. 測試。

接下來,我們可以參考案例編寫一個srv文件,該文件中包含請求數(shù)據(jù)(兩個整型字段)與響應(yīng)數(shù)據(jù)(一個整型字段)。

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

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

int32 num1?

int32 num2

---?

int32 sum

2.編輯配置文件

1.package.xml 文件

srv文件與msg文件的包依賴一致,如果你是新建的功能包添加srv文件,那么直接參考定義msg文件時package.xml 配置即可。由于我們使用的是base_interfaces_demo該包已經(jīng)為msg文件配置過了依賴包,所以package.xml不需要做修改。

2.CMakeLists.txt 文件

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

find_package(rosidl_default_generators REQUIRED)


rosidl_generate_interfaces(${PROJECT_NAME}?

?"srv/AddInts.srv"

)

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

rosidl_generate_interfaces(${PROJECT_NAME} ?

"msg/Student.msg" ?

"srv/AddInts.srv"?

)

3.編譯

終端中進入當前工作空間,編譯功能包:

colcon build --packages-select base_interfaces_demo

4.測試

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

. install/setup.bash?

ros2 interface show base_interfaces_demo/srv/AddInts

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


2.3.3 服務(wù)通信(C++)

1.服務(wù)端實現(xiàn)

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

/* ? ?

? 需求:編寫服務(wù)端,接收客戶端發(fā)送請求,提取其中兩個整型數(shù)據(jù),相加后將結(jié)果響應(yīng)回客戶端。 ?

? 步驟: ? ?

? ? ? 1.包含頭文件; ? ?

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

? ? ? 3.定義節(jié)點類; ? ? ?

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

? ? ? ? 3-2.處理請求數(shù)據(jù)并響應(yīng)結(jié)果。

? ? ? ? 3-3.組織請求數(shù)據(jù)并發(fā)送;? ?

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

? ? ? 5.釋放資源。


*/

// 1.包含頭文件

#include "rclcpp/rclcpp.hpp"

#include "base_interfaces_demo/srv/add_ints.hpp"


using base_interfaces_demo::srv::AddInts;

using std::placeholders::_1;

using std::placeholders::_2;


// 3.定義節(jié)點類;

class MinimalService: public rclcpp::Node{?

?public: ?

?? MinimalService():Node("minimal_service"){ ? ??

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

?? server = this->create_service<AddInts("add_ints",std::bind(&MinimalService::add, this, _1, _2)); ? ?RCLCPP_INFO(this->get_logger(),"add_ints 服務(wù)端啟動完畢,等待請求提交..."); ? ?} ?

?private: ? ?

? ?rclcpp::Service<AddInts>::SharedPtr server; ? ?

? ?// 3-2.處理請求數(shù)據(jù)并響應(yīng)結(jié)果。 ??

??void add(const AddInts::Request::SharedPtr req,const AddInts::Response::SharedPtr res){ ? ? ?

? ?res->sum = req->num1 + req->num2; ? ? ?

? ?RCLCPP_INFO(this->get_logger(),"請求數(shù)據(jù):(%d,%d),響應(yīng)結(jié)果:%d", req->num1, req->num2, res->sum); ? ?

? ?}?

};


int main(int argc, char const *argv[])

{ ?

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

?? rclcpp::init(argc,argv); ?

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

??auto server = std::make_shared<MinimalService>();?

? ?rclcpp::spin(server); ?

? // 5.釋放資源。 ?

? rclcpp::shutdown(); ?

? return 0;?

}

2.客戶端實現(xiàn)

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


3.編輯配置文件

1.packages.xml

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

<depend>rclcpp</depend> <depend>base_interfaces_demo</depend>

2.CMakeLists.txt

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

find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(base_interfaces_demo REQUIRED) add_executable(demo01_server src/demo01_server.cpp) ament_target_dependencies( ?demo01_server ?"rclcpp" ?"base_interfaces_demo" ) add_executable(demo02_client src/demo02_client.cpp) ament_target_dependencies( ?demo02_client ?"rclcpp" ?"base_interfaces_demo" ) install(TARGETS ?demo01_server ?demo02_client ?DESTINATION lib/${PROJECT_NAME})

4.編譯

終端中進入當前工作空間,編譯功能包:

colcon build --packages-select cpp02_service

5.執(zhí)行

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

終端1輸入如下指令:

. install/setup.bash?

ros2 run cpp02_service demo01_server

終端2輸入如下指令:

. install/setup.bash?

ros2 run cpp02_service demo02_client 100 200

最終運行結(jié)果與案例類似。


2.3.4 服務(wù)通信(Python)

1.服務(wù)端實現(xiàn)

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

""" ? ? ?

? ?需求:編寫服務(wù)端,接收客戶端發(fā)送請求,提取其中兩個整型數(shù)據(jù),相加后將結(jié)果響應(yīng)回客戶端。 ? ?

? ?步驟: ? ? ? ?

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

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

? ? ? ?3.定義節(jié)點類; ? ? ? ? ? ?

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

? ? ? ? ?3-2.處理請求數(shù)據(jù)并響應(yīng)結(jié)果。 ? ? ? ?

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

? ? ? ? 5.釋放資源。?

"""


# 1.導(dǎo)包;

import rclpy

from rclpy.node import Node

from base_interfaces_demo.srv import AddInts

# 3.定義節(jié)點類;

class MinimalService(Node): ??


? ?def __init__(self): ? ?

? ? ? super().__init__('minimal_service_py') ? ? ? ?

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

? ? ?self.srv = self.create_service(AddInts, 'add_ints', self.add_two_ints_callback) ? ? ? ?

? ? ?self.get_logger().info("服務(wù)端啟動!") ? ?


? ? ?# 3-2.處理請求數(shù)據(jù)并響應(yīng)結(jié)果。 ? ?

? ? ?def add_two_ints_callback(self, request, response):? ? ? ? ? ? ?

? ? ?response.sum = request.num1 + request.num2? ? ? ? ? ?

? ? ?self.get_logger().info('請求數(shù)據(jù):(%d,%d),響應(yīng)結(jié)果:%d' % (request.num1, request.num2, response.sum)) ? ? ? ?

? ? ?return response

def main(): ? ?

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

? ? ? rclpy.init() ? ?

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

? ? ? minimal_service = MinimalService() ? ?

? ? ? rclpy.spin(minimal_service) ? ?

? ? ? # 5.釋放資源。 ? ?

? ? ? rclpy.shutdown()


if __name__ == '__main__': ? ?

? main()

2.客戶端實現(xiàn)

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

3.編輯配置文件

1.package.xml

在創(chuàng)建功能包時,所依賴的功能包已經(jī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_server_py = py02_service.'demo01_server_py:main',? ? ? ? ??

? ? ? 'demo02_client_py = py02_service.demo02_client_py:main' ? ?

? ? ],?

},

4.編譯

終端中進入當前工作空間,編譯功能包:

colcon build --packages-select py02_service

5.執(zhí)行

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

終端1輸入如下指令:

. install/setup.bash?

ros2 run py02_service demo01_server_py

終端2輸入如下指令:

. install/setup.bash?

ros2 run py02_service demo02_client_py 100 200

最終運行結(jié)果與案例類似。

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

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

2.3 服務(wù)通信的評論 (共 條)

分享到微博請遵守國家法律
玉树县| 莒南县| 贡山| 琼海市| 拉萨市| 武宁县| 酉阳| 凌源市| 济宁市| 三亚市| 甘南县| 进贤县| 永济市| 台北县| 尉犁县| 广宗县| 鸡泽县| 色达县| 三原县| 汽车| 聂拉木县| 乌鲁木齐县| 永善县| 霍州市| 金寨县| 开封县| 烟台市| 外汇| 施甸县| 宽甸| 六枝特区| 绿春县| 庄浪县| 新龙县| 珠海市| 习水县| 绥阳县| 宜都市| 普定县| 大洼县| 乌鲁木齐市|