• ROS节点通信(二)service和client


    1、说明

    ROS的节点通信模式有多种,本文介绍service-client模式

    本文的示例功能是计算 sum=a+b-c*n

    下文中功能包的创建步骤不再做详细介绍

    2、创建功能包

    仍然和前例使用同一个工作空间

    cd ~/projrct/catkin_ws/
    catkin_create_pkg test_service roscpp std_msgs message_generation
    

    这里还是显示指定依赖,避免后期修改编译配置

    3、自定义通信数据类型

    和 topic 模式不同的是,topic 使用msg文件声明类型,service-client使用srv文件声明类型

    cd test_service
    mkdir srv && cd srv
    touch TestData.srv
    

    编辑 TestData.srv 文件,如下:

    int32 a
    int32 b
    int32 c
    int32 n
    ---
    int64 sum
    

    service-client既然是一问一答模式,自然就需要request和response,这里的 --- 用于区分,必不可少

    这时候,可以先编译一下包,以方便后面写代码

    我们可以通过 rossrv 指令来检查自定义的类型是否被ROS识别了

    rossrv show test_service/TestData
    

    如果能打印出文件内容,表示已经被识别

    4、编写代码

    cd ~/project/catkin_ws/src/test_service/src
    touch service_node.cpp
    touch client_node.cpp
    

    service_node.cpp 代码如下:

    #include "ros/ros.h"
    #include "test_service/TestData.h"//自动生成的自定义类型头文件
    
    bool calc(test_service::TestData::Request &req, test_service::TestData::Response &res)
    {
        res.sum = req.a + req.b - req.c * req.n;
        ROS_INFO("recieve request: a=%d, b=%d, c=%d, n=%d", req.a, req.b, req.c, req.n);
        ROS_INFO("send response: sum=%ld", (long int)res.sum);
        return true;
    }
    
    int main(int argc, char **argv)
    {
        ros::init(argc, argv, "server_node");//初始化ROS节点,声明节点名称
        ros::NodeHandle handle;//声明一个ros节点句柄
    
        #创建服务,并讲服务加入到ROS网络中,在ROS网路中以calc作为唯一标识,其他节点使用此唯一标识进行请求
        ros::ServiceServer service = handle.advertiseService("calc", calc);
        ROS_INFO("service is ready!!!");
        ros::spin();
        return 0;
    }
    

    client_node.cpp 代码如下:

    #include "ros/ros.h"
    #include "test_service/TestData.h"
    
    int main(int argc, char **argv)
    {
        ros::init(argc, argv, "client_node");//初始化ROS节点,并声明节点名称
        ros::NodeHandle handle;
    
        //定义client,并指定需要请求的service,使用之前定义的唯一标识
        ros::ServiceClient client = handle.serviceClient<test_service::TestData>("calc");
        test_service::TestData testData;
    
        testData.request.a = 100;
        testData.request.b = 99;
        testData.request.c = 12;
        testData.request.n = 2;
        if (client.call(testData))//发起请求
        {
            ROS_INFO("sum=%ld", (long int)testData.response.sum);
        }
        else
        {
            ROS_INFO("failed to call service add_two_ints");
        }
        return 0;
    }
    

    5、编译配置

    查看一下 CMakeLists.txt 和 package.xml 中的关键项目

    5.1、CMakeLists.txt

    这里之列出一些关键项目

    #创建包时自动添加
    find_package(catkin REQUIRED COMPONENTS
      message_generation
      roscpp
      std_msgs
    )
    
    ## Generate services in the 'srv' folder
    #需要手动添加,由注释可知,srv文件需要放在srv文件夹下
    add_service_files(
      FILES
      TestData.srv
    )
    #创建包时自动添加,作用是自动创建自定义类型的代码文件,类型依赖std_msgs库
    generate_messages(
      DEPENDENCIES
      std_msgs
    )
    #手动添加,service-client模式需要生成两个二进制文件
    add_executable(${PROJECT_NAME}_service_node src/service_node.cpp)
    add_dependencies(${PROJECT_NAME}_service_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
    target_link_libraries(${PROJECT_NAME}_service_node
      ${catkin_LIBRARIES}
    )
    
    add_executable(${PROJECT_NAME}_client_node src/client_node.cpp)
    add_dependencies(${PROJECT_NAME}_client_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
    target_link_libraries(${PROJECT_NAME}_client_node
      ${catkin_LIBRARIES}
    )
    

    5.2、package.xml

    <?xml version="1.0"?>
    <package format="2">
        <name>test_service</name>
        <version>0.0.0</version>
        <description>The test_service package</description>
        <maintainer email="eco@todo.todo">eco</maintainer>
        <license>TODO</license>
        <buildtool_depend>catkin</buildtool_depend>
        <build_depend>message_generation</build_depend>
        <build_depend>roscpp</build_depend>
        <build_depend>std_msgs</build_depend>
        <build_export_depend>roscpp</build_export_depend>
        <build_export_depend>std_msgs</build_export_depend>
        <build_export_depend>message_generation</build_export_depend>
        <exec_depend>message_runtime</exec_depend>
        <exec_depend>roscpp</exec_depend>
        <exec_depend>std_msgs</exec_depend>
        <!-- The export tag contains other, unspecified, tags -->
        <export>
            <!-- Other tools can request additional information be placed here -->
        </export>
    </package>
    

    这里有三个依赖比较关键

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

    6、编译运行

    编译:

    catkin_make -DCATKIN_WHITELIST_PACKAGES="test_service"
    

    开启节点管理器

    roscore
    

    运行service节点

    cd ~/project/catkin_ws/
    source devel/setup.bash
    rosrun test_service test_service_service_node
    

    运行client节点

    cd ~/project/catkin_ws/
    source devel/setup.bash
    rosrun test_service test_service_client_node
    

    运行如下:

    rosrun test_service test_service_serviceode 
    [ INFO] [1620440457.958186943]: service is ready!!!
    [ INFO] [1620440460.409754974]: recieve request: a=100, b=99, c=12, n=2
    [ INFO] [1620440460.409789657]: send response: sum=175
    
    rosrun test_service test_service_client_node 
    [ INFO] [1620440460.410109766]: sum=175
    
  • 相关阅读:
    cocos2dx-lua捕获用户touch事件的几种方式
    Java并发编程之闭锁CountDownLatch简单介绍
    opencv视频播放
    完全备份、差异备份以及增量备份的区别
    如何实现文件增量同步——算法
    Oracle提示“资源正忙,需指定nowait”的解决方案
    oracle之报错:ORA-00054: 资源正忙,要求指定 NOWAIT
    一次oracle大量数据删除经历
    rownum的使用-分页
    sql语句分页多种方式ROW_NUMBER()OVER
  • 原文地址:https://www.cnblogs.com/sherlock-lin/p/14883531.html
Copyright © 2020-2023  润新知