ROS服务(Service)通信:通信模型、Hello World与拓展

服务通讯是基于请求响应模式的,是一种应答机制。

用于偶然的、对时时性有要求、有一定逻辑处理需求的数据传输场景。

一、服务通讯模型

服务是一种双向通讯方式,它通过请求和应答的方式传递消息,该模型涉及到三个角色:

  • Master (管理者)
  • Server(服务端)
  • Client(客户端)

Master 负责保管 ServerClient 的注册信息,并匹配服务名称相同的 ServerClient ,帮助 他们建立连接,连接建立后,Client 可以发送请求信息, Server 收到请求后返回响应信息。

在这里插入图片描述

服务模型通讯流程:

  • 0)advertise:服务端注册

    服务端(Server)向管理者(Master)注册信息,包括RPC地址和Service名字。Master会将服务端的注册信息加入到注册表中。

  • 1)客户端注册

    客户端(Client)向管理者(Master)注册信息,包括Service名字。Master会将客户端(Client)的注册信息加入到注册表中。

  • 2)Master匹配信息:牵线搭桥

    管理者(Master)通过查询注册表发现有匹配的服务端(Server)和客户端(Client),则通过RPC向客户端(Client)发送服务端(Server)的 TCP/UDP 地址信息。

  • 3)客户端发送请求信息

    客户端根据服务端的 TCP/UDP 地址与服务端建立网络连接,并发送请求信息。

  • 4)服务端响应请求

    服务端收到请求数据后,通过处理产生响应数据,通过 TCP/UDP 返回给客户端。

Note:

  1. 上述实现流程中,前三步使用 RPC 协议,最后两步使用 TCP/UDP 协议,默认TCP。
  2. 客户端请求时,必须保证服务端已经启动。
  3. 服务名相同的客户端可以有多个,服务端只能有1个。
  4. 与话题通信不同,服务通信过程中,ROS Master必须处于启动状态。

二、Service Hello World

万物始于Hello World,同样,使用Hello World介绍Service的简单使用。

使用Service传输数据时,需要注意以下几点:

  • Service名称
  • 消息格式(srv)
  • 服务端实现
  • 客户端实现

接下来实现一个简单的 Service 服务通信,客户端请求启动机器人,服务端启动机器人的各个模块,然后返回执行结果。

2.1 创建并初始化功能包

首先创建 service_hello_world 包,命令如下:

catkin_creat_pkg service_hello_world std_srvs roscpp rospy

创建后,文件结构如下:

在这里插入图片描述

2.2 确定Service名称及消息格式

Service名称:/hello_world_service

消息格式:std_srvs::SetBool

消息文件路径:/opt/ros/noetic/share/std_srvs/srv/SetBool.srv

消息文件内容:

bool data # e.g. for hardware enabling / disabling
---
bool success   # indicate successful run of triggered service
string message # informational, e.g. for error messages

2.3 实现服务端与客户端(C++版)

在创建的 service_hello_world 包路径下有一个 src 目录,在这里存储C++源码,我们创建 service_hello_world_server.cpp 以实现服务端,编辑内容如下:

#include <ros/ros.h>
#include <std_srvs/SetBool.h>bool dealRobotSwitch(std_srvs::SetBool::Request &req, std_srvs::SetBool::Response &resp)
{bool flag = req.data;ROS_INFO("服务器收到 [%s] 机器人的指令.", flag ? "启动" : "关闭");// 逻辑处理if (flag){ROS_INFO("正在启动机器人各模块...");ros::Duration(2).sleep();// 使用时间模拟随机成功与失败if (ros::Time::now().toNSec() % 2 == 0){resp.success = true;resp.message = "Hello World.";ROS_INFO("机器人各模块启动成功.\n");}else{resp.success = false;resp.message = "再睡一会";ROS_INFO("机器人各模块启动失败.\n");}}else{ROS_INFO("正在关闭机器人各模块...");ros::Duration(2).sleep();// 模拟成功与失败if (ros::Time::now().toNSec() % 2 == 0){resp.success = true;resp.message = "Good Night.";ROS_INFO("机器人各模块关闭成功.\n");}else{resp.success = false;resp.message = "我还能卷";ROS_INFO("机器人各模块关闭失败.\n");}}return true;
}int main(int argc, char **argv)
{setlocale(LC_ALL, "");ros::init(argc, argv, "service_hello_world_server");ros::NodeHandle nh;ros::ServiceServer server = nh.advertiseService("/robotSwitch", dealRobotSwitch);ROS_INFO("robotSwitch 服务已启动...");ros::spin();return 0;
}

创建 service_hello_world_client.cpp 以实现客户端,编辑内容如下:

