目录

  • 1、说明
  • 2、创建功能包
  • 3、自定义通信数据类型
  • 4、编写代码
  • 5、编译配置
  • 5.1、CMakeLists.txt
  • 5.2、package.xml
  • 6、编译运行

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