04 ROS Client-Service-Server实例

2023-05-16

零、Service机制

  1. Client与Server向ROS MASTER注册
  2. MASTER根据Client订阅的信息,查阅注册表中是否有提供对应Service的Server
  3. Client收到Server的TCP通信地址
  4. Client用TCP通信尝试与Server连接,并发送Service的请求数据
  5. Server接收Service请求与参数,开始执行Service
  6. Server执行Service完毕后,向Client发送应答数据

一、客户端 Client

  1. 初始化ROS节点
  2. 创建句柄
  3. 检测所需的服务是否存在
  4. 创建Client实例
  5. 封装要请求的数据内容
  6. 发布数据请求服务
  7. 等待Service反馈结果

1.创建源码

/*
ask the service /spawn
data type of the service is turtlesim::Spawn
*/

#include<ros/ros.h>
#include<turtlesim/Spawn.h>

int main(int argc,char **argv)
{
	//ROS INIT
	ros::init(argc,argv,"turtle_spawn");
	
	//create nodeHandle
	ros::NodeHandle node;
	
	//when /spawn service is detected
	//create a client and connect to /spawn service
	ros::service::waitForService("/spawn");
	ros::ServiceClient add_turtle = node.serviceClient<turtlesim::Spawn>("/spawn");
	
	//initialize the ask data for turtlesim::Spawn
	turtlesim::Spawn srv;
	srv.request.x = 2.0;
	srv.request.y = 2.0;
	srv.request.name = "turtle2";
	
	//ask for the service
	ROS_INFO("Call service to spawn turtle[x:0.3%f y:0.3%f name:%s]",
	srv.request.x,srv.request.y,srv.request.name.c_str());
	add_turtle.call(srv);
	
	//show the result
	ROS_INFO("Spawn turtle successfully![name:%s]",srv.response.name.c_str());
	
	return 0;
}

2.修改CMakeLists.txt

为成功编译
在build部分下添加

add_executable(turtle_spawn src/turtle_spawn.cpp)
target_link_libraries(turtle_spawn ${catkin_LIBRARIES})

二、服务器 Server

1.编写源码

/*
This node will execuate /turtle_command
data type of the service is std_srvs/Trigger
*/

#include<ros/ros.h>
#include<geometry_msgs/Twist.h>
#include<std_srvs/Trigger.h>

//a global publisher
ros::Publisher turtle_vel_pub;

//figure out the sport statement of turtle 
//false is stop, and true is moving
bool pubCommand = false;

//Function:
//CallBack Function for service, the input parameter is req, and the output parameter is res
//when the request is called,system will execute this function
//回调函数,输入参数为std_srvs::trigger::Request类型的req,输出参数为std_srvs::Trigger::Response类型的res
bool CommandCallBack(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)
{
	//not
	pubCommand = !pubCommand;
	
	//print the ask data
	ROS_INFO("Publish turtle velocity command [%s]",pubCommand==true?"YES":"NO");
	
	//set feedback data to the Client
	//执行Service成功,返回res给Client
	res.success = true;
	res.message = "Turtle command state Changed";
}

int main(int argc,char **argv)
{
	//ROS INIT
	ros::init(argc,argv,"turtle_command_server");
	
	//Create NodeHandle
	ros::NodeHandle n;
	
	//Create server /turtle_command
	//register the CallBack Function
	//注册Server名为command_service,接收名为/turtle_command的Service请求,触发回调函数CommandCallBack
	ros::ServiceServer command_service = n.advertiseService("/turtle_command",CommandCallBack);
	
	//Create a Publisher and pub the topic /turtle1_cmd_vel
	//message type is geometry_msgs::Twist
	//length of line is 10
	turtle_vel_pub=n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10);
	
	//waiting for the ask
	ROS_INFO("Ready to receive turtle command.");
	
	//set the rate of rotation
	ros::Rate loop_rate(10);
	
	while(ros::ok())
	{
		//check the CallBackFunction line
		ros::spinOnce();//循环等待回调函数
		
		//pub the velocity command if the flag is ture
		//the main process was set in the main function
		//so the CallBackFunction will be easy
		if(pubCommand)
		{
			geometry_msgs::Twist vel_msg;
			vel_msg.linear.x=0.5;
			vel_msg.angular.z=0.2;
			turtle_vel_pub.publish(vel_msg);
		}
		
	}
}

2.修改CMakeLists.txt

为成功编译
在build部分下添加

