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

ROS通信机制包括话题通信、服务通信和参数服务器三种通信方式,各原理及代码实现如下表

在这里插入图片描述

功能博客链接说明
VScode配置 ROS 环境VScode创建ROS项目 ROS集成开发环境使用VScode使用配置了ROS开发环境,实现ROS开发的第一步
话题通信理论ROS话题通信流程理论介绍了话题通信机制的原理
ROS话题通信机制实操C++ROS话题通信机制实操C++手把手的用C++实现了话题通信机制
ROS话题通信机制实操PythonROS话题通信机制实操Python手把手的用Python实现了话题通信机制
ROS话题通信流程自定义msg格式ROS话题通信流程自定义msg格式介绍了如何准备话题通信机制自定义msg数据格式,及相关配置
ROS话题通信机制自定义msg实战C++ROS话题通信机制自定义msg实战C++手把手的用C++实现了话题通信机制自定义msg数据通信
ROS话题通信机制自定义msg实战PythonROS话题通信机制自定义msg实战Python手把手的用Python实现了话题通信机制自定义msg数据通信
服务通信理论ROS服务通信流程理论介绍了服务通信机制的原理
ROS服务通信自定义srvROS服务通信自定义srv介绍了如何准备服务通信机制自定义srv数据格式,及相关配置
ROS服务通信机制实操C++ROS服务通信机制实操C++手把手的用C++实现了服务通信机制
ROS服务通信机制实操PythonROS服务通信机制实操Python手把手的用Python实现了话题通信机制
参数服务器理论ROS参数服务器理论模型介绍了参数服务器的原理
ROS参数服务器增删改查实操C++ROS参数服务器增删改查实操C++用 C++ 实现了参数服务器的的增删改查操作
ROS参数服务器增删改查实操PythonROS参数服务器增删改查实操Python用 Python 实现了参数服务器的的增删改查操作

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,失败为flase
        if(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,失败为flase
    if(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,失败为flase
    if(flag)
    {
        ROS_INFO("响应成功");
        ROS_INFO("响应结果:sum = %d", add.response.sum);
    }
    else
    {
        ROS_INFO("响应失败...");
    }
    
    return 0;
}

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

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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值