ROS服务通信机制实操C++

ROS服务通信实操C++

  • 步骤流程
  • VScode 配置
  • 服务端
  • 客户端
  • 编辑配置文件
  • 编译并执行
  • 优化
    • 实现参数的动态提交
    • 优化先启动客户端后启动服务端

ROS服务通信的理论查阅:ROS服务通信流程理论

ROS服务通信的自定义srv数据的准备可以查阅:ROS服务通信自定义srv

在模型实现中,ROS master不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:

  • 服务端
  • 客户端
  • 数据

步骤流程

实现ROS服务通信的步骤分为以下5步:

  • 1.VScode 配置
  • 2.编写服务端实现;
  • 3.编写客户端实现;
  • 4.编辑配置文件;
  • 5.编译并执行。

VScode 配置

需要像之前自定义 msg 实现一样配置 c_cpp_properies.json 文件,如果以前已经配置且没有变更工作空间,可以忽略,如果需要配置,配置方式与之前相同:

在这里插入图片描述

服务端

  • 基本流程

    • 1.包含头文件;
    • 2.初始化ROS节点;
    • 3.创建6节点句柄;
    • 4.创建一个服务对象;
    • 5.处理请求并产生响应;
    • 6.spin()
  • 代码实现

    #include "ros/ros.h"
    #include "plumbing_server_client/AddInts.h"/*服务端实现:解析客户端提交的数据,并运算再进行响应1.包含头文件;2.初始化ROS节点;3.创建6节点句柄;4.创建一个服务对象;5.处理请求并产生响应;6.spin()
    */bool doMsg(plumbing_server_client::AddInts::Request & request,plumbing_server_client::AddInts::Response & response)
    {int num1 = request.num1;int num2 = request.num2;ROS_INFO("收到的请求数据:num1 = %d,num2 = %d",num1, num2);int sum = num1 + num2;response.sum = sum;ROS_INFO("求和结果:sum = %d", sum);return true;}int main(int argc, char  *argv[])
    {setlocale(LC_ALL, "");// 2.初始化ROS节点;ros::init(argc, argv, "heiShui");// 3.创建6节点句柄;ros::NodeHandle nh;// 4.创建一个服务对象;ros::ServiceServer server = nh.advertiseService("addInts", doMsg);ROS_INFO("服务器端启动");// 5.处理请求并产生响应;// 6.spin()ros::spin(); //处理回调函数return 0;
    }
    
  • 验证是否有问题

    • 编辑配置文件
      修改 plumbing_server_client 功能包下的CMakeLists.txt,找到add_executable、add_dependencies和target_link_libraries,修改成如图所示:
      在这里插入图片描述

    • 按快捷键 ctrl + shift + B 编译

      在这里插入图片描述

    • 开启一个Terminal,运行 roscore 命令;再开启一个新的Terminal,运行 source ./devel/setup.bash rosrun plumbing_server_client demo_server_c ;再开启一个Terminal,运行 rosservice call addInts "num1: 1 num2: 2" (num1 num2是按Tab键自动补齐,然后修改数字),查看服务请求数据并响应

      在这里插入图片描述

客户端

  • 基本流程

    • 1.包含头文件;
    • 2.初始化ROS节点;
    • 3.创建节点句柄;
    • 4.创建一个客户端对象;
    • 5.提交请求并处理响应
  • 代码实现

    #include "ros/ros.h"
    #include "plumbing_server_client/AddInts.h"/*客户端:提交两个整数,并处理响应的结果1.包含头文件;2.初始化ROS节点;3.创建节点句柄;4.创建一个客户端对象;5.提交请求并处理响应
    */int main(int argc, char *argv[])
    {setlocale(LC_ALL, ""); // 处理中文乱码// 2.初始化ROS节点;ros::init(argc, argv, "daZhuang");// 3.创建节点句柄;ros::NodeHandle nh;// 4.创建一个客户端对象;ros::ServiceClient client = nh.serviceClient<plumbing_server_client::AddInts>("addInts");// 5.提交请求并处理响应plumbing_server_client::AddInts add; // 创建一个 AddInts 对象// 5-1 组织请求add.request.num1 = 100;add.request.num2 = 300;// 5-2 处理请求bool flag = client.call(add); // 处理请求,传入AddInts对象, 返回响应结果,响应成功flag为true,失败为flaseif(flag){ROS_INFO("响应成功");ROS_INFO("响应结果:sum = %d", add.response.sum);}else{ROS_INFO("响应失败...");}return 0;
    }
    

