云计算百科
云计算领域专业知识百科平台

ROS2学习笔记8

一、ROS2服务入门

1.1 简介

        服务分为“客户端”和“服务端”。

        客户端发送请求给服务端,服务端可以根据客户端的请求做一些处理,然后返回结果给客户端。所以服务-客户端模型,也可以成为请求-响应模型。

注意事项:

  • 同一个服务(名称相同)有且只能有一个节点来提供
  • 同一个服务可以被多个客户端调用

1.2 服务常用命令

  (1)查看服务列表:

ros2 service list

 (2)手动调用服务:

ros2 service call <service_name> <service_type > <values>

        使用实例:

ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 5,b: 10}"

 (3)查看服务接口类型:

ros2 service type <service_name>

          使用实例: 

ros2 service type /add_two_ints

  (4)查找使用某一接口的服务:

ros2 service find <service_type>

           使用实例:

ros2 service find example_interfaces/srv/AddTwoInts

学习:【ROS2机器人入门到实战】ROS2服务入门_鱼香ros-CSDN博客

二、服务之RCLCPP实现

2.1 创建功能包和节点

(1)打开终端

        在chapt3_ws/src/目录下打开终端,创建功能包:

ros2 pkg create example_service_rclcpp –build-type ament_cmake –dependencies rclcpp

         创建节点:

cd example_service_rclcpp/
touch service_server_01.cpp
touch service_client_01.cpp

        编写服务端代码:

sudo nano service_server_01.cpp
#include "rclcpp/rclcpp.hpp"

class ServiceServer01 : public rclcpp::Node {
public:
ServiceServer01(std::string name) : Node(name) {
RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());
}

private:
};

int main(int argc, char** argv) {
rclcpp::init(argc, argv);
auto node = std::make_shared<ServiceServer01>("service_server_01");
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}

         编写客户端代码:

sudo nano service_client_01.cpp
#include "rclcpp/rclcpp.hpp"

class ServiceClient01 : public rclcpp::Node {
public:
// 构造函数,有一个参数为节点名称
ServiceClient01(std::string name) : Node(name) {
RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());
}
private:
};

int main(int argc, char** argv) {
rclcpp::init(argc, argv);
/*创建对应节点的共享指针对象*/
auto node = std::make_shared<ServiceClient01>("service_client_01");
/* 运行节点,并检测退出信号*/
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}

          修改CMakeLists.txt,在最后加入一下代码:

cd ..
sudo nano CMakeLists.txt
add_executable(service_client_01 src/service_client_01.cpp)
ament_target_dependencies(service_client_01 rclcpp)

add_executable(service_server_01 src/service_server_01.cpp)
ament_target_dependencies(service_server_01 rclcpp)

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

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

(2)编译和测试

         编译:

cd chapt3/chapt3_ws/
colcon build –packages-select example_service_rclcpp

         运行 service_server_01:

source install/setup.bash
ros2 run example_service_rclcpp service_server_01

        在工作空间打开新终端, 运行 service_client_01:

source install/setup.bash
ros2 run example_service_rclcpp service_client_01

2.2  服务端实现

(1)导入接口

        两数相加我们需要利用ROS2自带的example_interfaces接口,使用命令行可以查看这个接口的定义。

ros2 interface show example_interfaces/srv/AddTwoInts

ament_cmake类型功能包导入消息接口分为三步:

  • 在CMakeLists.txt中导入,具体是先find_packagesament_target_dependencies
  • 在packages.xml中导入,具体是添加depend标签并将消息接口写入。
  • 在代码中导入,C++中是#include"消息功能包/xxx/xxx.hpp"
  •         修改CMakeLists.txt:

    cd chapt5_ws/src/example_server_rclcpp/
    sudo nano CMakeLists.txt
    # 这里我们一次性把服务端和客户端对example_interfaces的依赖都加上
    find_package(example_interfaces REQUIRED) # 新增

    add_executable(service_client_01 src/service_client_01.cpp)
    ament_target_dependencies(service_client_01 rclcpp example_interfaces) # 新增

    add_executable(service_server_01 src/service_server_01.cpp)
    ament_target_dependencies(service_server_01 rclcpp example_interfaces) # 新增

             修改packages.xml:

    sudo nano package.xml
    <depend>example_interfaces</depend>

            修改service_server_01.cpp:

    cd src/
    sudo nano service_server_01.cpp
    #include "example_interfaces/srv/add_two_ints.hpp"

             修改service_client_01.cpp:

    sudo nano service_client_01.cpp
    #include "example_interfaces/srv/add_two_ints.hpp"

     (2)编写代码

            继续编写service_server_01.cpp:

    sudo nano service_server_01.cpp
    #include "example_interfaces/srv/add_two_ints.hpp"
    #include "rclcpp/rclcpp.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);
    response->sum = request->a + request->b;
    };
    };

    int main(int argc, char **argv) {
    rclcpp::init(argc, argv);
    auto node = std::make_shared<ServiceServer01>("service_server_01");
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
    }

             继续编写service_client_01.cpp:

    sudo nano 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) {
    RCLCPP_INFO(this->get_logger(), "计算%d+%d", a, b);

    // 1.等待服务端上线
    while (!client_->wait_for_service(std::chrono::seconds(1))) {
    //等待时检测rclcpp的状态
    if (!rclcpp::ok()) {
    RCLCPP_ERROR(this->get_logger(), "等待服务的过程中被打断…");
    return;
    }
    RCLCPP_INFO(this->get_logger(), "等待服务端上线中");
    }

    // 2.构造请求的
    auto request =
    std::make_shared<example_interfaces::srv::AddTwoInts_Request>();
    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);
    }
    };

    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;
    }

    (3)编译和测试

            在工作空间目录下打开终端进行编译:

    colcon build –packages-select example_service_rclcpp

             运行客户端:

    source install/setup.bash
    ros2 run example_service_rclcpp service_client_01

             在工作空间目录下打开新终端运行服务端:

    source install/setup.bash
    ros2 run example_service_rclcpp service_server_01

    学习:【ROS2机器人入门到实战】服务之RCLCPP实现-CSDN博客

    学习rclcpp服务:rclcpp文档

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » ROS2学习笔记8
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!