【服务通信/参数通信】

【服务通信/参数通信】

服务通信:请求/响应 双向通信机制
参数通信:管理节点

关于服务和参数【概述】

服务通信 service

ros2 service list -t查询服务列表 -t:显示服务接口类型

/spawn [turtlesim/srv/Spawn]
spawn:服务名称 产生一只新海龟
[ ]:接口类型->(1)请求接口 (2)响应接口

ros2 interface show turtlesim/srv/Spawn

# 请求接口定义
float32 x
float32 y
float32 theta
string name # Optional.  A unique name will be created and returned if this is empty
---
# 响应接口定义
string name

调用接口

ros2 service call /spawn turtlesim/srv/Spawn "{x: 1, y: 1}"

基于服务的参数通信 param

参数:节点的设置

ros2 service list -t | grep parameter 查看和参数有关的服务

/turtlesim/describe_parameters [rcl_interfaces/srv/DescribeParameters]
/turtlesim/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
/turtlesim/get_parameters [rcl_interfaces/srv/GetParameters]
/turtlesim/list_parameters [rcl_interfaces/srv/ListParameters]
/turtlesim/set_parameters [rcl_interfaces/srv/SetParameters]
/turtlesim/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]

关于ros2 param使用

  delete    Delete parameter
  describe  Show descriptive information about declared parameters
  dump      Show all of the parameters of a node in a YAML file format
  get       Get parameter
  list      Output a list of available parameters
  load      Load parameter file for a node
  set       Set parameter

ros2 param list 查看参数列表

/turtlesim:
  background_b
  background_g
  background_r
  qos_overrides./parameter_events.publisher.depth
  qos_overrides./parameter_events.publisher.durability
  qos_overrides./parameter_events.publisher.history
  qos_overrides./parameter_events.publisher.reliability
  use_sim_time

ros2 param describe /turtlesim background_r 查看某个参数的具体描述

Parameter name: background_r
  Type: integer
  Description: Red channel of the background color
  Constraints:
    Min value: 0
    Max value: 255
    Step: 1

ros2 param get /turtlesim background_r 获取节点参数值 get
ros2 param set /turtlesim background_r 255 修改参数值 set

使用文件配置参数

将某节点配置导出yaml格式文件
ros2 param dump /turtlesim > turtlesim_param.yaml
修改yaml文件
重新打开终端
ros2 run turtlesim turtlesim_node --ros-args --params-file turtlesim_param.yaml

自定义服务接口:海龟寻迹项目为例

创建一个功能包来存服务接口

srv/Patrol.srv

# Request 请求部分
float32 target_x  # 目标x值
float32 target_y  # 目标y值
---
# Response 应答部分
int8 SUCCESS = 1  # 定义常量,表示成功
int8 FAIL = 0     # 定义常量,表示失败
int8 result       # 处理结果 -> SUCCESS/FAIL取其一

CMakeList.txt注册

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(turtlesim REQUIRED)
find_package(sensor_msgs REQUIRED)

# 在rosidl_generate_interfaces中添加sensor_msgs依赖
rosidl_generate_interfaces(${PROJECT_NAME}
    "srv/Patrol.srv"
    DEPENDENCIES sensor_msgs
)

package.xml声明:同消息接口

测试

$ ros2 interface show chapt4_interfaces/srv/Patrol //注意这里文件长度不超过3个

服务端:控制海龟到目标点

创建功能包:与srv同级目录

ros2 pkg create demo_cpp_service...
--dependencies ... chapt4_interfaces ...  //注意把chapt4_interfaces包含到依赖里

在闭环控制海龟基础上写服务端

【添加服务头文件】

//添加服务头文件并创建别名
#include "chapt4_interfaces/srv/patrol.hpp"
using Patrol=chapt4_interfaces::srv::Patrol;

【TurtleController类里】

public:
//创建服务
patrol_server_ = this->create_service<Patrol>(
    "patrol",
    //lambda函数作为回调函数:参数为请求和响应对象的共享指针
    [&](const std::shared_ptr<Patrol::Request> request,
       std::shared_ptr<Patrol::Response> response) -> void{
    //判断巡逻点是否在模拟器边界内
    if((0 < request->target_x && request->target_x < 12.0f)
        && (0 < request->target_y && request->target_y < 12.0f)){
			//设置目标点
              target_x_ = request -> target_x;
              target_y_ = request -> target_y;
              response -> result = Patrol::Response::SUCCESS;
    }
    else{
         response -> result = Patrol::Response::FAIL;
   }
});

private:
//服务:Patrol类型服务共享指针
rclcpp::Service<Patrol>::SharedPtr patrol_server_;

