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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

村北头的码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值