ROS基础(二):ros通讯之服务(service)机制
上一章內(nèi)容鏈接:
ROS基礎(chǔ)(一):ROS通訊之話題(topic)通訊
目錄
- 一、概念
- 二、實例
- 1. 小烏龜例程中的service
- 2. 自定義service
- 3. 創(chuàng)建服務(wù)器節(jié)點與客戶端節(jié)點(c++)
- server節(jié)點編寫
- client節(jié)點編寫
- 運行結(jié)果
- 4. 創(chuàng)建服務(wù)器節(jié)點與客戶端節(jié)點(python)
- server節(jié)點編寫
- client節(jié)點編寫
- 運行結(jié)果
- 三、總結(jié)
一、概念
service服務(wù)通訊機制是一種雙向同步數(shù)據(jù)傳輸模式。基于客戶端/服務(wù)器模型,兩部分通信數(shù)據(jù)類型:一個用于請求,一個用于應(yīng)答,類似web服務(wù)器。
ROS中只允許一個節(jié)點提供指定命名的服務(wù)。
與topic通訊機制的區(qū)別:
| 同步性 | 異步 | 同步 |
| 通信模型 | 發(fā)布+訂閱 | 客戶端+服務(wù)器端 |
| 反饋機制 | 無 | 有 |
| 緩沖區(qū) | 有 | 無 |
| 節(jié)點關(guān)系 | 多對多 | 一(server)對多 |
| 傳輸數(shù)據(jù)格式 | *.msg | *.srv |
| 適合場景 | 數(shù)據(jù)傳輸 | 邏輯處理 |
二、實例
1. 小烏龜例程中的service
首先啟動第一個小烏龜:
rosrun turtlesim turtlesim_node然后查看能夠調(diào)用的所有service:
調(diào)用其中名為/spawn的服務(wù):
如上圖紅框部分所示,服務(wù)器返回指定生成的烏龜名字。同時,在小烏龜仿真中在指定位置出現(xiàn)第二只名為turtle7的小烏龜,如下圖所示。這烏龜可以的,還在聽音樂。
最后,我們查看該service的具體數(shù)據(jù)格式:
與我們的預(yù)期一致,—上方是client請求發(fā)出的內(nèi)容,其中包括指定新生成烏龜?shù)奈恢谩⒊颉⒚?#xff0c;—下方是server返回的內(nèi)容,string格式的烏龜名字,說明創(chuàng)建成功。
2. 自定義service
與topic話題中需要定義的message文件相似,當我們想要自定義某種服務(wù)時,需要提供對應(yīng)的srv文件來對兩個交互節(jié)點中具體傳輸?shù)臄?shù)據(jù)格式進行約束。
這里我們創(chuàng)建一個乘法運算案例,客戶端提供兩個整數(shù)a、b,服務(wù)器端計算完成后返回乘法結(jié)果到客戶端。
將該srv文件命名為multinum.srv,該文件中的內(nèi)容如下:
將該文件放在名為srv的文件夾下,將文件夾放在功能包目錄下。最終的功能包目錄如下所示:
與定義message一樣,我們同樣要修改對應(yīng)的package.xml文件和CmakeLists.txt文件的對應(yīng)部分:
package.xml文件:
<build_depend>message_generation</build_depend><exec_depend>message_runtime</exec_depend>CmakeLists.txt文件:
第一塊:修改find_package部分,確保編譯時找到對應(yīng)文件
find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsmessage_generation )第二塊:設(shè)置srv文件
add_service_files(FILESmultinum.srv)generate_messages(DEPENDENCIESstd_msgs)第三塊:catkin依賴部分
如果我們編寫的ros程序不打算給別人使用,這塊就無所謂。
catkin_package( ...CATKIN_DEPENDS roscpp rospy std_msgs message_runtime ... )最后,在工作空間編譯,通過相關(guān)命令測試是否已經(jīng)安裝成功:
如上圖所示,我們的service服務(wù)查詢得到,沒問題。
3. 創(chuàng)建服務(wù)器節(jié)點與客戶端節(jié)點(c++)
我們利用第二小節(jié)中自定義的service格式,來設(shè)計兩個node進行service通訊。主要功能是client隨機生成兩個數(shù)字傳遞給service,然后service計算完成之后,將結(jié)果回傳給client。具體的代碼如下所示
server節(jié)點編寫
#include <ros/ros.h> #include <learn_service/multinum.h>bool multi_callback(learn_service::multinum::Request &req, learn_service::multinum::Response &res){res.c = req.a * req.b;ROS_INFO("computing result is %f", res.c);return true; }int main(int argc, char **argv){ros::init(argc, argv, "multi_server");ros::NodeHandle nh;ros::ServiceServer server = nh.advertiseService("multi_two_num",multi_callback);ROS_INFO("waiting two numbers...");ros::spin();return 0; }client節(jié)點編寫
#include <ros/ros.h> #include <learn_service/multinum.h> #include<cstdlib> #include <time.h> int main(int argc, char **argv){srand(int(time(0)));double a = rand()/(double(RAND_MAX)/100);double b = rand()/(double(RAND_MAX)/100);ros::init(argc, argv, "multi_client");ros::NodeHandle nh;ros::ServiceClient client = nh.serviceClient<learn_service::multinum>("multi_two_num");learn_service::multinum srv;srv.request.a = a;srv.request.b = b;if (client.call(srv)){ROS_INFO("%f * %f = %f", a, b, srv.response.c);}else{ROS_ERROR("Failed to call service");}return 0; }運行結(jié)果
首先我們將服務(wù)器節(jié)點開啟,然后需要計算的時候調(diào)用client節(jié)點,服務(wù)器計算好結(jié)果之后回傳給client。具體效果如下所示:
4. 創(chuàng)建服務(wù)器節(jié)點與客戶端節(jié)點(python)
同樣的東西,我們用python再實現(xiàn)一次。
server節(jié)點編寫
#!/usr/bin/env python # coding:utf-8import rospy from learn_service.srv import *def callback_func(req):answer = req.a*req.brospy.loginfo("result is %f", answer)return multinumResponse(answer)def server():rospy.init_node("python_server")s = rospy.Service("multi_2num",multinum,callback_func)rospy.loginfo("Waiting 2 numbers...")rospy.spin()if __name__=="__main__":server()重點:
client節(jié)點編寫
#!/usr/bin/env python # coding:utf-8import rospy from learn_service.srv import * import randomdef client():rospy.init_node("python_client")rospy.wait_for_service("multi_2num")try:c = rospy.ServiceProxy("multi_2num",multinum)a = random.random() * 100b = random.random() * 100response = c.call(a,b)rospy.loginfo("%f * %f = %f", a, b, response.c)except rospy.ServiceException, e:rospy.logerr("service call failed: %s", e)if __name__=="__main__":client()重點:
運行結(jié)果
如下所示,跟預(yù)期一致,沒有問題。
三、總結(jié)
到此,我們用兩章的內(nèi)容,基本涵蓋ros通訊中的兩大最常用的方式。ros還有一種action通訊方式,平時基本用不到。所以接下來教程也不會涉及到這部分內(nèi)容。
下一章,我們來一起探索ros中的tf坐標變換。
總結(jié)
以上是生活随笔為你收集整理的ROS基础(二):ros通讯之服务(service)机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机应知应会培训班,必知必会应知应会学
- 下一篇: 简单的音乐播放器(上一曲,下一曲,暂停/