• ROS三种通信方式之服务通信


    一、服务通信的理论模型

    服务通信也是ROS中一种极其常用的通信模式,服务通信是基于请求响应模式的,是一种应答机制。也即: 一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A。就像是服务器与客户端,客户端发出请求,服务器给出响应。

    在该模型中存在三个角色,管理者Master,客户端Client,服务端Server

    在这里插入图片描述

    Talker其实也是一个服务器,他为客户端的请求做出响应。

    二、服务通信自定义srv

    服务通信中,数据分成两部分,请求与响应,在 srv 文件中请求和响应使用---分割,具体实现如下:

    功能包下新建 srv 目录,添加 addNums.srv 文件,内容:

    # 客户端请求时发送的两个数字
    int32 num1
    int32 num2
    ---
    # 服务器响应发送的数据
    int32 sum
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

      <build_depend>message_generationbuild_depend>
      <exec_depend>message_runtimeexec_depend>
    
    • 1
    • 2

    CMakeLists.txt编辑 srv 相关配置

    find_package(catkin REQUIRED COMPONENTS
      roscpp
      rospy
      std_msgs
      message_generation
    )
    
    add_service_files(
      FILES
      addNums.srv
    )
    
    generate_messages(
      DEPENDENCIES
      std_msgs
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    我们编译一下发现可以编译成功那基本代表着配置成功了

    三、C++编码实现

    3.1、实现服务端

    #include "ros/ros.h"
    #include "Server_Client_test/addNum.h"
    
    bool doReq (Server_Client_test::addNum::Request& req,Server_Client_test::addNum::Response& res) {
        res.sum = req.num1 + req.num2;
        return true;
    }
    
    int main(int argc, char *argv[]) {
    
        setlocale(LC_ALL,"");
        // 2.初始化 ROS 节点
        ros::init(argc,argv,"addNum_Server");
        // 3.创建 ROS 句柄
        ros::NodeHandle nh;
        // 4.创建 服务 对象
        ros::ServiceServer server = nh.advertiseService("addNum",doReq);
        // 5.回调函数处理请求并产生响应
        // 6.由于请求有多个,需要调用 ros::spin()
        ros::spin();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3.2、实现客户端

    #include "ros/ros.h"
    #include "Server_Client_test/addNum.h"
    
    int main(int argc, char *argv[]) {
        ros::init(argc,argv,"Client_test");
        ros::NodeHandle nh;
        ros::ServiceClient c = nh.serviceClient<Server_Client_test::addNum>("addNum");
        Server_Client_test::addNum addNum;
        addNum.request.num1 = 1;
        addNum.request.num2 = 2;
        bool flah = c.call(addNum);
        if (flah) {ROS_INFO("答案是%d\n",addNum.response.sum);}
        else {ROS_ERROR("无法解析答案");}
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.3、运行服务器

    # 编译,这里我们需要配置配置文件,配置文件之前我们已经多次配置,这里不在重复
    catkin_make
    
    # 运行服务端
    rosrun Server_Client_test Server_test
    # 运行客户端
    rosrun Server_Client_test Client_test
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    四、服务通信相关命令rosservice && rossrv

    rosservice args    打印服务参数
    rosservice call    使用提供的参数调用服务
    rosservice find    按照服务类型查找服务
    rosservice info    打印有关服务的信息
    rosservice list    列出所有活动的服务
    rosservice type    打印服务类型
    rosservice uri     打印服务的 ROSRPC uri
    
    rossrv show        显示服务消息详情
    rossrv info        显示服务消息相关信息
    rossrv list        列出所有服务信息
    rossrv md5         显示 md5 加密后的服务消息
    rossrv package     显示某个包下所有服务消息
    rossrv packages    显示包含服务消息的所有包
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.1、rosservice list

    列出所有活动的 service

    4.2、osservice args

    打印服务参数

    rosservice args /spawn
    x y theta name
    
    • 1
    • 2

    4.3、rosservice call

    调用服务

    为小乌龟的案例生成一只新的乌龟

    rosservice call /spawn "x: 1.0
    y: 2.0
    theta: 0.0
    name: 'xxx'"
    name: "xxx"
    
    //生成一只叫 xxx 的乌龟
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4.4、rossrv list

    会列出当前 ROS 中的所有 srv 消息

    4.5、rossrv packages

    列出包含服务消息的所有包

    4.6、rossrv package

    列出某个包下的所有msg

    //rossrv package 包名 
    rossrv package turtlesim
    
    • 1
    • 2

    4.7、rossrv show

    显示消息描述

    //rossrv show 消息名称
    rossrv show turtlesim/Spawn
    
    float32 x
    float32 y
    float32 theta
    string name
    ---
    string name
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    五、控制小乌龟实例

    编码实现向 turtlesim 发送请求,在乌龟显示节点的窗体指定位置生成一乌龟,这是一个服务请求操作。

    获取话题:/spawn

    rosservice list
    Copy
    
    • 1
    • 2

    **获取消息类型:**turtlesim/Spawn

    rosservice type /spawn
    Copy
    
    • 1
    • 2

    获取消息格式:

    rossrv info turtlesim/Spawn
    Copy
    
    • 1
    • 2

    响应结果:

    float32 x
    float32 y
    float32 theta
    string name
    ---
    string name
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    编写cpp文件

    #include "ros/ros.h"
    #include "turtlesim/Spawn.h"
    
    
    int main(int argc, char *argv[]) {
        setlocale(LC_ALL,"");
        // 2.初始化 ros 节点
        ros::init(argc,argv,"Test_turtle_creat");
        // 3.创建 ros 句柄
        ros::NodeHandle nh;
        // 4.创建 service 客户端
        ros::ServiceClient client = nh.serviceClient<turtlesim::Spawn>("/spawn");
        // 5.等待服务启动
        // client.waitForExistence();
        ros::service::waitForService("/spawn");
        // 6.发送请求
        turtlesim::Spawn spawn;
        spawn.request.x = 1.0;
        spawn.request.y = 1.0;
        spawn.request.theta = 1.57;
        spawn.request.name = "my_turtle";
        bool flag = client.call(spawn);
        // 7.处理响应结果
        if (flag) {
            ROS_INFO("新的乌龟生成,名字:%s",spawn.response.name.c_str());
        } else {
            ROS_INFO("乌龟生成失败!!!");
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    编译后执行,这里我们需要注意一点就是,我们这个功能包需要添加turtlesim这个包的依赖,否则我们无法获取消息格式。

    # 运行乌龟节点
    rosrun turtlesim turtlesim_node
    
    # 运行生成乌龟的节点
    rosrun Server_Client_test Test_turtle_creat
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    为什么你应该聘请前端开发人员
    国产操作系统之中科方德桌面系统安装
    Java 8新特性
    【论文阅读】 Dimensionality reduction for large-scale neural recordings
    javaIO流01:文件,创建文件三种方式,获取文件相关信息,目录操作
    龙蜥白皮书精选:龙蜥安全漏洞管理体系介绍
    Gamba:将高斯溅射与Mamba结合用于单视图3D重建
    可验证的idea才是真的
    一篇搞懂Java基础流程语句
    小代码 - Python 读取iOS导出照片,修改名称为照片拍摄时间
  • 原文地址:https://blog.csdn.net/weixin_43903639/article/details/126258062