前言
學完了話題通信其實操作流程基本都已經很熟悉了,因此服務通訊的學習就會流暢許多。
服務通信也是ROS中一種極其常用的通信模式,服務通信是基于請求響應模式的,是一種應答機制。也即: 一個節點A向另一個節點B發送請求,B接收處理請求并產生響應結果返回給A。比如如下場景:機器人巡邏過程中,控制系統分析傳感器數據發現可疑物體或人... 此時需要拍攝照片并留存。在上述場景中,就使用到了服務通信。類似于計算機網絡的C/S模型一個節點需要向相機節點發送拍照請求,相機節點處理請求,并返回處理結果
服務通信更適用于對時時性(遇到需要拍照的地方就執行)有要求、具有一定邏輯處理的應用場景。用于偶然的、對時時性有要求、有一定邏輯處理需求的數據傳輸場景。
服務編程通信:請求響應模式
1.服務通信的理論模型
1.演員列表
Ⅰ.管理者:roscore核心(114平臺)
Ⅱ.服務端:(維修公司)
Ⅲ.客戶端 :(俺)
2.流程
master根據話題實現client和server之間的連接的過程,master起到媒介的應用。
Ⅰ.維修平臺(server)向中介平臺(master)注冊自己的信息(話題--疏通下水道+公司聯系方式--RPC地址)。
Ⅱ.我(client)向中介平臺(master)注冊自己所需要的服務(話題--疏通下水道)。
Ⅲ.中介公司(master)進行話題匹配,并將服務端的聯系方式(RPC地址)相應給我(客戶端)。
Ⅳ.我打電話給保潔公司。
Ⅴ.保潔公司到我家修馬桶(TCP)。
3.注意
Ⅰ.和話題通信相比較,應該保證服務端是先啟動的,客戶端是后請求的。
Ⅱ.服務端和客戶端都可以有多個。
Ⅲ.流程被封裝,只需要調用即可。
Ⅳ.也用到了話題,要保證話題相同。
2.服務通信自定義服務消息(srv)
1.需求
服務通信中,客戶端提交兩個整數至服務端,服務端求和并響應結果到客戶端,請創建服務器與客戶端通信的數據載體。
2.流程
srv 文件內的可用數據類型與 msg 文件一致,且定義 srv 實現流程與自定義 msg 實現流程類似:
按照固定格式創建srv文件——>編輯配置文件——>編譯生成中間文件
3.具體實現
為了熟悉前邊的操作這里建議從創建工作空間開始操作,具體細節就不展示了,如果從頭認真過一遍都能理解下面的操作。
創建一個工作空間、對其初始化、對其進行編譯、源碼空間中創建一個功能包、創建自定義的服務消息
1.消息的內容:
在功能包plumbing_server_client下創建文件夾srv并創建文件addints.srv,填入如下內容;
int32 num1
int32 num2
---
int32 sum
服務消息分為兩部分:請求部分(2個整形數字)和相應部分(1個整形數字)。三個杠是請求與響應的交界線?
2.編譯配置文件package.xml
<build_depend>message_generation</build_depend><exec_depend>message_runtime</exec_depend>
3.編譯配置文件CmakeLists.txt
find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsmessage_generation
)
## Generate services in the 'srv' folderadd_service_files(FILESaddints.srv)
## Generate added messages and services with any dependencies listed heregenerate_messages(DEPENDENCIESstd_msgs)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES plumbing_server_clientCATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
4.編譯catkin_make
5.生成的文件
3.實現服務通信(c++)
在模型實現中,ROS master 不需要實現,而連接的建立也已經被封裝了,需要關注的關鍵點有三個:服務端、客戶端、數據。
流程:編寫服務端實現;編寫客戶端實現;編輯配置文件;編譯并執行
1.vscode的配置
pwd獲取路徑添加json文件中。
我自己的路徑:/home/lvl/demo01_ws/devel/include/plumbing_server_client
2.創建服務端
1.創建一個實例
功能包源碼空間下創建一個實例(demo01_server.cpp):
#include "ros/ros.h"
#include"plumbing_server_client/addints.h"
/*
服務端實現:解析客戶端提交的數據,并運算再產生響應
1.包含相關頭文件
2.初始化ros節點
3.創建節點句柄
4.創建服務對象
5.處理請求并產生響應
6.spin()
*/bool doNums(plumbing_server_client::addints::Request & request,plumbing_server_client::addints::Response &response) //返回bool值,表明成功或者失敗
{//1.處理請求int num1 = request.num1;int num2 = request.num2;ROS_INFO("收到的請求數據為:num1=%d,num2=%d",num1,num2);//2.組織響應int sum = num1+num2;response.sum = sum;ROS_INFO("求和結果為%d",sum);return true;
}int main(int argc, char *argv[])
{setlocale(LC_ALL,"");ros::init(argc,argv,"heishui"); //節點名稱唯一ros::NodeHandle nh;ros::ServiceServer server = nh.advertiseService("addInts",doNums); //話題名稱、回調函數ros::spin();return 0;
}
2.配置CmakeLists.txt文件
3.編譯catkin_make
4.運行可執行文件
5.測試是否運行成功(新操作)
rosservice call 話題 空格 Tab補齊
3.創建一個客戶端
1.創建一個實例
功能包源碼空間下創建一個實例(demo01_client.cpp):
#include "ros/ros.h"
#include "plumbing_server_client/addints.h"
/*
客戶端:提交兩個數據,處理響應結果
1.包含相關頭文件
2.初始化ros節點
3.創建節點句柄
4.創建客戶端對象
5.提交請求并產生響應
*/int main(int argc, char *argv[])
{setlocale(LC_ALL,"");ros::init(argc,argv,"daBao");ros::NodeHandle nh;ros::ServiceClient client = nh.serviceClient<plumbing_server_client::addints>("addInts"); //話題//5-1組織請求plumbing_server_client::addints ai;ai.request.num1 = 100;ai.request.num2 = 200;//5-2處理響應bool flag = client.call(ai); //客戶端帶著ai對象訪問服務器if(flag){ROS_INFO("響應成功");//獲取sumROS_INFO("響應結果 = %d",ai.response.sum); //傳進去是引用變量}else{ROS_INFO("處理失敗.........");}return 0;
}
2.配置CmakeLists.txt文件
3.編譯catkin_make
4.運行可執行文件
優化
結束語
以上就是我學習到的內容,如果對您有幫助請多多支持我,如果哪里有問題歡迎大家在評論區積極討論,我看到會及時回復。