add_executable(turtle_command_server src/turtle_command_server.cpp)
target_link_libraries(turtle_command_server ${catkin_LIBRARIES})

3.测试

roscore
rosrun turtlesim turtlesim_node 
rosrun learning_service turtle_command_server 

执行结果:服务器准备接受service请求

[ INFO] [1647765013.874899023]: Ready to receive turtle command.

通过rosservice的call指令向服务器发起请求,内容为空(该service数据格式允许request部分为空)

rosservice call /turtle_command "{}"

该命令的反馈结果:

success: True
message: “Change turtle command state”

在服务器端结果:

[ INFO] [1647765059.771672656]: Publish turtle velocity command [YES]

海龟状态:开始画圆圈

再次执行

rosservice call /turtle_command "{}"

该命令的反馈结果:

success: True
message: “Change turtle command state”

在服务器端结果:

[ INFO] [1647765367.266284668]: Publish turtle velocity command [NO]

海龟状态:停止画圆圈

三、Service数据的定义与使用

在目录下建立srv文件夹用于存储.srv文件

1.修改Person.srv内容

string name
uint8 age
uint8 sex

uint8 unknown = 0
uint8 male= 1
uint8 female= 2
---
string result

三条横线用于划分request部分和response部分
在编译生成头文件时,两个部分将分开保存为三个头文件
Person.h PersonRequest.h PersonResponse.h

2.修改package.xml

添加消息生成、运行的功能包依赖

 <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

3.修改CMakeLists.txt

在find_package中添加message_generation包依赖

find_package(catkin REQUIRED COMPONENTS
  geometry_msgs
  roscpp
  rospy
  std_msgs
  turtlesim
  message_generation
)

################################################
Declare ROS messages, services and actions
################################################

部分
添加

add_service_files(FILES Person.srv)
generate_messages(DEPENDENCIES std_msgs)

无须添加Person.srv的路径,编译时会自动查找功能包下的srv文件
添加生成信息的依赖包std_msgs

4.编写Client源码

/*
This node will request service /show_person
ServiceDataType is learning_service::Person
*/

#include<ros/ros.h>
#include "learning_service/Person.h"

int main(int argc,char **argv)
{
	//ROSINIT
	ros::init(argc,argv,"person_client");
	
	//Create NodeHandle
	ros::NodeHandle n;
	
	//Searching for service /show_person 
	//Create a Client and connect it with service /show_person
	ros::service::waitForService("/show_person");
	ros::ServiceClient person_client = n.serviceClient<learning_service::Person>("/show_person");
	
	//Initialize the date which would be send to service /show_person
	learning_service::Person srv;
	srv.request.name="Herman123";
	srv.request.age=20;
	srv.request.sex=learning_service::Person::Request::male;
	
	//send request to Service /show_person
	ROS_INFO("Call service to show person[name:%s age:%d sex:%d]",srv.request.name.c_str(),srv.request.age,srv.request.sex);
	person_client.call(srv);
	
	//show the response
	ROS_INFO("Result:%s",srv.response.result.c_str());
	return 0;
	
}

5.编写Server源码

/*
 /show_person   server
 ServiceDataType is learning_service::Person
*/
#include<ros/ros.h>
#include"learning_service/Person.h"

//Service CALLBACKFUNCTION 
bool PersonCallBackFunction(learning_service::Person::Request &req,learning_service::Person::Response &res)
{
	//show request data
	ROS_INFO("Person name:%s age:%d sex:%d",req.name.c_str(),req.age,req.sex);
	
	//set response data
	res.result="response:OK";
	
	return true;
}

int main(int argc,char** argv)
{
	//ROSINIT
	ros::init(argc,argv,"person_server");
	
	//Create NodeHandle
	ros::NodeHandle n;
	
	//Create a server /show_person
	//register the CALLBACKFUNCTION
	//Server provide the Service /show_person
	//when server receive the request from Client
	//Server will call the CBF
	ros::ServiceServer person_service= n.advertiseService("/show_person",PersonCallBackFunction);
	
	//waiting for request and call the CBF
	ROS_INFO("READY TO SHOW PERSON INFORMATION");
	ros::spin();
	return 0;
}

6.修改CMakeLists.txt

添加依赖

add_executable(person_server src/person_server.cpp)
target_link_libraries(person_server ${catkin_LIBRARIES})
add_dependencies(person_server ${PROJECT_NAME}_gencpp)
add_executable(person_client src/person_client.cpp)
target_link_libraries(person_client ${catkin_LIBRARIES})
add_dependencies(person_client ${PROJECT_NAME}_gencpp)

