您现在的位置是:首页 >技术交流 >ros2服务器&客户端实例网站首页技术交流

ros2服务器&客户端实例

躺平了,不信你看 2025-04-23 12:01:02
简介ros2服务器&客户端实例

简介

1.话题的缺点。

        在ros通讯时,话题会按时持续的发送数据,这导致在我们不需要这些数据时发送一些无用数据,而且还消耗电脑资源。

2.服务器的优点

        在客户端访问主机前,主机一直在静默,知道客户端请求才发送消息。

实例

1.1创建功能包

//创建example_cpp功能包。(存放实例)
ros2 pkg create example_cpp --build-type ament_cmake --dependencies rclcpp  --license Apache-2.0

1.2在src中创建客户端

        创建service_client_01.cpp,代码如下还有注释

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"

class ServiceClient01 : public rclcpp::Node 
{
public:
    // 构造函数,有一个参数为节点名称
    ServiceClient01(std::string name) : Node(name) 
    {
        RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());
        // 创建客户端
        client_ = this->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints_srv");
    }

    void send_request(int a, int b) 
    {
        // 打印日志,输出计算a+b
        RCLCPP_INFO(this->get_logger(), "计算%d+%d", a, b);

        while (!client_->wait_for_service(std::chrono::seconds(1))) // 使用while循环等待服务端上线,每秒检测一次
        {
            if (!rclcpp::ok()) // 如果rclcpp的状态被打断,则打印错误日志并返回
            {
                RCLCPP_ERROR(this->get_logger(), "等待服务的过程中被打断...");
                return;
            }
            // 打印日志,输出等待服务端上线中
            RCLCPP_INFO(this->get_logger(), "等待服务端上线中");
        }

/*
    std::make_shared<example_interfaces::srv::AddTwoInts_Request>的变量类型
    int64 a
    int64 b
    ---
    int64 sum   结果
*/
        // 2.构造请求的
        //auto关键字用于自动推导变量的类型。编译器会根据右侧表达式的类型自动推断出变量的类型。
        auto request = std::make_shared<example_interfaces::srv::AddTwoInts_Request>();//std::make_shared在创建对象时会一次性分配内存,从而避免潜在的内存泄漏问题。
        request->a = a;// 设置请求的参数
        request->b = b;

        // 3.      发送异步请求,                                         返回时调用回调函数
        client_->async_send_request(request, std::bind(&ServiceClient01::result_callback_, this,std::placeholders::_1));
  };
  
private:
    // 声明客户端
    rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client_;

    // 定义一个回调函数,用于处理客户端请求的结果
    void result_callback_(rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedFuture result_future) 
      {
        
        auto response = result_future.get();// 获取共享未来的结果
        
        RCLCPP_INFO(this->get_logger(), "计算结果:%ld", response->sum);//response是一个指针,sum是一个成员变量,存储了计算的结果。
  }

};

int main(int argc, char** argv) {
    rclcpp::init(argc, argv);
    /*创建对应节点的共享指针对象*/
    auto node = std::make_shared<ServiceClient01>("service_client_01");

    //增加这一行,node->send_request(5, 6);,计算5+6结果
    node->send_request(5, 6);
    /* 运行节点,并检测退出信号*/
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

1.3在src中创建服务器

        创建service_server_01.cpp

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"

class ServiceServer01 : public rclcpp::Node 
{
public:
  ServiceServer01(std::string name) : Node(name) {
    // 打印节点启动信息
    RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());
  
    // 创建服务
    add_ints_server_ = this->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints_srv", std::bind(&ServiceServer01::handle_add_two_ints, this, std::placeholders::_1, std::placeholders::_2));
  }

private:
    // 声明一个服务
    rclcpp::Service<example_interfaces::srv::AddTwoInts>::SharedPtr add_ints_server_;
    // 处理两个整数的加法请求
    void handle_add_two_ints(const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request, std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response) 
    {
    
        RCLCPP_INFO(this->get_logger(), "收到a: %ld b: %ld", request->a,request->b);// 打印收到的a和b的值
        response->sum = request->a + request->b;// 将a和b相加的结果赋值给sum
    }
};

int main(int argc, char** argv) 
{
  rclcpp::init(argc, argv);// 初始化ROS2节点
  auto node = std::make_shared<ServiceServer01>("service_server_01");// 创建一个ServiceServer01对象,并命名为service_server_01
  rclcpp::spin(node);// 进入事件循环,等待回调函数
  rclcpp::shutdown();// 关闭ROS2节点
  return 0;
}

1.4编辑CMikeLists.txt文件

        注意要放到ament_package() 代码段之前

find_package(example_interfaces REQUIRED)
#----------------------service_client_01-----------------------#
add_executable(service_client_01 src/service_client_01.cpp)
ament_target_dependencies(service_client_01 rclcpp example_interfaces)

install(TARGETS
  service_client_01
  DESTINATION lib/${PROJECT_NAME}
)
#----------------------service_server_01-----------------------#
add_executable(service_server_01 src/service_server_01.cpp)
ament_target_dependencies(service_server_01 rclcpp example_interfaces)

install(TARGETS
  service_server_01
  DESTINATION lib/${PROJECT_NAME}
)

1.5编辑package.xml文件

        注意放到 <depend>rclcpp</depend>下面即可,如果还有依赖也是一样的也是

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>
  <depend>example_interfaces</depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

编译运行

2.1回到工作空间主目录下编译 colcon build

2.2加载可查询库中


source install/setup.bash    #载入当前ros2的文件节点路径

运行

//先运行客户端
ros2 run example_cpp service_client_01 
//再运行服务器
ros2 run example_cpp service_server_01 

结果

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。