3. ROS2服务通信基础
任务目标
实现一个ROS2加法服务:服务器节点提供add_two_ints服务,接收两个整数请求并返回求和结果;客户端节点发送请求并打印响应。同时演示使用ROS2命令行工具直接调用该服务。
环境准备
需要已安装ROS2(Humble或更新版本),并创建好工作空间。本案例使用C++实现,需确保已安装ros-humble-desktop或ros-humble-ros-base及C++编译工具链。
实现代码
创建功能包并编写服务器与客户端节点。以下为完整实现:
# 创建工作空间与功能包(若已存在可跳过)
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake --dependencies rclcpp example_interfaces add_two_ints_service
# 编辑 src/add_two_ints_service/src/server.cpp
cat > src/add_two_ints_service/src/server.cpp << 'EOF'
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
using AddTwoInts = example_interfaces::srv::AddTwoInts;
int main(int argc, char **argv) {
rclcpp::init(argc, argv);
auto node = std::make_shared<rclcpp::Node>("add_two_ints_server");
auto server = node->create_service<AddTwoInts>(
"add_two_ints",
[](const std::shared_ptr<AddTwoInts::Request> req,
std::shared_ptr<AddTwoInts::Response> res) {
res->sum = req->a + req->b;
RCLCPP_INFO(rclcpp::get_logger("server"),
"收到请求: %ld + %ld = %ld", req->a, req->b, res->sum);
});
RCLCPP_INFO(node->get_logger(), "加法服务已启动,等待请求...");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}
EOF
# 编辑 src/add_two_ints_service/src/client.cpp
cat > src/add_two_ints_service/src/client.cpp << 'EOF'
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
#include <chrono>
using AddTwoInts = example_interfaces::srv::AddTwoInts;
using namespace std::chrono_literals;
int main(int argc, char **argv) {
rclcpp::init(argc, argv);
auto node = std::make_shared<rclcpp::Node>("add_two_ints_client");
auto client = node->create_client<AddTwoInts>("add_two_ints");
// 等待服务可用
while (!client->wait_for_service(1s)) {
if (!rclcpp::ok()) {
RCLCPP_ERROR(node->get_logger(), "等待服务时被中断");
return 1;
}
RCLCPP_INFO(node->get_logger(), "等待服务上线...");
}
auto request = std::make_shared<AddTwoInts::Request>();
request->a = 15;
request->b = 27;
auto future = client->async_send_request(request);
// 等待响应(超时5秒)
if (future.wait_for(5s) == std::future_status::ready) {
auto response = future.get();
RCLCPP_INFO(node->get_logger(), "服务返回: %ld + %ld = %ld",
request->a, request->b, response->sum);
} else {
RCLCPP_ERROR(node->get_logger(), "请求超时");
return 1;
}
rclcpp::shutdown();
return 0;
}
EOF
# 编辑 CMakeLists.txt 添加编译规则
cat > src/add_two_ints_service/CMakeLists.txt << 'EOF'
cmake_minimum_required(VERSION 3.8)
project(add_two_ints_service)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(example_interfaces REQUIRED)
add_executable(server src/server.cpp)
ament_target_dependencies(server rclcpp example_interfaces)
add_executable(client src/client.cpp)
ament_target_dependencies(client rclcpp example_interfaces)
install(TARGETS server client
DESTINATION lib/${PROJECT_NAME})
ament_package()
EOF
# 编译
cd ~/ros2_ws
colcon build --packages-select add_two_ints_service
source install/setup.bash
运行与验证
按以下步骤验证服务通信是否正常:
- 启动服务器(终端1):
source ~/ros2_ws/install/setup.bash
ros2 run add_two_ints_service server
预期看到日志:加法服务已启动,等待请求...
- 命令行调用服务(终端2):
source ~/ros2_ws/install/setup.bash
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 10, b: 32}"
预期输出包含:sum: 42,同时服务器终端打印收到请求的日志。
- 运行客户端节点(终端3):
source ~/ros2_ws/install/setup.bash
ros2 run add_two_ints_service client
预期客户端打印:服务返回: 15 + 27 = 42。
通过判定标准:三个终端均无报错,命令行调用返回正确求和结果,客户端节点成功获取响应,服务器日志显示收到两次请求(分别来自命令行和客户端节点)。
常见问题
- 找不到功能包:确认已执行
source install/setup.bash且编译无错误。 - 服务调用超时:确认服务器节点正在运行且服务名拼写正确(
ros2 service list可查看)。 - 类型不匹配:命令行调用时需使用
example_interfaces/srv/AddTwoInts完整类型名。