编辑配置文件

修改 plumbing_server_client 功能包下的CMakeLists.txt,找到add_executable、add_dependencies和target_link_libraries,修改成如图所示:

在这里插入图片描述

编译并执行

  • 编译代码
    按快捷键 ctrl + shift + B 编译

    在这里插入图片描述

  • 执行代码

    • 1.启动 roscore;
      开启一个Terminal,启动 roscore
      在这里插入图片描述

    • 2.启动服务节点;
      开启一个新的Terminal

      cd topic_ws/
      source ./devel/setup.bash 
      rosrun plumbing_server_client demo_server_c 

      在这里插入图片描述

    • 3.启动客户节点。

      cd topic_ws/
      source ./devel/setup.bash 
      rosrun plumbing_server_client demo_client_c 

      在这里插入图片描述

正常情况下的服务通信必须得先启动服务端,然后启动客户端

优化

实现参数的动态提交

前面响应的数据都是写死的,将数据实现动态的输入,主要是修改客户端代码,服务端不用修改。
格式:rosrun xxxxx xxxxxx num1 num2
代码实现

#include "ros/ros.h"
#include "plumbing_server_client/AddInts.h"/*客户端:提交两个整数,并处理响应的结果1.包含头文件;2.初始化ROS节点;3.创建节点句柄;4.创建一个客户端对象;5.提交请求并处理响应
*/int main(int argc, char *argv[])
{setlocale(LC_ALL, ""); // 处理中文乱码// 优化实现,获取命令中的参数if (argc != 3){ROS_INFO("传入参数的个数不对!!!");return 1;}// 2.初始化ROS节点;ros::init(argc, argv, "daZhuang");// 3.创建节点句柄;ros::NodeHandle nh;// 4.创建一个客户端对象;ros::ServiceClient client = nh.serviceClient<plumbing_server_client::AddInts>("addInts");// 5.提交请求并处理响应plumbing_server_client::AddInts add; // 创建一个 AddInts 对象// 5-1 组织请求// add.request.num1 = 100;// add.request.num2 = 300;add.request.num1 = atoi(argv[1]);  // atoi()将字符串转成 int 类型add.request.num2 = atoi(argv[2]);// 5-2 处理请求bool flag = client.call(add); // 处理请求,传入AddInts对象, 返回响应结果,响应成功flag为true,失败为flaseif(flag){ROS_INFO("响应成功");ROS_INFO("响应结果:sum = %d", add.response.sum);}else{ROS_INFO("响应失败...");}return 0;
}

编译后,启动 roscore 和服务端,然后启动客户端,同时输入请求的参数 num1num2,如图所示:

在这里插入图片描述

优化先启动客户端后启动服务端

正常情况下是先启动服务端,然后在启动客户端。如果有先启动客户端,挂起等待服务端启动后再请求的需求。就需要调用ROS的内置等待函数 client.waitForExistence()ros::service::waitForService("服务话题")

代码实现

#include "ros/ros.h"
#include "plumbing_server_client/AddInts.h"/*客户端:提交两个整数,并处理响应的结果1.包含头文件;2.初始化ROS节点;3.创建节点句柄;4.创建一个客户端对象;5.提交请求并处理响应
*/int main(int argc, char *argv[])
{setlocale(LC_ALL, ""); // 处理中文乱码// 优化实现,获取命令中的参数if (argc != 3){ROS_INFO("传入参数的个数不对!!!");return 1;}// 2.初始化ROS节点;ros::init(argc, argv, "daZhuang");// 3.创建节点句柄;ros::NodeHandle nh;// 4.创建一个客户端对象;ros::ServiceClient client = nh.serviceClient<plumbing_server_client::AddInts>("addInts");// 5.提交请求并处理响应plumbing_server_client::AddInts add; // 创建一个 AddInts 对象// 5-1 组织请求// add.request.num1 = 100;// add.request.num2 = 300;add.request.num1 = atoi(argv[1]);  // atoi()将字符串转成 int 类型add.request.num2 = atoi(argv[2]);// 调用判断服务器状态的函数// client.waitForExistence();  // 创建的客户端自己有的等待函数ros::service::waitForService("addInts");  // ros内置的等待函数,需要传入等待的服务话题// 5-2 处理请求bool flag = client.call(add); // 处理请求,传入AddInts对象, 返回响应结果,响应成功flag为true,失败为flaseif(flag){ROS_INFO("响应成功");ROS_INFO("响应结果:sum = %d", add.response.sum);}else{ROS_INFO("响应失败...");}return 0;
}

