【自动驾驶】ROS中自定义格式的服务通信,含命令行动态传参(c++)

server/2024/9/25 21:21:08/

目录

  • 通信流程
  • 创建服务器端及客户端
  • 新建服务通讯文件
  • 修改service的xml及cmakelist
  • CMakeLists.txt编辑 msg 相关配置
  • 编译消息相关头文件
  • 在cmakelist中包含头文件的路径
  • 在service包下编写service.cpp
  • 在client包下编写client.cpp
  • 测试运行
  • 查询服务的相关指令
    • 列出目前的所有服务:
    • 查询参数:
    • 显示某包下的服务
    • 显示服务消息的具体信息

服务通信是基于请求产生的通信。

通信流程

0.Server注册
Server 启动后,会通过RPC在 ROS Master 中注册自身信息,其中包含提供的服务的名称。ROS Master 会将节点的注册信息加入到注册表中。

1.Client注册
Client 启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要请求的服务的名称。ROS Master 会将节点的注册信息加入到注册表中。

2.ROS Master实现信息匹配
ROS Master 会根据注册表中的信息匹配Server和 Client,并通过 RPC 向 Client 发送 Server 的 TCP 地址信息。

3.Client发送请求
Client 根据步骤2 响应的信息,使用 TCP 与 Server 建立网络连接,并发送请求数据。

4.Server发送响应
Server 接收、解析请求的数据,并产生响应结果返回给 Client。

注意:

1.客户端请求被处理时,需要保证服务器已经启动;

2.服务端和客户端都可以存在多个。

创建服务器端及客户端

cd 到ws/src目录下:

catkin_create_pkg service std_msgs rospy roscpp
catkin_create_pkg client std_msgs rospy roscpp

新建服务通讯文件

在服务端的src目录下,新建srv文件夹,并在内新建mymessage.srv

# 客户端请求时发送的两个数字
string a
string b
#客户端发送与服务端响应,中间使用---进行隔开,这里是简单把两个string拼接在一起
---
# 服务器响应发送的数据
string ab

修改service的xml及cmakelist

package.xml中添加编译依赖与执行依赖

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

CMakeLists.txt编辑 msg 相关配置

find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsmessage_generation
)

需要加入 message_generation,必须有 std_msgs

#配置 srv 源文件

add_service_files(FILESAddInts.srv
)

生成消息时依赖于 std_msgs

generate_messages(DEPENDENCIESstd_msgs
)#执行时依赖
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES demo02_talker_listenerCATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

编译消息相关头文件

退回到ws目录,使用catkin_make --pkg service
编译出相关的三个头文件
在这里插入图片描述

在cmakelist中包含头文件的路径

新生成的.h文件位于devel/include文件夹下,在请求及响应方的cmakelist中添加:

include_directories(
# include${catkin_INCLUDE_DIRS}"/root/work/ws/devel/include/"
)

在service包下编写service.cpp

服务端的功能主要是将收到的两个string连接起来。


#include "ros/ros.h"
#include "service/mymessage.h"
#include <string>
// bool 返回值由于标志是否处理成功
bool doReq(service::mymessage::Request& req,service::mymessage::Response& resp){std::stringstream ss;ss<<std::string(req.a)<<std::string(req.b);ROS_INFO("拼好的字符串:%s",ss.str().c_str());resp.ab = ss.str();return true;
}int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// 2.初始化 ROS 节点ros::init(argc,argv,"testServer");// 3.创建 ROS 句柄ros::NodeHandle nh;// 4.创建服务以及注册回调函数ros::ServiceServer server = nh.advertiseService("mymessage",doReq);ROS_INFO("服务已经启动....");//     5.回调函数处理请求并产生响应//     6.由于请求有多个,需要调用 ros::spin()ros::spin();return 0;
}

同时在cmakelist中:

add_executable(${PROJECT_NAME}_node src/service.cpp)
target_link_libraries(${PROJECT_NAME}_node${catkin_LIBRARIES}
)

在service包下新增launch文件

<launch><node name="myservice" pkg="service" type="service_node" output="screen"/>
</launch>

在client包下编写client.cpp


// 1.包含头文件
#include "ros/ros.h"
#include "service/mymessage.h"int main(int argc, char *argv[])
{setlocale(LC_ALL,"");// argv[0]:指向程序名称 ./program 的字符串指针// argv[1]:指向 arg1 的字符串指针// argv[2]:指向 arg2 的字符串指针// 调用时动态传值,如果通过 launch 的 args 传参,需要传递的参数个数 +3,//launch 传参(0-文件路径 1传入的参数 2传入的参数 3节点名称 4日志路径)if (argc != 5){ROS_INFO("argc=(%d)",argc);ROS_ERROR("请提交两个字符串");return 1;}// 2.初始化 ROS 节点ros::init(argc,argv,"testClient");// 3.创建 ROS 句柄ros::NodeHandle nh;// 4.创建 客户端 对象ros::ServiceClient client = nh.serviceClient<service::mymessage>("mymessage");//等待服务启动成功//方式1ros::service::waitForService("mymessage");//方式2// client.waitForExistence();// 5.组织请求数据service::mymessage ai;//直接输入命令行的字符串ai.request.a = argv[1];ai.request.b = argv[2];// 6.发送请求,返回 bool 值,标记是否成功bool flag = client.call(ai);// 7.处理响应if (flag){ROS_INFO("请求正常处理,响应结果:%s",ai.response.ab.c_str());}else{ROS_ERROR("请求处理失败....");return 1;}return 0;
}

