【ROS1】08-ROS通信機制——服務通信

目錄

一、概念

二、何時使用服務

三、話題通信與服務通信的區別

四、案例

4.1 C++實現

4.1.1 服務端

4.1.2 客戶端

4.1.3 測試執行

4.2 Python實現

4.2.1 服務端

4.2.2 客戶端

4.2.3 客戶端優化——動態傳參

4.2.4 客戶端優化——等待服務端啟動后再發起請求


一、概念

服務通信涉及兩個角色:

  • 服務服務器 (Service Server)

    • 提供特定功能或數據的節點。

    • 它會“打廣告”說:“我能提供XX服務!”(例如,“我能計算兩個整數的和”)。

    • 它平時處于待命狀態,一旦接收到請求,就執行相應的任務,并返回一個結果。

  • 服務客戶端 (Service Client)

    • 需要某個特定功能或數據的節點。

    • 它會向服務器發送一個具體的請求(例如,“請幫我計算 3 和 5 的和”)。

    • 發送請求后,它會暫停自己的工作,一直等待,直到收到服務器的響應。

?

二、何時使用服務

當你需要立即得到一個確切的答復觸發一個必須完成的遠程操作時,就應該使用服務。

典型應用場景:

  • 查詢數據: “機器人,你現在的坐標是多少?”

  • 觸發動作: “機械臂,移動到指定位置。” / “相機,拍一張照片。”

  • 執行計算: “路徑規劃器,幫我計算一條從A到B的最優路徑。”

  • 更改狀態: “機器人,切換到自動駕駛模式。”

?

三、話題通信與服務通信的區別

服務通信 (Service)話題通信 (Topic)
通信模型請求/響應發布/訂閱
數據流向雙向單向?
同步性同步 - 客戶端會阻塞等待異步 - 發布后立即返回
連接關系一對一?一對多/多對多
數據流類型離散的、事務性的連續的數據流
主要目的執行遠程調用、獲取確切結果持續廣播狀態、傳感器數據

四、案例

客戶端發送兩個整數,服務端計算它們的和并返回

4.1 C++實現

4.1.1 服務端

進入到工作空間的src目錄下,輸入如下指令來創建一個名為“plumbing_server_client”的功能包

catkin_create_pkg plumbing_server_client roscpp rospy std_msgs

在功能包中創建一個srv目錄

在srv目錄中創建一個.srv文件,這里命名為“AddTwoInts.srv”

“AddTwoInts.srv”內容如下:

int64 a
int64 b
---
int64 sum

打開功能包中的“package.xml”,添加如下兩行內容

<build_depend>message_generation</build_depend><exec_depend>message_runtime</exec_depend>

打開功能包下的“CMakeLists.txt”,添加如下內容:

添加“message_generation”

取消注釋并添加“AddTwoInts.srv”

取消注釋

取消注釋

Ctrl+Shift+B編譯一下

在功能包的src目錄中新建一個.cpp文件,這里命名為“server.cpp”?

在“server.cpp” 中添加如下代碼

#include "ros/ros.h"
#include "plumbing_server_client/AddTwoInts.h"// 服務處理函數。當收到請求時,ROS會調用這個函數。
// 函數的返回值是 bool 類型,如果成功處理返回 true,否則返回 false。
// 參數是請求對象(req)和響應對象(res)的引用。
bool add(plumbing_server_client::AddTwoInts::Request  &req,plumbing_server_client::AddTwoInts::Response &res)
{// 從請求對象中取出數據res.sum = req.a + req.b;// ROS_INFO 用于在終端打印日志信息,類似于C++的coutROS_INFO("請求: x=%ld, y=%ld", (long int)req.a, (long int)req.b);ROS_INFO("發送響應: sum=%ld", (long int)res.sum);return true; // 表示服務成功執行
}int main(int argc, char **argv)
{setlocale(LC_ALL,"");// 1. 初始化ROS節點ros::init(argc, argv, "add_two_ints_server");// 2. 創建節點句柄ros::NodeHandle n;// 3. 創建一個名為 "add_two_ints" 的服務//    它會調用 add 函數來處理請求ros::ServiceServer service = n.advertiseService("add_two_ints", add);ROS_INFO("服務已就緒,等待客戶端請求...");// 4. 進入循環,等待回調函數的觸發ros::spin();return 0;
}