启动客户端后,没有启动服务端,结果如图所示:
在这里插入图片描述

再启动服务端后,请求进行响应,结果如图所示:

在这里插入图片描述

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

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

相关文章

使用Docker 实现 MySQL 循环复制(三)

系列文章 使用Docker 实现 MySQL 循环复制&#xff08;一&#xff09; 使用Docker 实现 MySQL 循环复制&#xff08;二&#xff09; 目录 系列文章1. 在主机上安装MySQL客户端2. 配置循环复制拓扑2.1 进入容器2.2 创建复制用户并授予复制权限2.3 复位二进制日志2.4 配置环形复…

Navicat安装

1.安装包下载。 2.双击exe文件&#xff0c;一直点下一步即可&#xff0c;可以修改安装位置 3.双击PatchNavicat.exe&#xff0c;在下方位置输入navicat的安装位置 4.提示成功

【Linux】线程——线程池、线程池的实现、线程安全的线程池、单例模式的概念、饿汉和懒汉模式、互斥锁、条件变量、信号量、自旋锁、读写锁

文章目录 Linux线程7. 线程池7.1 线程池介绍7.2 线程池的实现7.3 线程安全的线程池7.3.1 单例模式的概念7.3.2 饿汉和懒汉模式 8. 常见锁使用汇总8.1 互斥锁&#xff08;Mutex&#xff09;8.2 条件变量&#xff08;Condition Variable&#xff09;8.3 信号量&#xff08;Semaph…

Ubantu 使用 docker 配置 + 远程部署 + 远程开发

大家好我是苏麟 , Ubantu 一些配置 . 视频 : 服务器很贵&#xff1f;搞台虚拟机玩玩&#xff01;保姆级 Linux 远程开发教程_哔哩哔哩_bilibili Docker安装及配置 安装命令 : sudo apt install docker.io 查看版本号 : docker -v 查看虚拟机地址命令 : ifconfig 虚拟机地址 或…

maven项目打成可运行的jar及pom中的依赖一同打包

maven项目打jar及pom中的依赖一同打包 最近开发中有个需求&#xff0c;不部署新的服务&#xff0c;只jar包执行 那maven项目中&#xff0c;代码如何以jar的方式运行、如何把代码打成jar、pom中的依赖如何与代码一同打到jar包中&#xff1f; 1、代码如何以jar的方式运行&…

海豚调度器(DolphinScheduler)集群搭建详细笔记

海豚调度器集群搭建笔记 1.DolphinScheduler Cluster部署1.1 集群部署规划1.2 集群准备工作1.3 初始化数据库1.4 修改安装环境配置1.5 安装DolphinScheduler1.6 启停命令1.7 登录 DolphinScheduler UI 1.DolphinScheduler Cluster部署 分布式去中心化易扩展的工作流任务调度系…

CTF-Web习题:[HFCTF2021]Unsetme

题目链接&#xff1a;[HFCTF2021]Unsetme 解题思路 打开靶场发现是一段PHP源码 做一下代码审阅&#xff1a; <?php// Kickstart the framework $f3require(lib/base.php);//引入f3框架源码$f3->set(DEBUG,1);//f3对象设置DEBUG属性 if ((float)PCRE_VERSION<8.0)…

腾讯元宝上线“3D角色梦工厂”:快速生成专属3D角色!

7月16日&#xff0c;腾讯旗下大模型应用“腾讯元宝”上线“3D角色梦工厂”&#xff0c;允许用户通过上传一张五官清晰的正面头像&#xff0c;并选择不同的角色模板&#xff0c;迅速生成个人3D角色&#xff01; 技术特点 “3D角色梦工厂”将大模型生成技术与3D应用相结合&#…

