ROS 2 服务通信
1. 简介
ROS 2(Robot Operating System 2) 是一个用于机器人系统开发的开源框架,提供了许多工具和库来简化复杂机器人应用的开发。在 ROS 2 中,服务(Service)是一种同步的通信机制,允许节点之间进行请求-响应模式的通信。这与话题(Topics)中的异步通信方式不同,服务更适合那些需要明确请求和相应结果的应用场景。
在这篇文章中,我们将介绍如何使用 C++ 创建和使用 ROS 2 服务,包括服务端(Service Server)和客户端(Service Client)的实现。
2. 什么是 ROS 2 服务?
ROS 2 服务是一种基于请求-响应的通信模式,通常用于需要立即得到响应的场景。服务由两个部分组成:
- 服务端(Server): 提供服务,等待客户端的请求,并返回相应的结果。
- 客户端(Client): 发送请求到服务端,并等待服务端返回结果。
服务的通信是同步的,这意味着客户端在等待服务端响应时会阻塞当前线程。
3. 创建自定义服务类型
在 ROS 2 中,服务类型定义了请求和响应的消息结构。可以使用 .srv
文件来定义自定义服务类型。以下是一个简单的服务类型定义示例:
AddTwoInts.srv
int64 a
int64 b
---
int64 sum
这个服务类型表示客户端会发送两个 int64
类型的整数(a
和 b
),服务端返回它们的和(sum
)。
以下内容在 CMakeLists.txt
添加
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/PositionSpeed.msg"
"srv/ComputeArea.srv"
#添加这一行
"srv/AddTwoInts.srv"
"action/Factorial.action"
DEPENDENCIES *# Add packages that above messages depend on*
)
4. 创建服务端(Service Server)
创建服务端节点需要使用 ROS 2 提供的 rclcpp
库。在 C++ 中实现服务端的如下:
#include "rclcpp/rclcpp.hpp"
#include "my_custom_msgs/srv/add_two_ints.hpp"
class AddTwoIntsServer : public rclcpp::Node
{
public:
AddTwoIntsServer() : Node("add_two_ints_server")
{
service_ = this->create_service<my_custom_msgs::srv::AddTwoInts>(
"add_two_ints", std::bind(&AddTwoIntsServer::handle_add_two_ints, this, std::placeholders::_1, std::placeholders::_2));
}
private:
void handle_add_two_ints(
const std::shared_ptr<my_custom_msgs::srv::AddTwoInts::Request> request,
std::shared_ptr<my_custom_msgs::srv::AddTwoInts::Response> response)
{
response->sum = request->a + request->b;
RCLCPP_INFO(this->get_logger(), "Request: a = %ld, b = %ld", request->a, request->b);
RCLCPP_INFO(this->get_logger(), "Sending back response: [%ld]", response->sum);
}
rclcpp::Service<my_custom_msgs::srv::AddTwoInts>::SharedPtr service_;
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<AddTwoIntsServer>());
rclcpp::shutdown();
return 0;
}
定义服务端节点类。在这个例子中,我们创建了一个名为 add_two_ints_server
的节点,它提供了一个名为 add_two_ints
的服务。服务处理函数 handle_add_two_ints
计算两个整数的和,并将结果返回给客户端。
5. 创建客户端(Service Client)
客户端的实现与服务端类似,也需要使用 rclcpp
库。以下是实现:
#include "rclcpp/rclcpp.hpp"
#include "my_custom_msgs/srv/add_two_ints.hpp" // 替换为自定义服务类型的头文件
class AddTwoIntsClient : public rclcpp::Node
{
public:
AddTwoIntsClient() : Node("add_two_ints_client")
{
client_ = this->create_client<my_custom_msgs::srv::AddTwoInts>("add_two_ints");
// 等待服务端准备就绪
while (!client_->wait_for_service(std::chrono::seconds(1))) {
RCLCPP_INFO(this->get_logger(), "Waiting for service to be available...");
}
auto request = std::make_shared<my_custom_msgs::srv::AddTwoInts::Request>();
request->a = 5;
request->b = 3;
auto result = client_->async_send_request(request);
// 等待结果
if (rclcpp::spin_until_future_complete(this->get_node_base_interface(), result) ==
rclcpp::FutureReturnCode::SUCCESS)
{
RCLCPP_INFO(this->get_logger(), "Result: %ld", result.get()->sum);
} else {
RCLCPP_ERROR(this->get_logger(), "Failed to call service");
}
}
private:
rclcpp::Client<my_custom_msgs::srv::AddTwoInts>::SharedPtr client_;
};
int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<AddTwoIntsClient>());
rclcpp::shutdown();
return 0;
}
在这个例子中,我们创建了一个名为 add_two_ints_client
的节点,发送两个整数给服务端,并打印出返回的结果。
6. 编译和运行
使用 CMake 编译上述服务端和客户端代码。以下是 CMakeLists.txt
的示例:
cmake_minimum_required(VERSION 3.8)
project(my_server)
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(my_custom_msgs REQUIRED)
find_package(rclcpp 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(AddTwoIntsServer_node src/AddTwoIntsServer.cpp)
ament_target_dependencies(AddTwoIntsServer_node rclcpp my_custom_msgs)
add_executable(AddTwoIntsClient_node src/AddTwoIntsClient.cpp)
ament_target_dependencies(AddTwoIntsClient_node rclcpp my_custom_msgs)
install(TARGETS
AddTwoIntsServer_node
AddTwoIntsClient_node
DESTINATION lib/${PROJECT_NAME})
ament_package()
编译后,运行服务端和客户端节点以观察通信效果。
7. 总结
在这篇文章中,我们详细介绍了如何使用 C++ 在 ROS 2 中创建和使用服务。通过创建服务端和客户端节点,开发者可以轻松实现同步的请求-响应通信模式。这种模式适用于机器人系统中那些需要立即得到响应的场景,如命令执行、传感器数据获取等。
希望这篇文章能帮助你更好地理解和使用 ROS 2 服务!