7.测试

roscore

尝试调换服务器和客户端的启动顺序
当客户端先启动时,客户端无法找到服务,就会等待服务

rosrun learning_service person_client 

客户端Client反馈信息:

[ INFO] [1647790441.760583113]: waitForService: Service [/show_person]
has not been advertised, waiting…

rosrun learning_service person_server 

服务器Server提示消息:

[ INFO] [1647790528.243310236]: READY TO SHOW PERSON INFORMATION

此时客户端Client提示与反馈消息:

[ INFO] [1647790528.250326397]: waitForService: Service [/show_person]
is now available. [ INFO] [1647790528.250425869]: Call service to show
person[name:Herman123 age:20 sex:1] [ INFO] [1647790528.258398762]:
Result:response:OK

服务器Server消息:

[ INFO] [1647790528.257503152]: Person name:Herman123 age:20 sex:1

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

04 ROS Client-Service-Server实例 的相关文章

  • 让 WSO2 IOT 服务器作为 Windows 服务运行

    我在Server 2012R2上安装了WSO2 IOT Server 我安装了 YAJSW 包装器并按照 WSO2 说明进行配置 当我启动 runConsole bat 来配置 Windows 服务时 出现以下错误 我设置了 JAVA HO
  • 服务作为 SOA 中的中介

    我知道什么是 通常的 中介设计模式 维基百科中有一些描述 http en wikipedia org wiki Mediator pattern http en wikipedia org wiki Mediator pattern 在我的
  • C# 构建一个 webservice 方法,它接受 POST 方法,如 HttpWebRequest 方法

    我需要一个接受 POST 方法的 Web 服务 访问我的服务器正在使用 POST 方法 它向我发送了一个 xml 我应该用一些 xml 进行响应 另一方面 当我访问他时 我已经使用 HttpWebRequest 类进行了管理 并且工作正常
  • 如何设置 Firefox 配置文件:Selenium RC、.Net 客户端驱动程序?

    我正在使用 Selenium RC Net 客户端驱动程序 我在 c selenium 目录中创建了一个 Firefox 配置文件 这是我的代码 Dim MySelenium As ISelenium Nothing MySelenium
  • Symfony2 - 将 Swiftmailer 添加为服务

    我想将我的电子邮件代码从我的控制器移至服务中 到目前为止我已完成以下操作 在 services yml 中创建条目 在 acme demobundle services EmailManager php 中创建了一个 EmailManage
  • 需要将用户名和密码添加到 VB.NET Web 服务客户端中的 SOAP 标头

    我需要查询一个进行基本身份验证的 Web 服务 将用户名和密码放在请求标头中 我的客户端是用 VB NET Visual Basic Express Edition 2010 编写的 我已将 Web 服务添加到服务引用中 它为我自动生成了合
  • 如何将 Perforce 仓库位置转换为客户端视图位置

    我想知道如何将 Perforce 仓库位置转换为客户端视图位置以用于脚本编写 我有一个脚本 它首先检查文件以进行编辑 然后与该文件进行交互 我需要将仓库位置 即 Projects Project6 转换为客户端视图位置 即 d Projec
  • 如何在 C# 中向肥皂信封添加命名空间

    我想向我的肥皂信封添加命名空间设置 我想在 IClientMessageInspector 的 BeforeSendRequest 中更改它 或者您有更优雅的方法 例如
  • 使用服务时应用程序终止时音乐暂停

    我正在使用一个Service类在后台播放音乐 当我在顶部显示通知栏时 我的应用程序出现问题 当我终止该应用程序时 音乐停止约 1 秒 然后再次开始 我不知道出了什么问题 我正在关注this https www simplifiedcodin
  • 如何与使用 child_process.spawn 创建的新创建的服务器交互

    我正在尝试为我的私人托管的 反恐精英全球攻势 服务器制作一个前端 当我点击运行服务器时 在前端 一切正常 服务器启动并记录到控制台 但是如何查看服务器IP地址 服务器中的玩家等信息呢 这是我到目前为止运行服务器的内容 router post
  • Java TCP Echo 服务器 - 广播

    我有一个简单的回显服务器 我希望当连接的用户向服务器键入任何内容时 所有其他客户端和该客户端都会收到消息 MOD 它现在不会发送给所有客户端 但它应该发送 而且我只是不知道我的代码出了什么问题 所以现在它只会将消息 MOD 发送给发送消息的
  • 通用开源 REST 客户端? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • WCF 包装代理客户端

    我的项目中有许多在客户端应用程序中使用的 Web 方法 我不想写这样的代码 using ServiceClient sc new ServiceClient Invoke service methods sc Method1 相反 我想写
  • C:为什么这个服务器/客户端设置只能在一台计算机上运行?

    我是网络新手 我想知道为什么会这样TCP 服务器 客户端 C 语言实现 https www geeksforgeeks org tcp server client implementation in c 只能在一台计算机上运行 1 我的意思
  • 有没有办法强制 svcutil.exe 忽略 SSL 证书问题?

    我需要 svcutil exe 为我生成代理类 但问题是 Web 服务只能通过 HTTPS 访问 并且 SSL 证书是自签名的 如何强制 svcutil exe 忽略此问题 似乎有效的一件事是启动 Fiddler 并让它在您发出 SVCUT
  • Nodejs 异步函数是否使用所有 CPU 核心?

    如果我使用异步函数或带有回调的函数 例如本机 fs 模块 http 等 它们会默认在所有 cpu 核心上运行吗 或者整个系统只使用 1 个核心 Node js 中的一些异步操作 例如文件 I O fsmodule 将通过 libuv 中的线
  • 服务中的 AngularJS 变量未在视图中更新?

    我花了几天时间把头撞在桌子上 阅读博客文章 以及围绕我的问题提出的问题 我尝试了下面代码的几种变体 但到目前为止没有一个有效 我将不胜感激任何帮助 服务内的 taskList 变量会更新 但控制器中的变量不会更新 控制器 angular m
  • Grails:在域类中动态注入服务

    我需要注入基于域属性的服务 到目前为止我想出了以下内容 ApplicationHolder application getServiceClass package property Service clazz 但以这种方式加载它不会注入它的
  • Node.js Socket.IO 无法完全工作

    我运行一个侦听端口 5000 的独立服务器 当我通过 Netcat 或 Telnet 连接到它时 该应用程序不会在终端上打印任何内容 但在 Netcat Telnet 应用程序屏幕上 它显示连接已建立 var io require sock
  • 使用 TcpClient 通过 C# 通过 TCP 发送多个文件

    我正在尝试使用 C TcpClient 通过 TCP 发送多个文件 对于单个文件来说它效果很好 但是当我有多个文件时 它只发送第一个文件 这是我的代码 发送文件 try TcpClient tcpClient new TcpClient N

