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

目录

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

通信流程

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目录下:

bash 复制代码
catkin_create_pkg service std_msgs rospy roscpp
catkin_create_pkg client std_msgs rospy roscpp

新建服务通讯文件

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

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

修改service的xml及cmakelist

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

bash 复制代码
  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

CMakeLists.txt编辑 msg 相关配置

bash 复制代码
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)

需要加入 message_generation,必须有 std_msgs

#配置 srv 源文件

bash 复制代码
add_service_files(
  FILES
  AddInts.srv
)

生成消息时依赖于 std_msgs

bash 复制代码
generate_messages(
  DEPENDENCIES
  std_msgs
)

#执行时依赖
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES demo02_talker_listener
  CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
#  DEPENDS system_lib
)

编译消息相关头文件

退回到ws目录,使用catkin_make --pkg service

编译出相关的三个头文件

在cmakelist中包含头文件的路径

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

bash 复制代码
include_directories(
# include
  ${catkin_INCLUDE_DIRS}
  "/root/work/ws/devel/include/"
)

在service包下编写service.cpp

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

cpp 复制代码
#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中:

bash 复制代码
add_executable(${PROJECT_NAME}_node src/service.cpp)
target_link_libraries(${PROJECT_NAME}_node
  ${catkin_LIBRARIES}
)

在service包下新增launch文件

bash 复制代码
<launch>
    <node name="myservice" pkg="service" type="service_node" output="screen"/>
</launch>

在client包下编写client.cpp

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");
    //等待服务启动成功
    //方式1
    ros::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中:

bash 复制代码
add_executable(${PROJECT_NAME}_node src/client.cpp)
target_link_libraries(${PROJECT_NAME}_node
  ${catkin_LIBRARIES}
)

在client包下新增launch文件

bash 复制代码
<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>

测试运行

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

查询服务的相关指令

列出目前的所有服务:

bash 复制代码
rosservice list

得到服务列表:

bash 复制代码
/mymessage
/myservice/get_loggers
/myservice/set_logger_level
/rosout/get_loggers
/rosout/set_logger_level

查询参数:

bash 复制代码
rosservice args /mymessage

输出:

bash 复制代码
a b

显示某包下的服务

bash 复制代码
rossrv package service

得出:

bash 复制代码
service/mymessage

显示服务消息的具体信息

bash 复制代码
rossrv show mymessage

得出具体信息

bash 复制代码
[service/mymessage]:
string a
string b
---
string ab
相关推荐
羊小猪~~4 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
撞南墙者7 分钟前
OpenCV自学系列(1)——简介和GUI特征操作
人工智能·opencv·计算机视觉
OCR_wintone4218 分钟前
易泊车牌识别相机,助力智慧工地建设
人工智能·数码相机·ocr
王哈哈^_^29 分钟前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt
一者仁心36 分钟前
【AI技术】PaddleSpeech
人工智能
是瑶瑶子啦44 分钟前
【深度学习】论文笔记:空间变换网络(Spatial Transformer Networks)
论文阅读·人工智能·深度学习·视觉检测·空间变换
EasyCVR1 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频
脉牛杂德1 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz1 小时前
STL--哈希
c++·算法·哈希算法
CSUC1 小时前
【C++】父类参数有默认值时子类构造函数列表中可以省略该参数
c++