当前位置 博文首页 > 自定义srv调用实现(C++)_txr152111的博客:16th 服务通信

    自定义srv调用实现(C++)_txr152111的博客:16th 服务通信

    作者:[db:作者] 时间:2021-09-01 22:11

    15th 服务通信自定义srv | 生成头文件

    一、目标及分析

    目标:

    编写服务通信,客户端提交两个整数至服务端,服务端求和并响应结果到客户端。

    分析:

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

    1. 服务端
    2. 客户端
    3. 数据

    二、实现方法(C++)

    2.0 配置VSCode

    不配置也是可以的,但是不能再vscode中代码自动补齐,且导报时VSCode会报错,但是不影响最终程序的运行,建议配置。

    ?

    ?使用pwd获得到路径。

    添加路径:

    2.1? 服务器端

    2.1.1新建文件

    #include<ros/ros.h>
    #include<plumbing_server_client/Addints.h>
    /*
            服务端实现:解析客户端提交的数据,并运算再返回相应
            1.包含头文件
            2.初始化ros节点
            3.创建节点句柄
            4.创建一个服务对象
            5.处理并产生相应
            6.spin()
    */
    bool doNum(plumbing_server_client::Addints::Request &request,
                                plumbing_server_client::Addints::Response &response)
    {
        //1.处理请求
        int num1 = request.num1;
        int num2 = request.num2;
        ROS_INFO("收到的请求数据:num1 = %d,num2 = %d",num1,num2);
        //2.组织响应
        int sum = num2+num1;
        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,"gongsi");   //设置节点名,为gongsi
            // 3.创建节点句柄
            ros::NodeHandle nh;
            // 4.创建一个服务对象
            ros::ServiceServer  server = nh.advertiseService("AddInts",doNum);
            ROS_INFO("服务器端已启动");
            // 5.处理并产生相应
            // 6.spin()
            ros::spin();
    
            return 0;
    }

    2.1.2服务器端的配置

    在CMakelist.txt文件中:

    2.1.3编译及测试

    编译:Ctrl + Shift + B

    rosservice? call? AddInts? ?Tab键补齐

    ?2.2 客户端

    2.2.1 新建文件

    #include<ros/ros.h>
    #include<plumbing_server_client/Addints.h>
    /*
        客户端:提交两个整数,并处理响应的结果(打印出来即可)
            1.包含头文件
            2.初始化ros节点
            3.创建节点句柄
            4.创建一个客户端对象
            5.提交请求并处理相应
    
            没有回调函数,spin()就可有可无了
    
    */
    int main(int argc, char  *argv[])
    {
        setlocale(LC_ALL,"");
            // 2.初始化ros节点
        ros::init(argc,argv,"DaBao");
            // 3.创建节点句柄
        ros::NodeHandle nh;
            // 4.创建一个客户端对象
        ros::ServiceClient client = nh.serviceClient<plumbing_server_client::Addints>("AddInts");
            // 5.提交请求并处理相应
                //5.1组织请求
        plumbing_server_client::Addints ai;
         ai.request.num1 = 100;
         ai.request.num2 = 200;
                //5.2处理响应
        client.call(ai);
        bool flag = client.call(ai);
        if (flag = true)
          {
              ROS_INFO("响应成功!");
              ROS_INFO("响应结果=%d",ai.response.sum);
          }
        else
          {
              ROS_INFO("处理失败!");
          }   
        return 0;
    
        
    }
    
    

    2.2.2 配置

    CMakelists.txt文件中:

    2.2.3 编译并测试

    ?编译:Ctrl + Shift + B

    ?测试:

    2.2.4 客户端的优化——参数的动态提交

    这上面的例程中,num1和num2都是固定死的,如何实现那种任意输入的参数呢,实现参数的动态提交。格式: rosrun ?包名 ?节点名 ?num1 ?num2

    #include<ros/ros.h>
    #include<plumbing_server_client/Addints.h>
    /*
        客户端:提交两个整数,并处理响应的结果(打印出来即可)
            1.包含头文件
            2.初始化ros节点
            3.创建节点句柄
            4.创建一个客户端对象
            5.提交请求并处理相应
    
            没有回调函数,spin()就可有可无了
    
        
        实现参数的动态提交:
                1.格式: rosrun  包名  节点名  num1  num2
                2.节点执行时,需要获取命令中的参数,并赋值入request
    */
    int main(int argc, char  *argv[])
    {
        setlocale(LC_ALL,"");
    
        //优化实现,获取命令中的参数
        if (argc != 3)
        {
            ROS_INFO("提交的参数个数不对");
            return 1;
        }
    
            // 2.初始化ros节点
        ros::init(argc,argv,"DaBao");
            // 3.创建节点句柄
        ros::NodeHandle nh;
            // 4.创建一个客户端对象
        ros::ServiceClient client = nh.serviceClient<plumbing_server_client::Addints>("AddInts");
            // 5.提交请求并处理相应
                //5.1组织请求
        plumbing_server_client::Addints ai;
         ai.request.num1 = atoi(argv[1]);
         ai.request.num2 = atoi(argv[2]);   //atoi,将字符串类型转换为整数类型
                //5.2处理响应
        client.call(ai);
        bool flag = client.call(ai);
        if (flag = true)
          {
              ROS_INFO("响应成功!");
              ROS_INFO("响应结果=%d",ai.response.sum);
          }
        else
          {
              ROS_INFO("处理失败!");
          }   
        return 0;
    
        
    }
    
    

    ?运行测试:

    ?3.思考题

    如果先启动客户端,那么会导致运行失败,但是现在就需要先启动客户端,并且要求正常挂起,如何实现?

    优化:

    在客户端发送请求前添加:client.waitForExistence();

    或:ros::service::waitForService("AddInts");? ?需要传一个参数,为服务的话题名。

    这是一个阻塞式函数,只有服务启动成功后才会继续执行

    此处可以使用 launch 文件优化,但是需要注意 args 传参特点

    ?

    cs