跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++AI算法

ROS2 服务 Service Hello World 代码示例(C++ 版)

介绍 ROS2 中 Service 通信机制,基于调用 - 响应模型。通过 C++ 实现一个计算两整数之和的自定义服务,涵盖功能包创建、源文件编写、CMakeLists 配置、编译及节点运行步骤。

鲜活发布于 2026/3/26更新于 2026/6/633 浏览
ROS2 服务 Service Hello World 代码示例(C++ 版)

Service 通信流程图

每个服务只能有一个服务器,但可以有多个客户端。

一、Service 通讯机制

服务是 ROS 节点的另一种通信方式。服务基于调用 - 响应模型,而非主题的发布者 - 订阅者模型。主题允许节点订阅数据流并获取持续更新,而服务仅在客户端明确调用时才提供数据。

在 ROS 2 中,服务指的是远程过程调用。换句话说,一个节点可以对另一个节点进行远程过程调用,该节点将执行计算并返回结果。

在 ROS 2 中,由于客户端通常需要等待结果,因此服务应该能够快速返回。服务不应该用于长时间运行的进程,尤其是在异常情况下可能需要被抢占的进程。如果你的服务需要执行长时间运行的计算,请考虑使用 Action。

一个服务由两部分组成:服务器和客户端。

服务器是接受远程过程请求并执行某些计算的实体,客户端是一个请求远程服务器代替其执行计算的实体。

服务的执行流程如下图:

Service 执行流程

二、创建自定义服务 C++ 版

2.1 创建功能包

cd ros2_learning/src
ros2 pkg create --build-type ament_cmake hello_world_service_cpp

其中,

使用 --build-type 指定编译系统为 ament_cmake

hello_world_service_cpp:自定义功能包名称

生成的目录结构如下:

hello_world_service_cpp
├── CMakeLists.txt
├── include
│   └── hello_world_service_cpp
├── LICENSE
├── package.xml
└── src

2.2 编辑源文件

我们编写一个服务端(server)和一个客户端(client),实现计算两个整型数字的和。

在 hello_world_service_cpp/include 目录下新增 server.h 文件,文件内容如下:

#pragma once
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"

using AddTwoInts = example_interfaces::srv::AddTwoInts;

class AddTwoIntsServer : public rclcpp::Node {
public:
    AddTwoIntsServer();
private:
    void handle_add_two_ints(const std::shared_ptr<AddTwoInts::Request> request, 
                             std::shared_ptr<AddTwoInts::Response> response);
    rclcpp::Service<AddTwoInts>::SharedPtr service_;
};

在 hello_world_service_cpp/src 目录下新增 server.cpp 文件,文件内容如下:

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
#include "hello_world_service_cpp/server.h"

AddTwoIntsServer::AddTwoIntsServer() : Node("add_two_ints_server") {
    // 创建服务
    service_ = this->create_service<AddTwoInts>("add_two_ints", 
        std::bind(&AddTwoIntsServer::handle_add_two_ints, this, 
                  std::placeholders::_1, std::placeholders::_2));
    RCLCPP_INFO(this->get_logger(), "AddTwoInts 服务端已启动...");
}

void AddTwoIntsServer::handle_add_two_ints(
    const std::shared_ptr<AddTwoInts::Request> request, 
    std::shared_ptr<AddTwoInts::Response> response) {
    RCLCPP_INFO(this->get_logger(), "收到请求:%ld + %ld", request->a, request->b);
    response->sum = request->a + request->b;
    RCLCPP_INFO(this->get_logger(), "返回结果:%ld", response->sum);
}

int main(int argc, char** argv) {
    rclcpp::init(argc, argv);
    auto server = std::make_shared<AddTwoIntsServer>();
    rclcpp::spin(server);
    rclcpp::shutdown();
    return 0;
}

在 hello_world_service_cpp/include 目录下新增 client.h 文件,文件内容如下:

#pragma once
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
#include <chrono>

using namespace std::chrono_literals;
using AddTwoInts = example_interfaces::srv::AddTwoInts;

class AddTwoIntsClient : public rclcpp::Node {
public:
    AddTwoIntsClient();
    ~AddTwoIntsClient();
    bool send_request(int a, int b);
private:
    rclcpp::Client<AddTwoInts>::SharedPtr client_;
};

在 hello_world_service_cpp/src 目录下新增 client.cpp 文件,文件内容如下:

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
#include "hello_world_service_cpp/client.h"

AddTwoIntsClient::AddTwoIntsClient() : Node("add_two_ints_client") {
    client_ = this->create_client<AddTwoInts>("/add_two_ints");
}

AddTwoIntsClient::~AddTwoIntsClient() {}

