ROS基础(二):ros通讯之服务(service)机制
上一章内容链接:
ROS基础(一):ROS通讯之话题(topic)通讯
目录
- 一、概念
- 二、实例
- 1. 小乌龟例程中的service
- 2. 自定义service
- 3. 创建服务器节点与客户端节点(c++)
- server节点编写
- client节点编写
- 运行结果
- 4. 创建服务器节点与客户端节点(python)
- server节点编写
- client节点编写
- 运行结果
- 三、总结
一、概念
service服务通讯机制是一种双向同步数据传输模式。基于客户端/服务器模型,两部分通信数据类型:一个用于请求,一个用于应答,类似web服务器。
ROS中只允许一个节点提供指定命名的服务。
与topic通讯机制的区别:
比较列表 | 话题topic | 服务service |
---|---|---|
同步性 | 异步 | 同步 |
通信模型 | 发布+订阅 | 客户端+服务器端 |
反馈机制 | 无 | 有 |
缓冲区 | 有 | 无 |
节点关系 | 多对多 | 一(server)对多 |
传输数据格式 | *.msg | *.srv |
适合场景 | 数据传输 | 逻辑处理 |
二、实例
1. 小乌龟例程中的service
首先启动第一个小乌龟:
rosrun turtlesim turtlesim_node
然后查看能够调用的所有service:
调用其中名为/spawn的服务:
如上图红框部分所示,服务器返回指定生成的乌龟名字。同时,在小乌龟仿真中在指定位置出现第二只名为turtle7
的小乌龟,如下图所示。这乌龟可以的,还在听音乐。
最后,我们查看该service的具体数据格式:
与我们的预期一致,—上方是client请求发出的内容,其中包括指定新生成乌龟的位置、朝向、名字,—下方是server返回的内容,string格式的乌龟名字,说明创建成功。
2. 自定义service
与topic话题中需要定义的message文件相似,当我们想要自定义某种服务时,需要提供对应的srv文件来对两个交互节点中具体传输的数据格式进行约束。
这里我们创建一个乘法运算案例,客户端提供两个整数a、b,服务器端计算完成后返回乘法结果到客户端。
将该srv文件命名为multinum.srv
,该文件中的内容如下:
float32 a
float32 b
---
float64 c
将该文件放在名为srv
的文件夹下,将文件夹放在功能包目录下。最终的功能包目录如下所示:
与定义message一样,我们同样要修改对应的package.xml
文件和CmakeLists.txt
文件的对应部分:
package.xml
文件:
<build_depend>message_generation</build_depend><exec_depend>message_runtime</exec_depend>
CmakeLists.txt
文件:
第一块:修改find_package部分,确保编译时找到对应文件
find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsmessage_generation
)
第二块:设置srv文件
add_service_files(FILESmultinum.srv)generate_messages(DEPENDENCIESstd_msgs)
第三块:catkin依赖部分
如果我们编写的ros程序不打算给别人使用,这块就无所谓。
catkin_package(
...CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
...
)
最后,在工作空间编译,通过相关命令测试是否已经安装成功:
如上图所示,我们的service服务查询得到,没问题。
3. 创建服务器节点与客户端节点(c++)
我们利用第二小节中自定义的service格式,来设计两个node进行service通讯。主要功能是client随机生成两个数字传递给service,然后service计算完成之后,将结果回传给client。具体的代码如下所示
server节点编写
#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节点编写
#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;
}
运行结果
首先我们将服务器节点开启,然后需要计算的时候调用client节点,服务器计算好结果之后回传给client。具体效果如下所示:
4. 创建服务器节点与客户端节点(python)
同样的东西,我们用python再实现一次。
server节点编写
#!/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()
重点:
- 启动服务的函数接口:
rospy.Service("service名", srv数据类型, 回调函数)
- 回调函数中传入的是请求request,返回的是response
- 返回的数据类型是自定义的,比如上例中,我们自定义的srv数据类型是
multinum
,那么对应的response数据类型为multinumResponse
client节点编写
#!/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()
重点:
rospy.wait_for_service("service名称")
可以使得该client_node节点直到对应service服务器开始工作之后,代码才继续往下运行- 启动client的函数接口:
rospy.ServiceProxy("service名称",自定义srv数据类型)
- 向服务器发送请求使用
2
步骤中返回类的call
函数:response = client.call(srv中request相关数据)
,call函数的参数为request的具体参数,本例中就是要乘的a,b两数;或者为对应的request数据格式,本例为multinumRequest(a,b)
运行结果
如下所示,跟预期一致,没有问题。
三、总结
到此,我们用两章的内容,基本涵盖ros通讯中的两大最常用的方式。ros还有一种action通讯方式,平时基本用不到。所以接下来教程也不会涉及到这部分内容。
下一章,我们来一起探索ros中的tf坐标变换。
ROS基础(二):ros通讯之服务(service)机制相关推荐
- [ROS基础-4] ROS系统框架
系列文章目录 [ROS基础-1] Linux系统介绍与ubuntu安装(virtualbox) [ROS基础-2] Ubuntu系统基本操作与基本命令讲解 [ROS基础-3] ROS系统安装与基本配置 ...
- [ROS基础-3] ROS系统安装与基本配置
系列文章目录 [ROS基础-1] Linux系统介绍与ubuntu安装(virtualbox) [ROS基础-2] Ubuntu系统基本操作与基本命令讲解 [ROS基础-3] ROS系统安装与基本配置 ...
- 一 ROS基础教程
ROS教程 这是小弟的学习笔记,有错求请拍,多指教,谢谢 一 ROS基础知识 ROS文件系统介绍 1.功能包集stack ROS软件包集合,像Navigation Stack,属于导航软件包集合,包含 ...
- ROS基础篇(二)-- 基础知识
文章目录 1 ROS简介 1.1 ROS的定义 1.2 如何学习 1.3 ROS 机器人操作系统 1.4 Linux入门 1.5 C++/Python 基础 1.6 二进制包与源代码包 2 ROS文件 ...
- ROS理论与实践——二、ROS基础
ROS理论与实践--二.ROS基础 前言 一.创建工作空间 1 什么是工作空间 2 创建流程 二.创建功能包 1 创建命令 2 创建流程 三.ROS通信编程 1 话题编程 1.1 话题编程流程 1.2 ...
- SLAM导航机器人零基础实战系列:(二)ROS入门——2.ROS系统整体架构
SLAM导航机器人零基础实战系列:(二)ROS入门--2.ROS系统整体架构 摘要 ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便.我们的机 ...
- ROS探索总结(一)(二)(三):ROS总体框架 ROS总体框架 ROS新手教程
ROS探索总结(一)--ROS简介 一.历史 随着机器人领域的快速发展和复杂化,代码的复用性和模块化的需求原来越强烈,而已有的开源机器人系统又不能很好的适应需求.2010年Willow Garage公 ...
- ROS学习小笔记(Topic通信 ,service通信,参数服务器)
(菜鸡整理的学习笔记,原文链接已经挂上,不小心过来的朋友建议去博主那边学习,谢谢) 原文链接:https://blog.csdn.net/LoongEmbedded/article/details/1 ...
- SLAM+语音机器人DIY系列:(二)ROS入门——2.ROS系统整体架构
摘要 ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便.我们的机器人"miiboo"中的大部分程序也采用ROS进行开发,所 ...
最新文章
- 转:场景管理--BSP
- java如何消除太多的if else判断?
- TS和JS相对比的优势
- 2020-11-6(简述html)
- 【CCNA】思科PPP身份验证(PAP单向认证与CHAP单向认证)
- 腾讯翻译君在线翻译怎么翻译整个文件_藏语怎么翻译成中文?这两方法非常好用...
- Python自定义词云图形状和文本颜色
- 字节跳动算法工程师总结:java资料文件
- linux源码(含有kfifo)下载
- Oracle VM VirtualBox 打开Ubuntu出现0x00000000指令引用的0x00000000内存,该内存不能为written的解决方案
- 两线制智能仪表的信号隔离方案
- 超星网站服务器,云服务器 超星
- 1002. 写出这个数 (20)练习
- 网络流量分析/网络流量监测
- java memorystream 包_C#使用MemoryStream类读写内存
- 符号的英文读法(转)
- speak failed:not bound to TTS engine解决方案
- jdk1.8后在接口中新增的内容defau和static函数
- js根据数组对象属性删除里面的指定对象
- 坦克对战 : FlutterFlame在游戏上的实践
热门文章
- 自由浏览播放不了html5,囤货备战剁手节!360安全浏览器“抢货快”三招玩爽双十一...
- zimbra收取邮件跟踪日志
- Redis——性能测试
- python tabula 使用方法_Python tabula py不会读取pd
- php excel读写,phpGrace 工具类库 - excel 读写操作
- dotnetCore源码扩展:自定义ActionResult
- python中的map怎么用_python中的map怎么使用(方法详解)
- ks检验与s-w 检验_Python实现「统计学」常用的假设检验
- 分布式存储Swift原理分析
- 查找算法3——分块查找