ROS2学习(8)------ROS2 服务说明
- 操作系统:ubuntu22.04
- IDE:Visual Studio Code
- 编程语言:C++11
- ROS版本:2
ROS 2(Robot Operating System 2)中的服务是一种允许节点之间进行请求/响应式通信的机制。与话题(Topics)不同,话题主要用于发布/订阅模式的持续数据流传输,而服务更适合于一次性或偶尔的数据交换场景,比如查询状态、执行操作等。
ROS2服务的基本概念
-
服务类型:每个服务都有其类型,这定义了请求和响应消息的数据结构。服务类型由两个部分组成:请求消息类型和响应消息类型。
-
服务客户端(Client):发起请求的一方,发送特定类型的请求并等待响应。
-
服务端(Server):接收请求并处理后返回响应的一方。
-
srv文件:服务的消息格式通过.srv文件定义,位于包的srv/目录下。一个.srv文件定义了一个服务的请求和响应格式。
创建和使用ROS 2服务
定义服务消息
首先,你需要为你的服务创建一个.srv文件。例如,创建一个名为MyService.srv的服务,用于计算两个整数的和:
int64 a
int64 b
---
int64 sum
上面的文件定义了一个接受两个长整型数字作为输入,并返回它们的和的服务。
修改package.xml
确保在package.xml中添加对rosidl_default_runtime以及任何你用到的消息包(如std_msgs)的依赖:
<?xml version="1.0"?>
<package format="3"><name>robot_nodes</name><version>0.0.0</version><description>My multi-node ROS 2 package</description><maintainer email="76457551@qq.com">User Name</maintainer><license>Apache-2.0</license><buildtool_depend>ament_cmake</buildtool_depend><build_depend>rosidl_default_generators</build_depend><exec_depend>rosidl_default_runtime</exec_depend><depend>rclcpp</depend><depend>std_msgs</depend><depend>geometry_msgs</depend><depend>example_interfaces</depend><member_of_group>rosidl_interface_packages</member_of_group><export><build_type>ament_cmake</build_type></export>
</package>
修改CMakeLists.txt
在CMakeLists.txt中找到find_package命令,并确保它包含了rosidl_default_generators:
cmake_minimum_required(VERSION 3.8)
project(robot_nodes)# 查找必要的依赖
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)find_package(rosidl_default_generators REQUIRED)
find_package(geometry_msgs REQUIRED)find_package(example_interfaces REQUIRED) # 假设你使用的是自定义的服务接口# 生成自定义接口
rosidl_generate_interfaces(${PROJECT_NAME}"srv/MyService.srv"DEPENDENCIES # 如果有其他依赖(如 std_msgs)
)# 添加子目录(每个节点)
add_subdirectory(nodes/node1)
add_subdirectory(nodes/node2)ament_package()
编写服务端代码
下面是一个简单的服务端示例,它实现了上述AddTwoInts服务:
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp" // 引入服务接口class MinimalService : public rclcpp::Node
{
public:MinimalService() : Node("minimal_service"){service_ = this->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints",std::bind(&MinimalService::handle_add_two_ints, this, std::placeholders::_1, std::placeholders::_2));}private:void handle_add_two_ints(const example_interfaces::srv::AddTwoInts::Request::SharedPtr request,const example_interfaces::srv::AddTwoInts::Response::SharedPtr response){response->sum = request->a + request->b;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);}rclcpp::Service<example_interfaces::srv::AddTwoInts>::SharedPtr service_;
};int main(int argc, char **argv)
{rclcpp::init(argc, argv);auto node = std::make_shared<MinimalService>();rclcpp::spin(node);rclcpp::shutdown();return 0;
}
编写客户端代码
客户端将调用服务来执行请求:
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"class MinimalClientAsync : public rclcpp::Node
{
public:MinimalClientAsync() : Node("minimal_client_async"), client_(this->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints")){while (!client_->wait_for_service(std::chrono::seconds(1))){if (!rclcpp::ok()){RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting.");return;}RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again...");}send_request();}private:void send_request(){auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();request->a = 1;request->b = 2;using ServiceResponseFuture = rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedFuture;auto response_received_callback = [this](ServiceResponseFuture future){auto result = future.get();RCLCPP_INFO(this->get_logger(), "Result: %ld", result->sum);};auto future_result = client_->async_send_request(request, response_received_callback);}rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client_;
};int main(int argc, char **argv)
{rclcpp::init(argc, argv);auto node = std::make_shared<MinimalClientAsync>();rclcpp::spin(node);rclcpp::shutdown();return 0;
}
运行结果
分别执行两个节点:
node1:
source install/setup.bash
ros2 run robot_nodes node1
node2:
source install/setup.bash
ros2 run robot_nodes node2
终端输出:
ros2 run robot_nodes node1
[2025-05-21 16:51:15:471][node1][info][node1.cpp:58]:==========main===========
[INFO] [1747817521.071953435] [rclcpp]: Incoming request
a: 1 b: 2
[INFO] [1747817521.071991360] [rclcpp]: sending back response: [3]
ros2 run robot_nodes node2
[2025-05-21 16:52:01:064][node2][info][node2.cpp:76]:==========main===========
[INFO] [1747817521.072052185] [minimal_client_async]: Result: 3