#include <ros/ros.h>
#include <std_srvs/SetBool.h>int main(int argc, char **argv)
{setlocale(LC_ALL, "");ros::init(argc, argv, "service_hello_world_client");ros::NodeHandle nh;ros::ServiceClient client = nh.serviceClient<std_srvs::SetBool>("/robotSwitch");std_srvs::SetBool srv;if (strcmp(argv[1], "on") == 0){srv.request.data = true;}else if (strcmp(argv[1], "off") == 0){srv.request.data = false;}else{ROS_WARN("仅支持on和off");return 1;}// 等待服务启动// ros::service::waitForService("/robotSwitch");// client.waitForExistence();if (client.call(srv)){if (srv.response.success){ROS_INFO("操作成功, %s", srv.response.message.c_str());}else{ROS_ERROR("操作失败, %s", srv.response.message.c_str());}}else{ROS_ERROR("操作失败, 未知错误!");}return 0;
}

修改 CMakeLists.txt ,只需添加如下内容:

add_executable(${PROJECT_NAME}_client src/service_hello_world_client.cpp)
add_executable(${PROJECT_NAME}_server src/service_hello_world_server.cpp)target_link_libraries(${PROJECT_NAME}_client${catkin_LIBRARIES}
)target_link_libraries(${PROJECT_NAME}_server${catkin_LIBRARIES}
)

编译运行

进入工作空间执行 catkin_make 命令编译工程,编译成功后,使用如下命令依次启动服务端和客户端。

1. 启动ros master
roscore
2. 启动服务端
rosrun service_hello_world service_hello_world_server
3. 启动客户端
rosrun service_hello_world service_hello_world_client

结果如下:

在这里插入图片描述

目前为止,Service Hello World 已经成功了。

2.4 实现服务端与客户端(Python版)

在创建的 service_hello_world 包路径下 src 目录的同级,创建一个 scripts 目录,在这里存储脚本(如python脚本),我们创建 service_hello_world_server.py 以实现服务端,编辑内容如下:

import rospy
from std_srvs.srv import SetBool, SetBoolResponsedef dealRobotSwitch(req):flag = req.datarospy.loginfo("服务器收到 [%s] 机器人的指令.", "启动" if flag else "关闭")if flag:rospy.loginfo("正在启动机器人各模块...")if rospy.Time.now().to_nsec() % 2 == 0:rospy.loginfo("机器人各模块启动成功.\n")return SetBoolResponse(True, "Hello World.")else:rospy.logerr("机器人各模块启动失败.\n")return SetBoolResponse(False, "再睡一会")else:rospy.loginfo("正在关闭机器人各模块...")if rospy.Time.now().to_nsec() % 2 == 0:rospy.loginfo("机器人各模块关闭成功.\n")return SetBoolResponse(True, "Good Night.")else:rospy.logerr("机器人各模块关闭失败.\n")return SetBoolResponse(False, "我还能卷")if __name__ == "__main__":rospy.init_node("service_hello_world_server")server = rospy.Service("/robotSwitch", SetBool, dealRobotSwitch)rospy.loginfo("robotSwitch 服务已启动...")rospy.spin()

创建 service_hello_world_client.py 以实现客户端,编辑内容如下:

import sys
import rospy
from std_srvs.srv import SetBool, SetBoolRequestif __name__ == "__main__":rospy.init_node("service_hello_world_client")if len(sys.argv) != 2:rospy.logerr("参数个数有误")sys.exit(1)flag = Falseif sys.argv[1] == "on":flag = Trueelif sys.argv[1] == "off":passelse:rospy.logwarn("仅支持on和off")sys.exit(1)rospy.loginfo("客户端请求 [%s] 机器人.", "启动" if flag else "关闭")client = rospy.ServiceProxy("/robotSwitch", SetBool)client.wait_for_service()req = SetBoolRequest()req.data = flagres = client.call(req)if res.success:rospy.loginfo("操作成功,%s", res.message)else:rospy.logerr("操作失败,%s", res.message)

修改 CMakeLists.txt ,只需添加如下内容:

