ROS Service

在 ROS (Robot Operating System) 中,Service 是一种通信机制,允许节点之间进行同步的请求-响应交互。与 Publisher/Subscriber 模式不同,Service 提供了阻塞式调用,使客户端节点可以发起请求并等待服务器节点的响应。这种模式常用于需要即时响应的数据请求或指令的场景。

ROS Service 的工作原理

  • Server(服务器):一个 ROS 节点可以作为服务器提供某个 Service,并在接收到请求时执行相应操作。
  • Client(客户端):另一个节点可以作为客户端发起请求,向指定 Service 发送数据,并接收服务器的响应。

每个 Service 都包含一个请求和一个响应数据结构,通常在 .srv 文件中定义。请求和响应类型可以是基本数据类型(如 int32float64 等)或自定义的复杂类型。

1. ROS Service 的基本组成

一个 ROS Service 由以下几个部分组成:

  • Service 名称:用于标识服务,以便客户端和服务器能够匹配。
  • Request:客户端发送给服务器的数据。
  • Response:服务器处理后返回给客户端的结果。

2. 定义 ROS Service

在 ROS 中,我们使用 .srv 文件来定义 Service 的请求和响应数据格式。一个 .srv 文件通常包含两个部分:请求和响应,以 --- 分隔。

示例:定义一个求和的服务

首先我们先创建一个my_service的功能包,进入到自己的ros工作空间下面,执行:

catkin_create_pkg my_service roscpp std_msgs message_generation

在建立的功能包下再创建一个srv文件夹,用来存放“.srv”文件

假设我们想定义一个名为 AddTwoInts.srv 的服务,它接收两个整数并返回它们的和:

AddTwoInts.srv 文件内容:

int64 a
int64 b
---
int64 sum

在此示例中:

  • 请求部分(在 --- 之前):包含两个 int64 类型的整数 ab
  • 响应部分(在 --- 之后):包含一个 int64 类型的整数 sum,用于存储返回的和。

3. 实现 ROS Service 服务器端

服务器节点会创建服务并定义服务回调函数,当接收到请求时,该回调函数将被调用。

在功能包的src目录下我们创建一个add_two_ints_server.cpp文件

#include "ros/ros.h"
#include "my_service/AddTwoInts.h"  // 自动生成的头文件,包含服务类型

// 服务回调函数,接收请求和响应
bool add(my_service::AddTwoInts::Request &req,
         my_service::AddTwoInts::Response &res) {
    res.sum = req.a + req.b;  // 计算并返回和
    ROS_INFO("Request: a=%ld, b=%ld", (long int)req.a, (long int)req.b);
    ROS_INFO("Sending back response: [%ld]", (long int)res.sum);
    return true;
}

int main(int argc, char **argv) {
    ros::init(argc, argv, "add_two_ints_server");
    ros::NodeHandle n;

    // 创建服务
    ros::ServiceServer service = n.advertiseService("add_two_ints", add);
    ROS_INFO("Ready to add two ints.");
    ros::spin();

    return 0;
}
解释
  • advertiseService:注册并启动一个名为 "add_two_ints" 的服务。
  • add 函数:处理请求的回调函数。函数接收请求对象 req 和响应对象 res,并在响应对象中设置返回值。

4. 实现 ROS Service 客户端

客户端节点会发送请求并等待服务器的响应。

在功能包的src目录下我们创建一个add_two_ints_client.cpp文件

#include "ros/ros.h"
#include "my_service/AddTwoInts.h"
#include <cstdlib>

int main(int argc, char **argv) {
    ros::init(argc, argv, "add_two_ints_client");

    if (argc != 3) {
        ROS_INFO("usage: add_two_ints_client X Y");
        return 1;
    }

    ros::NodeHandle n;
    ros::ServiceClient client = n.serviceClient<my_service::AddTwoInts>("add_two_ints");

    my_service::AddTwoInts srv;
    srv.request.a = atoll(argv[1]);
    srv.request.b = atoll(argv[2]);

    if (client.call(srv)) {
        ROS_INFO("Sum: %ld", (long int)srv.response.sum);
    } else {
        ROS_ERROR("Failed to call service add_two_ints");
        return 1;
    }

    return 0;
}
解释
  • serviceClient:创建一个服务客户端,连接到 "add_two_ints" 服务。
  • srv.request:填充请求数据。
  • client.call(srv):调用服务并等待响应。调用成功时,响应值存储在 srv.response 中。

5. 启动 ROS Service 节点

编译和运行

假设项目目录结构如下:

my_service/
├── src/
│   ├── add_two_ints_server.cpp
│   └── add_two_ints_client.cpp
├── srv/
│   └── AddTwoInts.srv
└── CMakeLists.txt
└── package.xml

CMakeLists.txt 中添加以下配置:

find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
  message_generation
)

add_service_files(
  FILES
  AddTwoInts.srv
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

catkin_package(
  CATKIN_DEPENDS roscpp std_msgs message_runtime
)

add_executable(add_two_ints_server src/add_two_ints_server.cpp)
add_dependencies(add_two_ints_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})

add_executable(add_two_ints_client src/add_two_ints_client.cpp)
add_dependencies(add_two_ints_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})

检查package.xml,确保以下编译依赖项正确

<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>
<exec_depend>roscpp</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>message_generation</exec_depend>

编译和运行节点:

cd ~/catkin_ws           
catkin_make
source devel/setup.bash
roscore
rosrun my_service add_two_ints_server
rosrun my_service add_two_ints_client 5 10

一个终端先运行roscore启动ros master,另起一个终端开启service服务端:

再起一个终端开启客户端:

此时客户端就已经打印出了服务端返回的结果,服务端也打印了相应的log

这样就顺利完成了客户端的以此service请求。

6. Service 的典型应用场景

  • 查询和获取数据:当节点需要获取一次性的数据(如传感器状态、当前坐标等)时,可以通过 Service 请求获取。
  • 命令执行:可通过 Service 发起某种命令(如启动/停止某个过程)。
  • 调试和参数设置:可以使用 Service 在运行时动态调整节点参数。

7. 与 Topic 的区别

特性TopicService
通信方式发布-订阅(异步)请求-响应(同步)
通信频率通常用于高频率数据流(如传感器数据)通常用于低频率、即时响应需求
数据方向单向流数据(Publisher → Subscriber)双向传输(Client ↔ Server)
持久性持续通信请求-响应一次通信
使用场景数据流、监控等控制命令、数据查询等

总结

ROS Service 提供了一种便捷的请求-响应通信方式,适用于低频、请求即时处理的场景。通过 .srv 文件定义请求和响应结构,Service 提供了一种标准化的同步通信机制,可用于执行特定命令或获取数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值