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.rhkb.cn/news/195520.html

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

相关文章

ubuntu云服务器配置SFTP服务

目录 一、安装并运行SSH服务 1&#xff0c;安装ssh服务 2&#xff0c;运行ssh 3&#xff0c;查看ssh运行状态 二、创建SFTP用户并进行用户相关的配置 1&#xff0c;创建SFTP用户 2&#xff0c;限制用户只能使用 SFTP&#xff0c;并禁止 SSH 登录。打开/ect/ssh/sshd_conf…

【源码系列】短剧系统开发国际版短剧系统软件平台介绍

系统介绍 短剧是一种快节奏、紧凑、有趣的戏剧形式&#xff0c;通过短时间的精彩表演&#xff0c;向观众传递故事的情感和思考。它以其独特的形式和魅力&#xff0c;吸引着观众的关注&#xff0c;成为了当代戏剧娱乐中不可或缺的一部分。短剧每一集都是一个小故事&#xff0c;…

ArcGIS创建格网

目录 1、创建网格 2、裁剪边界外的网格 3、只保留边界内完整的网格 1、创建网格 首先&#xff0c;我们在创建渔网前&#xff0c;需要指定渔网覆盖的范围。这里我们就以四子王为例 在ArcMap软件中&#xff0c;我们依次选择“Toolboxes”→“Data Management Tools&#xff0…

Centos上删除文件及目录的命令积累

01-如果我想删除Centos上当前目录下的文件 test06-2023-11-14-01.sql 该怎么操作&#xff1f; 答&#xff1a;如果你想删除CentOS上当前目录下的文件 test06-2023-11-14-01.sql&#xff0c;可以使用 rm 命令。以下是删除文件的基本语法&#xff1a; rm test06-2023-11-14-01.s…

结构体数组保存进二进制文件的简单做法

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 最近面临这样一个需求&#xff1a;以比较节省存储空间的存储一组坐标点到文件&#xff0c;要求程序能够跨平台读写这种文件。思考了一下&#xff0c;比较…

为开发GPT-5,OpenAI向微软寻求新融资

11月14日&#xff0c;金融时报消息&#xff0c;OpenAI正在向微软寻求新一轮融资&#xff0c;用于开发超级智能向AGI&#xff08;通用人工智能&#xff09;迈进&#xff0c;包括最新模型GPT-5。 最近&#xff0c;OpenAI召开了首届开发者大会&#xff0c;推出了GPT-4 Turbo、自定…

视频一键转码:批量转换MP4视频的技巧

随着数字媒体设备的普及&#xff0c;视频文件在生活中扮演着越来越重要的角色。而在处理视频文件时&#xff0c;有时需要将其转换为不同的格式以适应不同的需求。其中&#xff0c;MP4格式因其通用性和高质量而备受青睐。本文详解云炫AI智剪如何一键转码的技巧&#xff0c;帮助批…

基于SpringBoot的SSMP整合案例(在Linux中发布项目的注意事项与具体步骤步骤)

前言与注意 这几天在Linux中上线之前的小项目时&#xff0c;遇到了很多的问题&#xff0c;Linux镜像的选择&#xff0c;jdk&#xff0c; mysql在linux中的下载&#xff0c;使用finallshell连接linux&#xff0c;使用tomcat连接linux中的数据库........ 在下面的注意事项中我会将…

wpf devexpress 自定义统计

总计统计和分组统计包含预定义总计函数。这些函数允许你计算如下&#xff1a; 数据列的数量&#xff08;Count&#xff09; 最大和最小值(Max和Min) 总计和平均值&#xff08;Sum和Average&#xff09; 处理GridControl.CustomSummary 事件或者使用 GridControl.CustomSumm…

Android Glide加载transform CenterCrop, CircleCrop ShapeableImageView圆形图并描边,Kotlin

Android Glide加载transform CenterCrop, CircleCrop ShapeableImageView圆形图并描边&#xff0c;Kotlin import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.bumptech.glide.load.resource.bitmap.CenterCrop import com.bumptech.glide.…

