ROS 的 服务机制(Service) 是一种 同步的请求-响应通信方式 ,类似于 RPC(Remote Procedure Call,远程过程调用) 。
它通常用于 一次性请求 + 返回结果的场景,比如:
机器人请求地图服务器加载地图
请求计算某个结果(例如两个数相加)
请求机器人执行某个动作并返回结果
和 Topic(发布/订阅) 不同,Service 是 一对一 + 同步通信。
一、ROS通信方式整体结构
在 ROS 中主要有 三种通信机制:
| 通信方式 | 特点 | 使用场景 |
|---|---|---|
| Topic | 异步、发布订阅 | 传感器数据、控制指令 |
| Service | 同步、请求响应 | 计算请求、状态查询 |
| Action | 长时间任务 | 导航、机械臂动作 |
二、Service 的核心组成
ROS Service 由 三部分组成:
Service
├── Service Server(服务端)
├── Service Client(客户端)
└── Service Message(srv文件)
Service Server(服务端)
服务器负责:
接收客户端请求
执行计算
返回结果
Service Client(客户端)
调用服务的一方
客户端会:
- 发送请求
- 等待服务器处理
- 接收返回值
Service Message(srv 文件)
Service 使用 .srv 文件定义通信格式
格式:
Request
Response
示例:
int64 a
int64 b
int64 sum
含义:
客户端发送:
a
b
服务器返回:
sum
三、Service 工作流程(核心)
完整流程如下:
Client Server
| |
|----- request (a,b) ---------->|
| |
| 执行计算
| |
|<------ response (sum) ------|
| |
详细步骤:
第一步:Server 注册服务
服务端启动:
cpp
ros::ServiceServer service = nh.advertiseService(...)
此时会向 ROS Master 注册
第二步:Client 查询服务
客户端调用:
cpp
client = nh.serviceClient(...)
Client 会向 ROS Master 查询
/add_two_ints 在哪里?
Master 返回:
Service Server 地址
第三步:建立 TCP 连接
ROS 使用:TCPROS
客户端与服务器 建立 TCP 连接。
第四步:发送 Request
客户端发送:
a
b
第五步:Server 处理请求
Server 执行回调函数:
cpp
bool add(Request &req, Response &res)
{
res.sum = req.a + req.b;
}
第六步:返回 Response
Server 返回:sum
客户端收到结果
四、Service 通信结构(底层)
ROS Service 的底层是:
TCP + ROS 序列化
通信流程:
Client
|
| 1 查询服务
v
ROS Master
|
| 2 返回Server地址
v
Client <----TCP----> Server
Request
Response
注意:
ROS Master 不参与实际数据通信
它只负责:服务发现
五、Service 的特点
同步通信
调用服务时:client.call()
一对一通信
Service 只能:
一个 Client -> 一个 Server
不像 Topic 可以:
多个 subscriber
适合短任务
Service 不适合:
长时间任务
例如:
导航
机械臂抓取
这些应该用 Action。
六、Service 的代码结构(C++)
服务端
cpp
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
bool add(beginner_tutorials::AddTwoInts::Request &req,
beginner_tutorials::AddTwoInts::Response &res)
{
res.sum = req.a + req.b;
return true;
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "add_two_ints_server");
ros::NodeHandle nh;
ros::ServiceServer service =
nh.advertiseService("add_two_ints", add);
ros::spin();
return 0;
}
客户端
cpp
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "add_two_ints_client");
ros::NodeHandle nh;
ros::ServiceClient client =
nh.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
beginner_tutorials::AddTwoInts srv;
srv.request.a = 1;
srv.request.b = 2;
if(client.call(srv))
{
ROS_INFO("sum: %ld", srv.response.sum);
}
return 0;
}