上一章内容链接:

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()

重点:

  1. 启动服务的函数接口:rospy.Service("service名", srv数据类型, 回调函数)
  2. 回调函数中传入的是请求request,返回的是response
  3. 返回的数据类型是自定义的,比如上例中,我们自定义的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()

重点:

  1. rospy.wait_for_service("service名称")可以使得该client_node节点直到对应service服务器开始工作之后,代码才继续往下运行
  2. 启动client的函数接口:rospy.ServiceProxy("service名称",自定义srv数据类型)
  3. 向服务器发送请求使用2步骤中返回类的call函数:response = client.call(srv中request相关数据),call函数的参数为request的具体参数,本例中就是要乘的a,b两数;或者为对应的request数据格式,本例为multinumRequest(a,b)

运行结果

如下所示,跟预期一致,没有问题。

三、总结

到此,我们用两章的内容,基本涵盖ros通讯中的两大最常用的方式。ros还有一种action通讯方式,平时基本用不到。所以接下来教程也不会涉及到这部分内容。

下一章,我们来一起探索ros中的tf坐标变换。

ROS基础(二):ros通讯之服务(service)机制相关推荐

  1. [ROS基础-4] ROS系统框架

    系列文章目录 [ROS基础-1] Linux系统介绍与ubuntu安装(virtualbox) [ROS基础-2] Ubuntu系统基本操作与基本命令讲解 [ROS基础-3] ROS系统安装与基本配置 ...

  2. [ROS基础-3] ROS系统安装与基本配置

    系列文章目录 [ROS基础-1] Linux系统介绍与ubuntu安装(virtualbox) [ROS基础-2] Ubuntu系统基本操作与基本命令讲解 [ROS基础-3] ROS系统安装与基本配置 ...

  3. 一 ROS基础教程

    ROS教程 这是小弟的学习笔记,有错求请拍,多指教,谢谢 一 ROS基础知识 ROS文件系统介绍 1.功能包集stack ROS软件包集合,像Navigation Stack,属于导航软件包集合,包含 ...

  4. ROS基础篇(二)-- 基础知识

    文章目录 1 ROS简介 1.1 ROS的定义 1.2 如何学习 1.3 ROS 机器人操作系统 1.4 Linux入门 1.5 C++/Python 基础 1.6 二进制包与源代码包 2 ROS文件 ...

  5. ROS理论与实践——二、ROS基础

    ROS理论与实践--二.ROS基础 前言 一.创建工作空间 1 什么是工作空间 2 创建流程 二.创建功能包 1 创建命令 2 创建流程 三.ROS通信编程 1 话题编程 1.1 话题编程流程 1.2 ...

  6. SLAM导航机器人零基础实战系列:(二)ROS入门——2.ROS系统整体架构

    SLAM导航机器人零基础实战系列:(二)ROS入门--2.ROS系统整体架构 摘要 ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便.我们的机 ...

  7. ROS探索总结(一)(二)(三):ROS总体框架 ROS总体框架 ROS新手教程

    ROS探索总结(一)--ROS简介 一.历史 随着机器人领域的快速发展和复杂化,代码的复用性和模块化的需求原来越强烈,而已有的开源机器人系统又不能很好的适应需求.2010年Willow Garage公 ...

  8. ROS学习小笔记(Topic通信 ,service通信,参数服务器)

    (菜鸡整理的学习笔记,原文链接已经挂上,不小心过来的朋友建议去博主那边学习,谢谢) 原文链接:https://blog.csdn.net/LoongEmbedded/article/details/1 ...

  9. SLAM+语音机器人DIY系列:(二)ROS入门——2.ROS系统整体架构

    摘要 ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便.我们的机器人"miiboo"中的大部分程序也采用ROS进行开发,所 ...

最新文章

  1. 转:场景管理--BSP
  2. java如何消除太多的if else判断?
  3. TS和JS相对比的优势
  4. 2020-11-6(简述html)
  5. 【CCNA】思科PPP身份验证(PAP单向认证与CHAP单向认证)
  6. 腾讯翻译君在线翻译怎么翻译整个文件_藏语怎么翻译成中文?这两方法非常好用...
  7. Python自定义词云图形状和文本颜色
  8. 字节跳动算法工程师总结:java资料文件
  9. linux源码(含有kfifo)下载
  10. Oracle VM VirtualBox 打开Ubuntu出现0x00000000指令引用的0x00000000内存,该内存不能为written的解决方案
  11. 两线制智能仪表的信号隔离方案
  12. 超星网站服务器,云服务器 超星
  13. 1002. 写出这个数 (20)练习
  14. 网络流量分析/网络流量监测
  15. java memorystream 包_C#使用MemoryStream类读写内存
  16. 符号的英文读法(转)
  17. speak failed:not bound to TTS engine解决方案
  18. jdk1.8后在接口中新增的内容defau和static函数
  19. js根据数组对象属性删除里面的指定对象
  20. 坦克对战 : FlutterFlame在游戏上的实践

热门文章

  1. 自由浏览播放不了html5,囤货备战剁手节!360安全浏览器“抢货快”三招玩爽双十一...
  2. zimbra收取邮件跟踪日志
  3. Redis——性能测试
  4. python tabula 使用方法_Python tabula py不会读取pd
  5. php excel读写,phpGrace 工具类库 - excel 读写操作
  6. dotnetCore源码扩展:自定义ActionResult
  7. python中的map怎么用_python中的map怎么使用(方法详解)
  8. ks检验与s-w 检验_Python实现「统计学」常用的假设检验
  9. 分布式存储Swift原理分析
  10. 查找算法3——分块查找