CMakeList.txt内注册:不要忘记install

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(chapt4_interfaces REQUIRED)
find_package(rclcpp REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(turtlesim REQUIRED)

add_executable(turtle_control_two src/turtle_control.cpp)

ament_target_dependencies(turtle_control_two rclcpp geometry_msgs turtlesim chapt4_interfaces)

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

运行

【先打开海龟模拟器】
->【运行代码】

$ ros2 run demo_cpp_service turtle_control_two

【启动服务】
查看服务

ros2 service list

->source找消息接口
【请求服务】

ros2 service call /patrol chapt4_interfaces/srv/Patrol "{target_x: 10.0,target_y: 10.0}"

客户端:随机生成目标点,并请求服务端处理

#include<cstdlib>
#include<ctime>
#include"rclcpp/rclcpp.hpp"
#include"chapt4_interfaces/srv/patrol.hpp"
#include<chrono>
using namespace std::chrono_literals;
using Patrol=chapt4_interfaces::srv::Patrol;
class PatrolClient : public rclcpp::Node{
    public:
        PatrolClient() : Node("patrol_cilent"){
            patrol_client_ = this->create_client<Patrol>("patrol");
            timer_=this->create_wall_timer(10s,std::bind(&PatrolClient::timer_callback,this));
                                                                    //定时请求服务端->每10秒一次
            srand(time(NULL));
        }
        //实现函数
        void timer_callback(){
            //TODO 生成随机目标点,请求服务端
            //1.等待服务端上线                               👇超过指定时间
            while(!patrol_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<Patrol::Request>();
            request->target_x = rand() % 15;
            request->target_y = rand() % 15;
            RCLCPP_INFO(this->get_logger(),"请求巡逻:(%f,%f)",request->target_x,request->target_y);
            //3.发送异步请求,然后等待返回,返回时调用回调函数(用lambda写)
            patrol_client_->async_send_request(
                request,                   // ↓ 获取异步处理的结果
                [&](rclcpp::Client<Patrol>::SharedFuture result_future) -> void{
                    auto response = result_future.get();//获取Response共享指针
                    if(response -> result == Patrol::Response::SUCCESS){
                        RCLCPP_INFO(this->get_logger(),"目标点处理成功");
                    }
                    else if(response -> result == Patrol::Response::FAIL){
                        RCLCPP_INFO(this->get_logger(),"目标点处理失败");
                    }
                });
        }

    private:
        rclcpp::TimerBase::SharedPtr timer_;
        rclcpp::Client<Patrol>::SharedPtr patrol_client_;
};

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

【参数通信】

声明和设置参数

TurtleController() : Node("turtle_controller"){
     //声明和获取参数初始值
     this->declare_parameter("k",1.0);//声明参数
     this->declare_parameter("max_speed",1.0);
     this->get_parameter("k",k_);//获取当前参数值
     this->get_parameter("max_speed",max_speed_);
}

接受参数事件:服务端

//导入消息接口:返回参数设置结果
#include "rcl_interfaces/msg/set_parameters_result.hpp"
using SetParametersResult=rcl_interfaces::msg::SetParametersResult;
TurtleController() : Node("turtle_controller"){
	...
   //添加参数设置回调
   parameters_callback_handle_=this->add_on_set_parameters_callback(
   //添加回调函数即可
  [&](const std::vector<rclcpp::Parameter> &params)->SetParametersResult{//注意这里传入数组->静态引入
   for(auto param : params){
        RCLCPP_INFO(this->get_logger(),"更新参数%s值为:%f",param.get_name().c_str(),
        param.as_double());
        if(param.get_name() == "k"){
                k_ = param.as_double();
        }
        else if(param.get_name() == "max_speed"){
                max_speed_ = param.as_double();
        }
   }
   auto result = SetParametersResult();
   result.successful=true;//都是内置参数
   return result;
   });
}

【代码改变参数】

this->set_parameter(rclcpp::Parameter("k",2.0));

修改其他节点的参数:客户端

【请求服务】

#include "rcl_interfaces/msg/parameter.hpp"
#include "rcl_interfaces/msg/parameter_value.hpp"
#include "rcl_interfaces/msg/parameter_type.hpp"
#include "rcl_interfaces/srv/set_parameters.hpp"
using SetP=rcl_interfaces::srv::SetParameters;//消息与服务相关接口

【发送参数请求并接收响应】

std::shared_ptr<SetP::Response> call_set_parameters(rcl_interfaces::msg::Parameter &parameter){
	//创建客户端等待服务上线
       auto param_client=this->create_client<SetP>("turtle_controller/set_parameters");
       while(!param_client->wait_for_service(std::chrono::seconds(1))){
           if(!rclcpp::ok()){
               RCLCPP_ERROR(this->get_logger(),"等待服务的过程中被打断...");
               return nullptr;
           }
           RCLCPP_INFO(this->get_logger(),"等待参数设置服务端上线中");
       }
       //创建请求对象->等待服务上线
       auto request=std::make_shared<SetP::Request>();
       //parameters是内置数组
       request->parameters.push_back(parameter);
       //异步调用,等待并返回响应结果
       auto future=param_client->async_send_request(request);
       rclcpp::spin_until_future_complete(this->get_node_base_interface(),future);
       auto response=future.get();
       return response;
}

【发送请求更新参数k】

void update_server_param_k(double k){
            //创建参数对象
            auto param=rcl_interfaces::msg::Parameter();
            param.name="k";
            //创建参数值对象并赋值
            auto param_value=rcl_interfaces::msg::ParameterValue();
            param_value.type=rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE;
            param_value.double_value = k;
            param.value=param_value; //更新到原param里
            //请求更新参数并处理
            auto response=call_set_parameters(param);
            if(response == nullptr){
                RCLCPP_WARN(this->get_logger(),"参数修改失败");
                return;
            }
            else{
                for(auto result : response->results){
                    if(result.successful){
                        RCLCPP_INFO(this->get_logger(),"参数k已修改为:%f",k);
                    }
                    else{
                        RCLCPP_WARN(this->get_logger(),"参数k 失败 原因:%s",result.reason.c_str());
                    }
                }
            }
        }

在main函数内调用

node->update_server_param_k(1.5);
posted @ 2024-12-18 20:54  White_ink  阅读(95)  评论(0)    收藏  举报