bool AddTwoIntsClient::send_request(int a, int b) {
    // 等待服务端
    if (!client_->wait_for_service(5s)) {
        RCLCPP_ERROR(this->get_logger(), "等待服务端超时");
        return false;
    }
    auto request = std::make_shared<AddTwoInts::Request>();
    request->a = a;
    request->b = b;
    RCLCPP_INFO(this->get_logger(), "发送请求:%ld + %ld", request->a, request->b);
    auto result = client_->async_send_request(request);
    if (rclcpp::spin_until_future_complete(this->shared_from_this(), result) == 
        rclcpp::FutureReturnCode::SUCCESS) {
        auto response = result.get();
        RCLCPP_INFO(this->get_logger(), "计算结果:%ld", response->sum);
    } else {
        RCLCPP_ERROR(this->get_logger(), "请求失败");
    }
    return false;
}

int main(int argc, char** argv) {
    rclcpp::init(argc, argv);
    auto node = std::make_shared<AddTwoIntsClient>();
    if (argc >= 3) {
        int a = std::stoi(argv[1]);
        int b = std::stoi(argv[2]);
        RCLCPP_INFO(node->get_logger(), "请求参数:%d + %d", a, b);
        node->send_request(a, b);
    }
    rclcpp::shutdown();
    return 0;
}

2.3 编辑编译配置文件 CMakeLists.txt

默认生成的 CMakeLists.txt 文件内容如下:

CMakeLists.txt 默认内容

由于新增了 server 和 client,所以要配置该文件的编译规则。

找到 ros2_learning/src/hello_world_service_cpp/CMakeLists.txt,修改如下:

CMakeLists.txt 修改说明

修改说明如下:

find_package(rclcpp REQUIRED)
find_package(example_interfaces REQUIRED)

# 指定头文件目录
include_directories(include)

# 指定源文件,生成可执行文件
add_executable(add_two_ints_server src/server.cpp)
# 指定可执行文件的依赖项
ament_target_dependencies(add_two_ints_server rclcpp example_interfaces)

add_executable(add_two_ints_client src/client.cpp)
ament_target_dependencies(add_two_ints_client rclcpp example_interfaces)

# 定义安装规则,指定可执行文件的安装目录
install(TARGETS add_two_ints_server add_two_ints_client DESTINATION lib/${PROJECT_NAME})

# 添加 ament 依赖导出
ament_export_dependencies(rclcpp)
ament_export_dependencies(example_interfaces)

2.4 编译工程

进入到工作空间 ros2_learning 目录,执行如下指令编译该工程:

colcon build

2.5 运行节点

ROS2 提供了 run 命令,可以根据包名和节点名,在任何目录执行。

但需要先设置环境变量,即让系统可以找到节点,进入到工作空间目录,执行如下指令:

source install/setup.bash

执行如下命令分别启动服务端和客户端节点:

ros2 run hello_world_service_cpp add_two_ints_server
ros2 run hello_world_service_cpp add_two_ints_client 3 7

启动节点后,打印如下:

运行结果

目录

  1. 一、Service 通讯机制
  2. 二、创建自定义服务 C++ 版
  3. 2.1 创建功能包
  4. 2.2 编辑源文件
  5. 2.3 编辑编译配置文件 CMakeLists.txt
  6. 指定头文件目录
  7. 指定源文件,生成可执行文件
  8. 指定可执行文件的依赖项
  9. 定义安装规则,指定可执行文件的安装目录
  10. 添加 ament 依赖导出
  11. 2.4 编译工程
  12. 2.5 运行节点
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • llama-cpp-python 完整安装与配置指南
  • LLaMA Factory 微调时报 disable multiprocessing 错误解决
  • Win11 本地部署 OpenClaw 并通过 WSL 实现飞书机器人功能
  • Ever Gauzy 开源商业管理平台概览
  • CentOS 7 系统安装 Docker CE 详解
  • 图论算法精讲:核心概念、存储与例题
  • 双指针算法实战:移动零与复写零详解
  • ToDesk 内置 ToClaw AI 实现科技新闻日报自动化实战
  • Go 语言快速入门与核心要点总结
  • Spring Cloud 熔断降级详解:Sentinel 实战指南
  • AI 大模型基础认知:从入门原理到行业赋能
  • OpenClaw 接入自定义模型并通过 WebUI 实现智能操作
  • C++ 技巧:明确拒绝编译器自动生成的拷贝函数
  • 大模型提示词工程核心技巧与实战应用指南
  • Python 基于人脸识别的自习室座位预约系统
  • Spring Cloud Gateway 网关核心原理与使用指南
  • 2024 Java 生态系统趋势分析:版本、JDK 与 GC 现状
  • 从人类视频到机器人跳舞:BeyondMimic 全流程解析与 rl_sar 部署实践
  • 解决 PKIX path building failed:SSL 证书导入 Java 信任库实战
  • WorkBuddy 接入 QQ 机器人配置指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online