catkin_install_python(PROGRAMSscripts/service_hello_world_server.pyscripts/service_hello_world_client.pyDESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

编译运行

进入工作空间执行 catkin_make 命令编译工程,编译成功后,使用如下命令依次启动服务端和客户端。

1. 启动ros master(如果已启动,无需再启动)
roscore
2. 启动服务端
rosrun service_hello_world service_hello_world_server.py
3. 启动客户端
rosrun service_hello_world service_hello_world_client.py

结果如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/188342.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

公寓水电管理系统

springbootmybatisthymeleaf 这次练习是尝试将layer与系统结合起来&#xff0c;将新增、修改、删除都和弹窗结合起来。 一、需求分析 二、数据库 三、模块 1、登录页面 哈哈哈&#xff0c;之前做的登录页面都好丑&#xff0c;这是目前做的最好看的一次了。 超级管理员&…

Redis实战篇(1)

实战篇Redis 短信登录 这一块我们会使用redis共享session来实现 商户查询缓存 通过本章节&#xff0c;我们会理解缓存击穿&#xff0c;缓存穿透&#xff0c;缓存雪崩等问题&#xff0c;让小伙伴的对于这些概念的理解不仅仅是停留在概念上&#xff0c;更是能在代码中看到对应…

ke11..--2其他界面也要提取我的locatStarage

获取浏览器里面的本地缓存 localStorage就是我们的浏览器缓存在哪都可以用 下面代码是获取打印到我们的页面上 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> …

深度学习入门(第二天)——走进深度学习的世界 神经网络模型

一、反向传播计算方法 简单的例子&#xff1a; 如何让 f 值更小&#xff0c;就是改变x、y、z&#xff0c;而损失函数也是这样&#xff0c;那么我们分别求偏导&#xff0c;则能得出每个值对结果的影响 链式法则 梯度是一步一步传的 复杂的例子&#xff1a; 二、神经网络整体架…

ACM练习——第一天

因为最近要去农大参加他们的算法邀请赛&#xff0c;然后赛制是ACM赛制的&#xff0c;所以我就直接很迷茫。 然后我就找到了牛客的ACM练习题&#xff0c;好好的练习一下ACM写法&#xff0c;而且我还要被迫写C&#xff0c;哭了。 开始钻研 1.从Java过度到C 题目源于牛客网&…

超越视觉:探索The Foundry NUKE 15 的无限可能性

你是否曾被电影中那些令人震撼的特效所吸引&#xff1f;是否曾梦想过自己也能制作出这样的特效&#xff1f;现在&#xff0c;这个梦想即将成为现实。今天&#xff0c;我们将向你介绍一款引领影视后期特效制作潮流的软件——The Foundry NUKE 15。 The Foundry NUKE 15是一款专…

07.智慧商城——商品详情页、加入购物车、拦截器封装token

01. 商品详情 - 静态布局 静态结构 和 样式 <template><div class"prodetail"><van-nav-bar fixed title"商品详情页" left-arrow click-left"$router.go(-1)" /><van-swipe :autoplay"3000" change"onCha…

结合 Django 和 Vue.js 打造现代 Web 应用

概要 在 Web 开发的世界里&#xff0c;Django 和 Vue.js 分别是后端和前端两个非常流行的框架。Django 以其强大的后端能力、快速开发以及安全性而著称&#xff0c;而 Vue.js 因其简洁、灵活和易于上手在前端开发领域广受欢迎。 本篇文章将详细介绍如何将 Django 与 Vue.js 结…

双点双向重发布

配置IP [R1-GigabitEthernet0/0/0]ip ad 192.168.12.1 24 [R1-GigabitEthernet0/0/1]ip ad 192.168.13.1 24 [R1-LoopBack0]ip address 1.1.1.1 24 [R2-GigabitEthernet0/0/0]ip address 192.168.12.2 24 [R2-GigabitEthernet0/0/1]ip address 192.168.24.2 24 [R2-LoopBack0…

多媒体领域顶会ACM MM 2023 获奖论文一览

ACM 国际多媒体会议是计算机科学领域中多媒体领域的顶级会议&#xff0c;属于CCF A类。今年的ACM MM 2023 已于2023年10月29日至11月2日在加拿大渥太华举行。 ACM MM会议专注于推动多媒体研究和应用&#xff0c;其研究领域广泛涉及触觉、视频、VR/AR、音频、语音、音乐、传感器…

解析 Python requests 库 POST 请求中的参数顺序问题

在这篇文章中&#xff0c;我们将探讨一个用户在使用Python的requests库进行POST请求时遇到的问题&#xff0c;即参数顺序的不一致。用户通过Fiddler进行网络抓包&#xff0c;发现请求体中的参数顺序与他设置的顺序不符。我们将深入了解POST请求的工作原理&#xff0c;并提供解决…

Mysql超详细安装配置教程(保姆级)

目录 一、下载Mysql 二、安装Mysql 三、配置Mysql 四、连接Mysql 五、部分疑难问题 一、下载Mysql 从官网下载MySQL&#xff0c;这里我选用的是Mysql8.0.34版本 二、安装Mysql 下载完成后直接双击进行安装&#xff0c;打开后的页面如下所示&#xff1a; “Developer Defa…