随机推荐

  • Linux -- 查看进程 top命令 详解

    我们上篇介绍了 xff0c Linux 中的进程等概念 xff0c 那么 xff0c 在Linux 中如何查看进程呢 xff1f xff1f 我们常用到的有两个命令 xff0c PS 和 top 两个命令 xff0c 今天先来介绍下 top
  • 24届春招百度暑假实习笔试第二题

    题干 解答 该题目在解决的时候 xff0c 需要发现就是对于相同的字符我们应该放在一起 xff0c 这样在进行修改的时候 xff0c 对其他字符的影响才会小 然后连续相同字符个数 和 组成的回文子串数目 它们的通解为 an 61 n 2 4
  • ROS学习(八)launch启动文件的使用方法

    前言 使用命令行输入代码需要不断打开终端比较繁琐 xff0c 而且容易输入错误 xff0c 那么有没有什么方法可以快速启动所需节点呢 xff1f 一 launch文件介绍 Launch文件 xff1a 通过XML文件实现多节点的配置和启动
  • 【git】git lfs

    目录 原理 使用方法 报错记录 certificate signed by unknown authority 原理 项目中的大文件会很占空间 git lfs large file storage 将大文件替换为小指针 当真正需要到这些大文
  • gdb调试应用程序记录

    gdb 调试说明 xff1a 判断程序是否为debug版本 xff1a 方法一 xff1a 命令 xff1a gdb a out 注 xff1a 这里的命令是指在Linux终端下面输入的命令 非debug版本 xff0c 会提示 xff1a
  • 3D打印机硬件驱动-马林固件最新版本2.0.X中文注释(3)marlin 2.0.9.2 截至发稿时间2021年12月16日

    Marlin 3D Printer Firmware 头描述详见其他两个文件头描述 Copyright c 2020 MarlinFirmware https github com MarlinFirmware Marlin Based o
  • 字符串结尾‘\0‘

    C语言中字符串的结束标志是 39 0 39 C语言中没有专门的字符串变量 xff0c 通常用一个字符数组来存放一个字符串 xff0c 字符串总是以 39 0 39 作为结束符 39 0 39 就是8位的00000000 xff0c 因为字符
  • 蒙德里安的梦想 状压 DP

    定义 状压 DP 是动态规划的一种 xff0c 通过将状态压缩为整数来达到优化转移的目的 例题 xff1a 蒙德里安的梦想 求把 N M 的棋盘分割成若干个 1 2 的长方形 xff0c 有多少种方案 例如当 N 61 2 xff0c M
  • Hadoop 核心三大件

    一 Hadoop Distributed File System xff0c 简称 HDFS xff0c 是一个分布式文件系统 二 YARN架构 三 MapReduce架构概述 MapReduce将计算过程分为两个阶段 xff1a Map和
  • 努力加油——感想帖

    一直很想写一篇自己的心路历程 xff0c 这篇文章于2022 10 28午编写 2020年7月10日在高考地理考卷上给自己的中学生涯画上了句号 走出考场那一刻 xff0c 心里像是有一块沉甸甸的石头被放了下来 xff0c 但好像自己并不是很
  • 小国王——状压DP

    在 n n 的棋盘上放 k 个国王 xff0c 国王可攻击相邻的 8 个格子 xff0c 求使它们无法互相攻击的方案总数 输入格式 共一行 xff0c 包含两个整数 n 和 k 输出格式 共一行 xff0c 表示方案总数 xff0c 若不能
  • 小国王(目标状态优化版)—— 状态压缩DP

    在 n n 的棋盘上放 k 个国王 xff0c 国王可攻击相邻的 8 个格子 xff0c 求使它们无法互相攻击的方案总数 输入格式 共一行 xff0c 包含两个整数 n 和 k 输出格式 共一行 xff0c 表示方案总数 xff0c 若不能
  • 炮兵阵地——状态压缩DP

    司令部的将军们打算在 N MN M 的网格地图上部署他们的炮兵部队 一个 N MN M 的地图由 NN 行 MM 列组成 xff0c 地图的每一格可能是山地 xff08 用 H 表示 xff09 xff0c 也可能是平原 xff08 用 P
  • hadoop项目实战——奥运会数据分析

    大三学期项目 hadoop MapReduce 奥运会数据分析结果 xff1a 有没需要详细实现方法的小伙伴呀 xff1f 可以在评论区评论一下 如果人多 xff0c 那么后续会详细更新实现方法
  • RT-Thread 内核线程切换原理

    1 背景 本文章主要说明 rtthread 内核线程是如何切换的 xff0c 初学者刚从裸机开发接触 RTOS 时难免会有些不适应 xff0c 明白这部分原理之后就会对 RTOS 有更深的理解 在学习内核线程切换原理之前需要有以下基础知识铺
  • 【多线程】C/C++语言中多线程和简单例子

    目录 前言 一 pthread两种状态joinable和unjoinable 二 thread join 方法存在的必要性 三 为什么要多线程 xff1a 问题 xff1a 简单的多线程编程 线程的数据处理 四 实例代码 C 43 43 C
  • 单片机开发之裸机也能 “多任务”?

    单片机开发之裸机也能 多任务 xff1f 1 背景 对于一些简单的单片机项目 xff0c 没必要非得跑RTOS xff0c 因此 xff0c 很多项目都是在 裸奔 指纯循环加上中断的机制 所以 xff0c 开发出一套好用的裸机框架是非常有必
  • vscode如何运行C++程序

    首先说一下vscode是一个支持跨平台的轻量级编辑器 1 安装c c 43 43 编译器 Linux系统一般都自带gcc和g 43 43 xff0c 但对于Windows系统而言就需要安装Mingw w64来获得编译器 步骤如下 xff1a
  • TX2 安装显卡驱动

    1 官网查询驱动版本 官方 GeForce 驱动程序 NVIDIA 这个版本gcc不合适 xff0c 换了下一个 又换了一个版本 xff0c 依旧有gcc版本问题 但查了一些资料 xff0c 对照一些版本 xff0c 觉得可能gcc冲突并不
  • 04 ROS Client-Service-Server实例

    零 Service机制 Client与Server向ROS MASTER注册MASTER根据Client订阅的信息 xff0c 查阅注册表中是否有提供对应Service的ServerClient收到Server的TCP通信地址Client用