4.1.2 客戶端

在功能包的src目錄下添加一個.cpp文件,這里命名為“client.cpp”

在“client.cpp”中添加如下代碼

#include "ros/ros.h"
#include "plumbing_server_client/AddTwoInts.h"
#include <cstdlib> // 用于 atoll 函數int main(int argc, char **argv)
{setlocale(LC_ALL,"");// 初始化ROS節點ros::init(argc, argv, "add_two_ints_client");// 檢查命令行參數是否正確if (argc != 3){ROS_INFO("用法: add_two_ints_client X Y");return 1;}// 創建節點句柄ros::NodeHandle n;// 創建一個客戶端,連接到名為 "add_two_ints" 的服務// serviceClient 會一直嘗試連接,直到成功ros::ServiceClient client = n.serviceClient<plumbing_server_client::AddTwoInts>("add_two_ints");// 創建一個服務對象 srvplumbing_server_client::AddTwoInts srv;// 將命令行參數轉換為 long long (int64) 并填充到請求中srv.request.a = atoll(argv[1]);srv.request.b = atoll(argv[2]);// 調用服務// client.call() 是一個阻塞操作。它會發送請求并等待,直到收到響應。// 如果服務調用成功,call() 返回 true,響應數據會填充到 srv.response 中。// 如果失敗,call() 返回 false。if (client.call(srv)){ROS_INFO("響應 Sum: %ld", (long int)srv.response.sum);}else{ROS_ERROR("調用服務失敗");return 1;}return 0;
}

打開功能包中“CMakeLists.txt”文件,添加如下內容

編譯一下

4.1.3 測試執行

開啟三個終端,分別輸入如下指令來依次啟動ros核心、啟動服務端、啟動客戶端

roscore  //啟動ros核心rosrun plumbing_server_client server  //啟動服務端rosrun plumbing_server_client client 15 20  //啟動客戶端

可以看到服務端成功計算并返回計算結果。

但是如果我們先開啟客戶端再開啟服務端就會導致客戶端拋出異常:

為了避免這個問題,我們可以給客戶端添加如下一行代碼,這樣就可以客戶端就可以等服務端啟動后再請求

client.waitForExistence();
// 或
ros::service::waitForService("add_two_ints_server");  //add_two_ints_server為服務器節點名稱

可以看到客戶端在服務端未啟動時一直等待?

等服務端啟動后再執行請求

4.2 Python實現

4.2.1 服務端

打開“settings.json”,如果沒有如下配置則需要補充

{"editor.tabSize": 4,"cmake.sourceDirectory": "/home/chaochao/demo02_ws/src/helloworld","files.associations": {"sstream": "cpp"},"python.autoComplete.extraPaths": ["/opt/ros/noetic/lib/python3/dist-packages","/home/chaochao/demo02_ws/devel/lib/python3/dist-packages"]
}

新建一個文件夾“scripts”

添加一個Python文件,這里命名為“server_py.py”

在“server_py.py”添加如下代碼:

