# 7.3 Service in rospy
本節用python來寫一個節點間,利用Service通信的demo,與5.4類似,創建一個節點,發布模擬的gps信息,另一個接收和計算距離原點的距離。
## 7.3.1 srv文件
在5.4節,我們已經說過要建立一個名為`Greeting.srv`的服務文件,內容如下:
```
string name #短橫線上邊部分是服務請求的數據
int32 age
--- #短橫線下面是服務回傳的內容
string feedback
```
然后修改`CMakeLists.txt`文件。ROS的catkin編譯系統會將你自定義的msg、srv(甚至還有action)文件自動編譯構建,生成對應的C++、Python、LISP等語言下可用的庫或模塊。許多初學者錯誤地以為,只要建立了一個msg或srv文件,就可以直接在程序中使用,這是不對的,必須在`CMakeLists.txt`中添加關于消息創建、指定消息/服務文件那幾個宏命令。
## 7.3.2 創建提供服務節點(server)
見`service_demo/scripts/server_demo.py`:
```python
#!/usr/bin/env python
#coding=utf-8
import rospy
from service_demo.srv import *
def server_srv():
# 初始化節點,命名為 "greetings_server"
rospy.init_node("greetings_server")
# 定義service的server端,service名稱為"greetings", service類型為Greeting
# 收到的request請求信息將作為參數傳遞給handle_function進行處理
s = rospy.Service("greetings", Greeting, handle_function)
rospy.loginfo("Ready to handle the request:")
# 阻塞程序結束
rospy.spin()
def handle_function(req):
# 注意我們是如何調用request請求內容的,是將其認為是一個對象的屬性,在我們定義
# 的Service_demo類型的service中,request部分的內容包含兩個變量,一個是字符串類型的name,另外一個是整數類型的age
rospy.loginfo( 'Request from %s with age %d', req.name, req.age)
# 返回一個Service_demo.Response實例化對象,其實就是返回一個response的對象,其包含的內容為我們在Service_demo.srv中定義的
# response部分的內容,我們定義了一個string類型的變量feedback,因此,此處實例化時傳入字符串即可
return GreetingResponse("Hi %s. I' server!"%req.name)
# 如果單獨運行此文件,則將上面定義的server_srv作為主函數運行
if __name__=="__main__":
server_srv()
```
以上代碼中可以看出Python和C++在ROS服務通信時,server端的處理函數有區別:
C++的handle_function()傳入的參數是整個srv對象的request和response兩部分,返回值是bool型,顯示這次服務是否成功的處理,也就是:
```cpp
bool handle_function(service_demo::Greeting::Request &req, service_demo::Greeting::Response &res){
...
return true;
}
```
而Python的handle_function()傳入的只有request,返回值是response,即:
```pyhon
def handle_function(req):
...
return GreetingResponse("Hi %s. I' server!"%req.name)
```
這也是ROS在兩種語言編程時的差異之一。相比來說Python的這種思維方式更加簡單,符合我們的思維習慣。
### 7.3.3 創建服務請求節點(client)
`service_demo/srv/client.cpp`內容如下:
```python
#!/usr/bin/env python
# coding:utf-8
import rospy
from service_demo.srv import *
def client_srv():
rospy.init_node('greetings_client')
# 等待有可用的服務 "greetings"
rospy.wait_for_service("greetings")
try:
# 定義service客戶端,service名稱為“greetings”,service類型為Greeting
greetings_client = rospy.ServiceProxy("greetings",Greeting)
# 向server端發送請求,發送的request內容為name和age,其值分別為"HAN", 20
# 此處發送的request內容與srv文件中定義的request部分的屬性是一致的
#resp = greetings_client("HAN",20)
resp = greetings_client.call("HAN",20)
rospy.loginfo("Message From server:%s"%resp.feedback)
except rospy.ServiceException, e:
rospy.logwarn("Service call failed: %s"%e)
# 如果單獨運行此文件,則將上面函數client_srv()作為主函數運行
if __name__=="__main__":
client_srv()
```
以上代碼中`greetings_client.call("HAN",20)`等同于`greetings_client("HAN",20)`。
- 前言
- 第一章 ROS簡介
- 機器人時代的到來
- ROS發展歷程
- 什么是ROS
- 安裝ROS
- 安裝ROS-Academy-for-Beginners教學包
- 二進制與源碼包
- 安裝RoboWare Studio
- 單元測試一
- 第二章 ROS文件系統
- Catkin編譯系統
- Catkin工作空間
- Package軟件包
- CMakeLists.txt
- package.xml
- Metapacakge軟件元包
- 其他常見文件類型
- 單元測試二
- 第三章 ROS通信架構(一)
- Node & Master
- Launch文件
- Topic
- Msg
- 常見msg類型
- 單元測試三
- 第四章 ROS通信架構(二)
- Service
- Srv
- Parameter server
- Action
- 常見srv類型
- 常見action類型
- 單元測試四
- 第五章 常用工具
- Gazebo
- RViz
- Rqt
- Rosbag
- Rosbridge
- moveit!
- 單元測試五
- 第六章 roscpp
- Client Library與roscpp
- 節點初始、關閉與NodeHandle
- Topic in roscpp
- Service in roscpp
- Param in roscpp
- 時鐘
- 日志與異常
- 第七章 rospy
- Rospy與主要接口
- Topic in rospy
- Service in rospy
- Param與Time
- 第八章 TF與URDF
- 認識TF
- TF消息
- tf in c++
- tf in python
- 統一機器人描述格式
- 附錄:TF數學基礎
- 三維空間剛體運動---旋轉矩陣
- 三維空間剛體運動---歐拉角
- 三維空間剛體運動---四元數
- 第九章 SLAM
- 地圖
- Gmapping
- Karto
- Hector
- 第十章 Navigation
- Navigation Stack
- move_base
- costmap
- Map_server & Amcl
- 附錄:Navigation工具包說明
- amcl
- local_base_planner
- carrot_planner
- clear_costmap_recovery
- costmap_2d
- dwa_local_planner
- fake_localization
- global_planner
- map_server
- move_base_msg
- move_base
- move_slow_and_clear
- navfn
- nav_core
- robot_pose_ekf
- rotate_recovery