JavaDS —— 二叉树

树的基本概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看 起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 树形结构中&#xff0c;子树之间不能有…

02线性表 - 链表

这里是只讲干货不讲废话的炽念&#xff0c;这个系列的文章是为了我自己以后复习数据结构而写&#xff0c;所以可能会用一种我自己能够听懂的方式来描述&#xff0c;不会像书本上那么枯燥和无聊&#xff0c;且全系列的代码均是可运行的代码&#xff0c;关键地方会给出注释^_^ 全…

十六、【机器学习】【监督学习】- 支持向量回归 (SVR)

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

GaussDB常见调优指南

文章目录 GaussDB常见调优指南一. Analyze 统计信息解析二. Explain 分布式计划解析三. 性能调优总体策略详解四. 性能调优之坏味道 SQL 识别五. 性能调优之好味道表定义六. 性能调优之 SQL 改写七. 性能调优之路径干预八. 性能调优之 Plan hint 运用九. 性能调优之 GUC 参数调…

C学习(数据结构)-->单链表习题

目录 一、环形链表 题一&#xff1a;环形链表 思路&#xff1a; 思考一&#xff1a;为什么&#xff1f; 思考二&#xff1a;快指针一次走3步、4步、......n步&#xff0c;能否相遇 step1&#xff1a; step2&#xff1a; 代码&#xff1a; 题二&#xff1a; 环形链表 I…

SAE J1939协议入门(一)

一、SAE J1939是什么 SAE J1939&#xff08;以下简称J1939&#xff09;是由汽车工程师协会&#xff08;SAE &#xff09;定义的标准&#xff0c;专门用于提供微处理器系统之间的串行数据通信。虽然CAN存在并且被广泛用于小型车辆&#xff0c;但J1939被设计为大型车辆复杂网络的…

深度挖掘行情接口:股票市场中的关键金融数据API接口解析

在股票市场里&#xff0c;存在若干常见的股票行情数据接口&#xff0c;每一种接口皆具备独特的功能与用途。以下为一些常见的金融数据 API 接口&#xff0c;其涵盖了广泛的金融数据内容&#xff0c;其中就包含股票行情数据&#xff1a; 实时行情接口 实时行情接口&#xff1a…

恒创科技:如何解决“服务器 IP 地址无法被找到”的错误

如何解决“服务器 IP 地址无法被找到”的错误?此错误通常出现在你的设备无法使用其分配的 IP 地址与网络服务器通信时。问题的来源可能多种多样&#xff0c;从简单的拼写错误到复杂的 DNS 和路由问题。以下是对“服务器 IP 地址无法找到”的常见原因以及可以采取的解决办法。 …

万界星空科技MES系统生产计划管理的功能

MES系统&#xff08;Manufacturing Execution System&#xff0c;制造执行系统&#xff09;的生产计划管理功能是其核心功能之一&#xff0c;旨在将企业的生产计划转化为实际的生产操作&#xff0c;并通过实时监控和调整来确保生产活动的顺利进行。以下是MES系统生产计划管理功…

SpringData JPA Mongodb 查询部分字段

JPA 网上用的好像不多&#xff0c;找了好多材料以后最终找了这个可行的方案&#xff1a; Query(fields "{tender_id:1,_id:0}")List<MGPltTender> findByTenderIdIsNotNull(PageRequest pageRequest); 调用&#xff1a; Sort sort Sort.by(popularType.getC…

【二维区域和检索-矩阵不可变】python刷题记录

一夜无解&#xff0c;痛苦&#xff0c;遂拜倒于灵神门下&#xff0c;妄做狂徒也&#xff01; . - 力扣&#xff08;LeetCode&#xff09; 灵神秒解如下&#xff1a; class NumMatrix:#二维初始矩阵def __init__(self, matrix: List[List[int]]):mlen(matrix)nlen(matrix[0])#…

vue和微信小程序的区别、比较

找到一篇很好的关于vue和小程序之间的理解文章&#xff0c;在此分享一下&#xff1a; 前端 - vue和微信小程序的区别、比较 - 个人文章 - SegmentFault 思否https://segmentfault.com/a/1190000015684864