7、使用真机调试鸿蒙项目

此处以华为手机为例&#xff0c;版本为鸿蒙4.0. 一、打开手机调试功能 1、打开开发者模式 打开“设置”—“关于手机”&#xff0c;连续点击“软件版本”可打开开发者模式 2、开启USB调试功能 打开“设置”—“系统更新”—“开发者选项”&#xff0c;下拉找到“USB调试”…

ffmpeg5及以上-s和像素格式转换 画屏问题

环境: lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.10 Release: 22.10 Codename: kinetic拉下ffmpeg源码&#xff0c;6.0.1&#xff0c;4.3.6&#xff0c;5.1.4&#xff0c;依次安装作实验 ./configure --disable-x86asm …

【Linux】第十八站:进程等待

文章目录 一、进程等待的必要性1.进程等待是什么2.进程等待的必要性3.为什么要进程等待呢&#xff1f; 二、进程等待的方法1.问题2.wait3.waitpid4.status的原理5.等待失败6.与status有关的两个宏7.options 一、进程等待的必要性 1.进程等待是什么 通过系统调用wait/waitpid&a…

034、test

之——全纪录 目录 之——全纪录 杂谈 正文 1.下载处理数据 2.数据集概览 3.构建自定义dataset 4.初始化网络 5.训练 杂谈 综合方法试一下。 leaves 1.下载处理数据 从官网下载数据集&#xff1a;Classify Leaves | Kaggle 解压后有一个图片集&#xff0c;一个提交示…

Linux :远程访问的 16 个最佳工具(一)

通过远程桌面协议 (RDP) 可以访问远程 Linux 桌面计算机&#xff0c;这是 Microsoft 开发的专有协议。它为用户提供了一个图形界面&#xff0c;可以通过网络连接连接到另一台/远程计算机。 FreeRDP 是 RDP 的免费实现。 RDP以客户端/服务器模型工作&#xff0c;其中远程计算机必…

服务器集群配置LDAP统一认证高可用集群(配置tsl安全链接)-centos9stream-openldap2.6.2

写在前面 因之前集群为centos6&#xff0c;已经很久没升级了&#xff0c;所以这次配置统一用户认证也是伴随系统升级到centos9时一起做的配套升级。新版的openldap配置大致与老版本比较相似&#xff0c;但有些地方配置还是有变化&#xff0c;另外&#xff0c;铺天盖地的帮助文…

R语言绘制精美图形 | 火山图 | 学习笔记

一边学习&#xff0c;一边总结&#xff0c;一边分享&#xff01; 教程图形 前言 最近的事情较多&#xff0c;教程更新实在是跟不上&#xff0c;主要原因是自己没有太多时间来学习和整理相关的内容。一般在下半年基本都是非常忙&#xff0c;所有一个人的精力和时间有限&#x…

「Verilog学习笔记」使用8线-3线优先编码器Ⅰ实现16线-4线优先编码器

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 分析 当EI10时、U1禁止编码&#xff0c;其输出端Y为000&#xff0c;GS1、EO1均为0。同时EO1使EI00&#xff0c;U0也禁止编码&#xff0c;其输出端及GS0、EO0均为0。由电路…

Postman内置动态参数以及自定义的动态参数

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 一&#xff09;内置动态参数 {{$timestamp}} 生成当前时间的时间戳{{$randomInt}} 生成0-1000之间的随机数{{$guid}} 生成随…

Ansys Electronics Desktop仿真——HFSS线圈寄生电阻,电感

利用ANSYS Electronics Desktop&#xff0c;可在综合全面、易于使用的设计平台中集成严格的电磁场分析和系统电路仿真。按需求解器技术让您能集成电磁场仿真器和电路及系统级仿真&#xff0c;以探索完整的系统性能。 HFSS&#xff08;High Frequency Structure Simulator&#…