同时在cmakelist中:

add_executable(${PROJECT_NAME}_node src/client.cpp)
target_link_libraries(${PROJECT_NAME}_node${catkin_LIBRARIES}
)

在client包下新增launch文件

<launch><arg name="a" default="empty"/><arg name="b" default="empty"/><node name="myclient" pkg="client" type="client_node" args="$(arg a) $(arg b)" output="screen"/>
</launch>

测试运行

source /root/work/ws/devel/setup.bash
roslaunch service start.launch 
#通过如下命令行的形式传入参数,launch文件中使用$(arg a)引用参数的值
roslaunch client start.launch a:=abcd b:=5678

在这里插入图片描述

查询服务的相关指令

列出目前的所有服务:

rosservice list

得到服务列表:

/mymessage
/myservice/get_loggers
/myservice/set_logger_level
/rosout/get_loggers
/rosout/set_logger_level

查询参数:

rosservice args /mymessage

输出:

a b

显示某包下的服务

rossrv package service

得出:

service/mymessage

显示服务消息的具体信息

rossrv show mymessage

得出具体信息

[service/mymessage]:
string a
string b
---
string ab

http://www.ppmy.cn/server/98534.html

相关文章

初步认识二叉树

二叉树的概念及结构 二叉树在我们的想象中长这样 下图是满二叉树 二叉树有左右子树 1是根结点&#xff0c; 1的左子树是2&#xff0c;右子树是3&#xff1b; 2是根结点&#xff0c; 2的左子树是4&#xff0c;右子树是5&#xff1b; 3是根结点&#xff0c; 3的左子树是6…

【Linux基础】Linux基本指令(二)

目录 &#x1f680;前言一&#xff0c;mv指令二&#xff0c;more & less指令2.1 more 指令2.1 less指令 三&#xff0c;重定向技术(重要)3.1 echo指令3.2 输出重定向 >3.3 追加重定向 >>3.4 输入重定向 < 四&#xff0c;head & tail指令4.1 head 指令4.2 t…

FPGA常见型号

FPGA&#xff08;现场可编程门阵列&#xff09;开发板种类繁多&#xff0c;涵盖了从入门级教育用途到高性能工业应用的广泛领域。以下是一些常见的 FPGA 开发板型号及其特点&#xff1a; 1. Xilinx&#xff08;赛灵思&#xff09;系列 Xilinx 是 FPGA 领域的领导者之一&#…

BugKu CTF Misc:眼见非实 啊哒 ping Snowfall

前言 BugKu是一个由乌云知识库&#xff08;wooyun.org&#xff09;推出的在线漏洞靶场。乌云知识库是一个致力于收集、整理和分享互联网安全漏洞信息的社区平台。 BugKu旨在提供一个实践和学习网络安全的平台&#xff0c;供安全爱好者和渗透测试人员进行挑战和练习。它包含了…

Windows下搭建Telegraf+Influxdb+Grafana(详解一)

InfluxDB&#xff08;时序数据库&#xff09;&#xff0c;常用使用场景&#xff1a;监控数据统计。 grafana&#xff0c;用作监控页面的前端展示。 telegraf&#xff0c;数据采集器。 所有的安装包都上传到网盘 链接: https://pan.baidu.com/s/1Lv6UnfueK7URx7emAatoYg 提取…

qt中调色板索引图像文件转换成cv:Mat格式

如果你的 QImage 使用的是 QImage::Format_Indexed8 格式&#xff0c;这意味着图像是一个 8 位的索引图像。每个像素值是一个 8 位的索引&#xff0c;用于查找调色板中的颜色。这种格式通常用于调色板索引的图像&#xff0c;并且需要一个额外的调色板来解码实际的颜色信息。 在…

poetry配置镜像

1.简介 poetry 是一个包管理和打包的工具。 在 Python 中&#xff0c;对于初学者来说&#xff0c;打包系统和依赖管理是非常复杂和难懂的。即使对于经验丰富的开发者&#xff0c;一个项目总是要同时创建多个文件&#xff1a; setup.py ,requirements.txt,setup.cfg , MANIFES…

有关OmniFocus的几个问题

一位学员向我提了几个有关OmniFocus的问题&#xff0c;我进行了解答&#xff0c;给大家分享一下。 问题&#xff08;一&#xff09; 我们要尽快和尽少地花费时间资源去处理任务&#xff0c;那是不是任务排程时就要制定规则。我有个规则&#xff0c;事前三问。这件事有无价值&am…