# 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