编写简单的服务和客户端
创建新的包
lxg@lxg:~/code/ROS2/workspace/demo/src$ ros2 pkg create --build-type ament_cmake cpp_srvcli --dependencies rclcpp example_interfaces
going to create a new package
package name: cpp_srvcli
destination directory: /home/lxg/code/ROS2/workspace/demo/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['lxg <xiaogang.li>']
licenses: ['TODO: License declaration']
build type: ament_cmake
dependencies: ['rclcpp', 'example_interfaces']
creating folder ./cpp_srvcli
creating ./cpp_srvcli/package.xml
creating source and include folder
creating folder ./cpp_srvcli/src
creating folder ./cpp_srvcli/include/cpp_srvcli
creating ./cpp_srvcli/CMakeLists.txt
lxg@lxg:~/code/ROS2/workspace/demo/src$ ls /opt/ros/humble/include/example_interfaces/example_interfaces/srv/
add_two_ints.h add_two_ints.hpp detail set_bool.h set_bool.hpp trigger.h trigger.hpp
编写服务端代码
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
#include <memory>
// 文件说明:
// 这是一个最小的 ROS2 服务端示例,提供名为 `add_two_ints` 的服务。
// 服务类型为 `example_interfaces::srv::AddTwoInts`,接收两个整数 `a` 和 `b`,
// 返回它们的和 `sum`。示例展示了如何定义服务回调、创建服务并进入事件循环。
// 服务回调函数:处理来自客户端的请求并填充响应
// 参数:
// - request: 指向请求消息的共享指针,包含请求字段 `a` 和 `b`(要相加的两个整数)
// - response: 指向响应消息的共享指针,回调应设置 `response->sum` 字段
void add(const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request,
std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response)
{
// 计算和并写入响应对象
response->sum = request->a + request->b;
// 打印接收到的请求到日志,便于调试
// 注意:使用 `%ld` 打印 long int,取决于平台上整数类型的大小
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Incoming request\na: %ld" " b: %ld",
request->a, request->b);
// 打印返回的响应值
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "sending back response: [%ld]", (long int)response->sum);
}
int main(int argc, char **argv)
{
// 初始化 ROS 2 客户端库(必须在程序开始时调用)
rclcpp::init(argc, argv);
// 创建一个名为 "add_two_ints_server" 的节点实例
// `make_shared` 返回节点的共享指针,便于与 `spin` 一起使用
std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_server");
// 创建服务:
// - 模板参数:服务的类型 `example_interfaces::srv::AddTwoInts`
// - 第一个参数:服务名 "add_two_ints",客户端将使用该名称进行调用
// - 第二个参数:回调函数指针 `&add`,用于处理每次到来的请求
rclcpp::Service<example_interfaces::srv::AddTwoInts>::SharedPtr service =
node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints", &add);
// 日志:表示服务已经准备就绪,可以接受请求
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Ready to add two ints.");
// 进入事件循环,处理传入的请求和回调,直到节点退出
rclcpp::spin(node);
// 清理并关闭 ROS 2 客户端库
rclcpp::shutdown();
}
写入客户端节点
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
#include <chrono>
#include <cstdlib>
#include <memory>
using namespace std::chrono_literals;
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
// 参数检查:期望两个整数参数 X 和 Y
if (argc != 3) {
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "usage: add_two_ints_client X Y");
return 1;
}
// 创建客户端节点
// 节点名为 "add_two_ints_client"
std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_client");
// 创建服务客户端:
// - 模板参数为服务类型 `example_interfaces::srv::AddTwoInts`
// - 参数为服务名 "add_two_ints",应与服务端提供的名称一致
rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client =
node->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");
// 构造请求消息并填充请求字段 a 和 b
auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();
// 将命令行参数转换为 long(使用 atoll)并赋值
request->a = atoll(argv[1]);
request->b = atoll(argv[2]);
// 等待服务可用,超时为 1 秒,每次超时后会再次检查
// 如果用户按下 Ctrl+C 或 ROS 被中断(rclcpp::ok() 变为 false),程序将退出
while (!client->wait_for_service(1s)) {
if (!rclcpp::ok()) {
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting.");
return 0;
}
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again...");
}
// 异步发送请求,返回一个 future 对象用于获取响应
auto result = client->async_send_request(request);
// 等待 future 完成(即等待服务端响应)并处理结果
if (rclcpp::spin_until_future_complete(node, result) ==
rclcpp::FutureReturnCode::SUCCESS)
{
// 如果成功,打印响应中的 sum 字段
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Sum: %ld", result.get()->sum);
} else {
// 否则打印错误信息
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Failed to call service add_two_ints");
}
// 关闭 ROS 2 客户端库并退出
rclcpp::shutdown();
return 0;
}
Cmake 配置
cmake_minimum_required(VERSION 3.8)
project(cpp_srvcli)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(example_interfaces REQUIRED)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
add_executable(server src/add_two_ints_server.cpp)
ament_target_dependencies(server
rclcpp example_interfaces)
add_executable(client src/add_two_ints_client.cpp)
ament_target_dependencies(client
rclcpp example_interfaces)
install(TARGETS
server
client
DESTINATION lib/${PROJECT_NAME})
ament_package()
编译
lxg@lxg:~/code/ROS2/workspace/demo$ colcon build --packages-select cpp_srvcli
Starting >>> cpp_srvcli
Finished <<< cpp_srvcli [3.22s]
Summary: 1 package finished [3.43s]
运行
# 服务端
lxg@lxg:~/code/ROS2/workspace/demo$ ros2 run cpp_srvcli server
[INFO] [1779517707.444431515] [rclcpp]: Ready to add two ints.
[INFO] [1779517722.915908316] [rclcpp]: Incoming request
a: 2 b: 3
[INFO] [1779517722.915932832] [rclcpp]: sending back response: [5]
# 客户端
lxg@lxg:~/code/ROS2/workspace/demo$ ros2 run cpp_srvcli client 2 3
[INFO] [1779517722.916145334] [rclcpp]: Sum: 5
创建自定义ROS2 msg 和 srv 文件
创建新包tutorial_interfaces
lxg@lxg:~/code/ROS2/workspace/demo/src$ ros2 pkg create --build-type ament_cmake tutorial_interfaces
going to create a new package
package name: tutorial_interfaces
destination directory: /home/lxg/code/ROS2/workspace/demo/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['lxg <xiaogang.li>']
licenses: ['TODO: License declaration']
build type: ament_cmake
dependencies: []
creating folder ./tutorial_interfaces
creating ./tutorial_interfaces/package.xml
creating source and include folder
creating folder ./tutorial_interfaces/src
creating folder ./tutorial_interfaces/include/tutorial_interfaces
creating ./tutorial_interfaces/CMakeLists.txt
编写msg 和 srv
lxg@lxg:~/code/ROS2/workspace/demo/src/tutorial_interfaces$ tree -L 2
.
├── build
│ ├── COLCON_IGNORE
│ └── tutorial_interfaces
├── CMakeLists.txt
├── include
│ └── tutorial_interfaces
├── install
│ ├── COLCON_IGNORE
│ ├── local_setup.bash
│ ├── local_setup.ps1
│ ├── local_setup.sh
│ ├── _local_setup_util_ps1.py
│ ├── _local_setup_util_sh.py
│ ├── local_setup.zsh
│ ├── setup.bash
│ ├── setup.ps1
│ ├── setup.sh
│ ├── setup.zsh
│ └── tutorial_interfaces
├── log
│ ├── build_2026-05-23_14-39-29
│ ├── COLCON_IGNORE
│ ├── latest -> latest_build
│ └── latest_build -> build_2026-05-23_14-39-29
├── msg
│ └── Num.msg
├── package.xml
├── src
└── srv
└── AddThreeInts.srv
13 directories, 17 files
编译自动生成的num.hpp
./build/tutorial_interfaces/rosidl_generator_cpp/tutorial_interfaces/msg/num.hpp
./install/tutorial_interfaces/include/tutorial_interfaces/tutorial_interfaces/msg/num.hpp
// generated from rosidl_generator_cpp/resource/idl.hpp.em
// generated code does not contain a copyright notice
#ifndef TUTORIAL_INTERFACES__MSG__NUM_HPP_
#define TUTORIAL_INTERFACES__MSG__NUM_HPP_
#include "tutorial_interfaces/msg/detail/num__struct.hpp"
#include "tutorial_interfaces/msg/detail/num__builder.hpp"
#include "tutorial_interfaces/msg/detail/num__traits.hpp"
#include "tutorial_interfaces/msg/detail/num__type_support.hpp"
#endif // TUTORIAL_INTERFACES__MSG__NUM_HPP_
lxg@lxg:~/code/ROS2/workspace/demo/src/tutorial_interfaces$ find . -name “add_three_ints.hpp”
./build/tutorial_interfaces/rosidl_generator_cpp/tutorial_interfaces/srv/add_three_ints.hpp
./install/tutorial_interfaces/include/tutorial_interfaces/tutorial_interfaces/srv/add_three_ints.hpp
// generated from rosidl_generator_cpp/resource/idl.hpp.em
// generated code does not contain a copyright notice
#ifndef TUTORIAL_INTERFACES__SRV__ADD_THREE_INTS_HPP_
#define TUTORIAL_INTERFACES__SRV__ADD_THREE_INTS_HPP_
#include "tutorial_interfaces/srv/detail/add_three_ints__struct.hpp"
#include "tutorial_interfaces/srv/detail/add_three_ints__builder.hpp"
#include "tutorial_interfaces/srv/detail/add_three_ints__traits.hpp"
#include "tutorial_interfaces/srv/detail/add_three_ints__type_support.hpp"
#endif // TUTORIAL_INTERFACES__SRV__ADD_THREE_INTS_HPP_
0
次点赞