#! /usr/bin/env python
# -*- coding: utf-8 -*-import rospy
from plumbing_server_client.srv import AddTwoInts, AddTwoIntsRequest, AddTwoIntsResponse
# from plumbing_server_client.srv import *"""
服務端:解析客戶端請求,產生響應1. 導包2. 初始化 ROS 節點;3. 創建服務端對象;4. 處理邏輯(回調函數)5. spin()
"""# 4. 處理邏輯
def call_doInt(request):num1 = request.anum2 = request.bsum = num1 + num2response = AddTwoIntsResponse()  # 將結果封裝進responseresponse.sum = sumrospy.loginfo("服務器收到:num1=%d, num2=%d, 響應:sum=%d", num1, num2, sum)return responseif __name__ == "__main__":# 2. 初始化 ROS 節點;rospy.init_node("server")# 3. 創建服務端對象;server = rospy.Service("AddTwoInts", AddTwoInts, call_doInt)  # "AddTwoInts":服務的名稱; AddTwoInts:服務的類型; call_doInt:回調函數;# 5. spin()rospy.spin()

cd到“scripts”目錄下,輸入如下指令來給python文件添加可執行權限

chmod +x *.py

打開“CMakeLists.txt”,添加如下內容?

編譯一下,然后輸入如下指令測試

source ./devel/setup.bash
rosrun plumbing_server_client server_py.pysource ./devel/setup.bash
rosservice call AddTwoInts "a: 12 b: 14"

4.2.2 客戶端

在“scripts”目錄下新建一個python文件,這里命名為“client_py.py”

在“client_py.py”中添加如下代碼

#! /usr/bin/env python
# -*- coding: utf-8 -*-import rospy
from plumbing_server_client.srv import AddTwoInts, AddTwoIntsRequest, AddTwoIntsResponse"""
客戶端:組織并提交請求,處理服務端響應。1. 導包;2. 初始化 ROS 節點;3. 創建客戶端對象;4. 組織請求數據,并發送請求;5. 處理響應。
"""if __name__ == "__main__":# 2. 初始化 ROS 節點;rospy.init_node("client")# 3. 創建客戶端對象;client = rospy.ServiceProxy("AddTwoInts", AddTwoInts)# 4. 組織請求數據,并發送請求;response = client.call(12, 24)# 5. 處理響應。rospy.loginfo("響應的數據:%d", response.sum)

給新建的python文件添加可執行權限?

打開“CMakeLists.txt”,添加如下內容

編譯后通過如下命令啟動服務端和客戶端,可以看到客戶端正常接收到了服務端響應的數據

rosrun plumbing_server_client server_py.py  //啟動服務端rosrun plumbing_server_client client_py.py  //啟動客戶端

4.2.3 客戶端優化——動態傳參

如果我們希望客戶端的參數是通過命令動態傳入的,可以對客戶端代碼做如下修改:

#! /usr/bin/env python
# -*- coding: utf-8 -*-import rospy, sys
from plumbing_server_client.srv import AddTwoInts, AddTwoIntsRequest, AddTwoIntsResponse"""
客戶端:組織并提交請求,處理服務端響應。1. 導包;2. 初始化 ROS 節點;3. 創建客戶端對象;4. 組織請求數據,并發送請求;5. 處理響應。
"""if __name__ == "__main__":# 判斷參數個數if len(sys.argv) != 3:rospy.logerr("傳入參數個數有誤...")sys.exit(1)# 2. 初始化 ROS 節點;rospy.init_node("client")# 3. 創建客戶端對象;client = rospy.ServiceProxy("AddTwoInts", AddTwoInts)# 4. 組織請求數據,并發送請求;num1 = int(sys.argv[1])num2 = int(sys.argv[2])response = client.call(num1, num2)# 5. 處理響應。rospy.loginfo("響應的數據:%d", response.sum)

此時執行效果如下

4.2.4 客戶端優化——等待服務端啟動后再發起請求

如果在服務端未啟動的情況下啟動客戶端,會拋出異常

為了解決這個問題,我們可以添加如下一行代碼,這樣客戶端就可以等待服務端啟動后再發起請求

client.wait_for_service()# 或rospy.wait_for_service("AddTwoInts")

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

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

相關文章

45.sentinel自定義異常

上文提到Blocked by Sentinel(flow limits) 限流異常,這樣返給用戶就不太友好,所以需要自定義異常。 默認情況下,發生限流、降級、授權攔截時,都會拋出異常到調用方。如果要自定義異常時的返回結果,需要實現BlockExceptionHandler接口: BlockException有很多子類: pac…

f4硬件配置spi

f4型號是stm32f407zgt6用spi來進行MOSI&#xff0c;主機發送從機接收時鐘頻率設置為1MHzMOSI為PC3&#xff0c;SCK為PB10&#xff0c;CS設置為output->PB12時鐘配置如下&#xff1a;波特率計算公式為&#xff1a;128M/(4*Prescaler) 要讓波特率為1M&#xff0c;10…

Redis的持久化-RDB

1.持久化一提到持久化&#xff0c;我們就會第一時間聯想到M有SQL的事務&#xff0c;MySQL事務有四個比較核心的特征&#xff1a;原子性&#xff08;把多個操作打包成一個整體&#xff09;&#xff0c;一致性&#xff08;事務執行之前和之后&#xff0c;數據都不能離譜&#xff…

前端內存泄漏

個人簡介 &#x1f440;個人主頁&#xff1a; 前端雜貨鋪 &#x1f64b;?♂?學習方向&#xff1a; 主攻前端方向&#xff0c;正逐漸往全干發展 &#x1f4c3;個人狀態&#xff1a; 研發工程師&#xff0c;現效力于中國工業軟件事業 &#x1f680;人生格言&#xff1a; 積跬步…

部署zabbox企業級分布式監控

目錄 一、監控系統的基礎認知 2.1 監控的定義與核心價值 2.2 監控的五大類型與五層邏輯架構 &#xff08;1&#xff09;五大監控類型 &#xff08;2&#xff09;五層邏輯架構 2.3 主流開源監控產品對比 二、Zabbix 系統深度解析 3.1 Zabbix 的定位與發展歷程 3.2 Zabb…

時空數據可視化新范式:基于Three.js的生產全流程時間軸回溯技術解析

內容摘要在現代工業生產中&#xff0c;如何高效地管理和分析生產全流程數據是一個關鍵問題。傳統的數據可視化方法往往只能展示靜態的數據快照&#xff0c;難以捕捉和回溯生產過程中的動態變化。然而&#xff0c;基于 Three.js 的時間軸回溯技術為這一難題提供了一種全新的解決…

寶塔面板Nginx報錯: IP+端口可以直接從訪問,反向代理之后就504了 Gateway Time-out

原因表示代理服務器在等待上游服務器&#xff08;即后端服務&#xff09;響應時超時 &#xff1a;<html><head><title>504 Gateway Time-out</title> </head><body><center><h1>504 Gateway Time-out</h1></center&g…

【ComfyUI學習筆記01】下載安裝 | 運行第一個工作流 | 學習思路

【ComfyUI學習筆記01】下載安裝 | 運行第一個工作流 | 學習思路前言下載安裝ComfyUI的下載和安裝ComfyUI Manager 的下載和安裝運行第一個工作流初識節點 (Nodes) 工作流案例1 Image Generation繪制流程圖&#xff0c;確定關鍵節點放置關鍵節點&#xff0c;確定連接順序補充中間…

numpy庫的基礎知識

一.numpy是什么 &#xff1f;Numpy 是 Python 中專門用于高性能數值計算的庫&#xff0c;其核心是一個功能強大的 n 維數組對象&#xff08;ndarray&#xff09;&#xff0c;可以用來存儲和操作大規模的數字矩陣或張量數據。numpy庫的作用&#xff1a;核心功能&#xff1a;實現…

在UniApp中防止頁面上下拖動的方法

1、pages.json中在某個頁面設置禁用彈性滾動的頁面 {"path": "pages/yourPage/yourPage","style": {"app-plus": {"bounce": "none"}} } 2、 pages.json中在所有頁面設置禁用彈性滾動的頁面 {"globalStyl…

LinkedList的模擬實現(雙向鏈表Java)

一&#xff1a;結構LinkedList的底層是雙向鏈表結構(鏈表后面介紹)&#xff0c;由于鏈表沒有將元素存儲在連續的空間中&#xff0c;元素存儲在單獨的節點中&#xff0c;然后通過引用將節點連接起來了&#xff0c;因此在在任意位置插入或者刪除元素時&#xff0c;不需要搬移元素…

Shopify 知識點

&#x1f4dc; 一、Liquid模板語言&#xff08;核心基礎&#xff09;語法結構 ? 輸出變量&#xff1a;{{ product.title }} 動態顯示商品標題。 ? 邏輯控制&#xff1a;{% if product.available %}…{% endif %} 條件渲染。 ? 循環遍歷&#xff1a;{% for item in collectio…

Web LLM 安全剖析:以間接提示注入為核心的攻擊案例與防御體系

文章目錄1 間接提示注入2 訓練數據中毒為什么會出現這種漏洞&#xff1f;3 泄露敏感訓練數據攻擊者如何通過提示注入獲取敏感數據&#xff1f;為什么會出現這種泄露&#xff1f;4 漏洞案例間接提示注入利用 LLM 中的不安全輸出處理5 防御 LLM 攻擊把LLM能訪問的API當成“公開接…

ElasticSearch:不停機更新索引類型(未驗證)

文章目錄**一、前期準備****1. 集群健康檢查****2. 備份數據****3. 監控系統準備****二、創建新索引并配置****1. 設計新索引映射****2. 創建讀寫別名****三、全量數據遷移****1. 執行初始 Reindex****2. 監控 Reindex 進度****四、增量數據同步****1. 方案選擇****五、雙寫切換…

python學智能算法(二十七)|SVM-拉格朗日函數求解上

【1】引言 前序學習進程中&#xff0c;我們已經掌握了支持向量機算法中&#xff0c;為尋找最佳分割超平面&#xff0c;如何用向量表達超平面方程&#xff0c;如何為超平面方程建立拉格朗日函數。 本篇文章的學習目標是&#xff1a;求解SVM拉格朗日函數。 【2】求解方法 【2.…

mac安裝node的步驟

適用于macOS 10.15及以上版本。 前提條件 macOS版本&#xff1a;確保系統為macOS 10.15&#xff08;Catalina&#xff09;或更高版本。可在“蘋果菜單 > 關于本機”查看。管理員權限&#xff1a;部分安裝可能需要管理員權限。網絡連接&#xff1a;需要聯網下載安裝包或工具…

【LeetCode數據結構】棧的應用——有效的括號問題詳解

&#x1f525;個人主頁&#xff1a;艾莉絲努力練劍 ?專欄傳送門&#xff1a;《C語言》、《數據結構與算法》、C語言刷題12天IO強訓、LeetCode代碼強化刷題 &#x1f349;學習方向&#xff1a;C/C方向 ??人生格言&#xff1a;為天地立心&#xff0c;為生民立命&#xff0c;為…

多尺度卷積模型:Inception塊

在GoogLeNet中&#xff0c;基本的卷積塊被稱為Inception塊&#xff08;Inception block&#xff09;。 使用窗口大小為11&#xff0c;33&#xff0c;551\times1&#xff0c;3\times3&#xff0c;5\times511&#xff0c;33&#xff0c;55的卷積層&#xff0c;從不同空間大小中提…

Android 默認圖庫播放視頻沒有自動循環功能,如何添加

Android 默認圖庫播放視頻沒有自動循環功能, 如何添加 按如下方式添加 開發云 - 一站式云服務平臺 .../apps/Gallery2/res/values-zh-rCN/strings.xml | 3 ++ packages/apps/Gallery2/res/values/strings.xml | 3 ++ .../com/android/gallery3d/app/MovieActivity…

7月21日總結

命令執行 RCE RCE&#xff08;remote code execute&#xff09;&#xff1a;遠程命令執行或者代碼執行&#xff0c;我們平時說的rce&#xff0c;比如thinkPHP的 rce漏洞&#xff0c;即算代碼注入漏洞&#xff0c;也算rce漏洞&#xff0c;因為滲透的最終情況可以實現執行命令或…