4.5 在C++节点中使用参数

本节沿用之前4.3 节小海龟控制例子。

4.5.1 参数声明与设置

打开src/demo_cpp_service/src/turtle_control.cpp文件

添加测试代码

cpp 复制代码
        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_);

重新构建后,运行节点

ros2 run demo_cpp_service turtle_control

查看参数列表

bohu@bohu-TM1701:~/chapt4/chapt4_ws$ ros2 param list

/turtle_controller:

k

max_speed

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

可以看到节点声明的参数了。还可以使用rqt软件直接修改

4.5.2 接受参数事件

上面设置参数只是修改ros2参数,节点的参数值没有修改,需要增加参数设置回调函数。

修改之前的turtle_control.cpp.

cpp 复制代码
#include "rclcpp/rclcpp.hpp"
#include "geometry_msgs/msg/twist.hpp"
#include "turtlesim/msg/pose.hpp"
#include "chapt4_interfaces/srv/patrol.hpp"
#include "rcl_interfaces/msg/set_parameters_result.hpp"
using Patrol = chapt4_interfaces::srv::Patrol;
using SetParametersResult = rcl_interfaces::msg::SetParametersResult;
using namespace std;


class TurtleControlNode : public rclcpp::Node
{
public:
    TurtleControlNode() : 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_);
        paramter_callback_handle_ = this->add_on_set_parameters_callback(
            [&](const 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;
            });
        patrol_service_ =  this->create_service<Patrol>(
        "patrol",[&](const shared_ptr<Patrol::Request> request,
            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;
          }
        });

        //调用继承来父类来创建发布者  
        publisher_ = this->create_publisher<geometry_msgs::msg::Twist>("/turtle1/cmd_vel",10);
        //订阅者
        subscriber_ = this->create_subscription<turtlesim::msg::Pose>("/turtle1/pose",10,std::bind(&
        TurtleControlNode::on_pose_received_,this,placeholders::_1));
    }
private:
    void on_pose_received_(const turtlesim::msg::Pose::SharedPtr pose) {
    //1获取当前位置
    auto current_x = pose->x;
    auto current_y = pose->y;
    RCLCPP_INFO(get_logger(),"当前:x=%f,y=%f",current_x,current_y);
    //2计算与目标距离,以及当前海龟的角度差
    auto distance = sqrt(
        (target_x_-current_x)*(target_x_-current_x)+
        (target_y_-current_y)*(target_y_-current_y)
    );
    auto angle = atan2((target_y_-current_y),(target_x_-current_x))-pose->theta;

    //3控制策略:
    auto msg = geometry_msgs::msg::Twist();
    if(distance>0.1){
        if(fabs(angle)>0.2)
        {
            msg.angular.z = fabs(angle);
        }else{
            msg.linear.x = k_*distance;
        }
    }

    //4 限制最大速度
    if(msg.linear.x>max_speed_){
        msg.linear.x = max_speed_;
    }
    publisher_->publish(msg);
  }
private:
    OnSetParametersCallbackHandle::SharedPtr paramter_callback_handle_;
    rclcpp::Service<Patrol>::SharedPtr patrol_service_;
    rclcpp::Subscription<turtlesim::msg::Pose>::SharedPtr  subscriber_; //订阅者智能指针
    rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr publisher_;   //发布者智能指针  
    double target_x_{1.0}; //目标位置X,
    double target_y_{1.0}; 目标位置Y
    double k_{1.0};//比例系数
    double max_speed_{2.0}; //最大速度    
};

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

主要是增加回调函数add_on_set_parameters_callback

重新构建后运行节点,打开rqt 修改属性值

bohu@bohu-TM1701:~/chapt4/chapt4_ws$ ros2 run demo_cpp_service turtle_control

INFO\] \[1736411168.111954645\] \[turtle_controller\]: 更新参数的值k=2.000000 \[INFO\] \[1736411195.539882142\] \[turtle_controller\]: 更新参数的值k=3.000000 \[INFO\] \[1736411207.634454220\] \[turtle_controller\]: 更新参数的值max_speed=2.000000 ### 4.5.3 修改其他节点的参数 参数机制是基于服务通信实现的,之前python节点验证过。先看下涉及SetParameters数据类型: bohu@bohu-TM1701:\~/chapt4/chapt4_ws$ ros2 interface show rcl_interfaces/srv/SetParameters # A list of parameters to set. Parameter\[\] parameters string name ParameterValue value uint8 type bool bool_value int64 integer_value float64 double_value string string_value byte\[\] byte_array_value bool\[\] bool_array_value int64\[\] integer_array_value float64\[\] double_array_value string\[\] string_array_value --- # Indicates whether setting each parameter succeeded or not and why. SetParametersResult\[\] results bool successful string reason 这也是为什么要引入相关头文件,修改后的patrol_client.cpp代码 ```cpp #include #include #include #include "rclcpp/rclcpp.hpp" #include "chapt4_interfaces/srv/patrol.hpp" #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; using Patrol = chapt4_interfaces::srv::Patrol; using namespace std; using namespace std::chrono_literals;//可以使用10s class PatrolClient : public rclcpp::Node { public: PatrolClient() : Node("patrol_client") { patrol_client_ = this->create_client("patrol"); timer_ = this->create_wall_timer(10s,[&]()->void{ //1检测服务端是否上线 while(!patrol_client_->wait_for_service(1s)){ RCLCPP_ERROR(this->get_logger(),"等待服务上线过程中,rclcpp异常,退出"); return; } RCLCPP_INFO(this->get_logger(),"等待服务上线...."); //2 构造请求对象 auto request = std::make_shared(); request->target_x = rand()%15; request->target_y = rand()%15; RCLCPP_INFO(this->get_logger(),"已准备好目标点%f,%f",request->target_x ,request->target_y ); //3 发送请求 this->patrol_client_->async_send_request(request,[&](rclcpp::Client::SharedFuture result_future)->void{ auto response = result_future.get(); if(response->result==Patrol::Response::SUCCESS){ RCLCPP_INFO(this->get_logger(),"请求目标点处理成功"); }else if(response->result==Patrol::Response::FAIL){ RCLCPP_INFO(this->get_logger(),"请求目标点处理失败"); } }); }); } /**发送请求 */ SetP::Response::SharedPtr call_set_parameters(const rcl_interfaces::msg::Parameter ¶m) { auto param_client_ = this->create_client("/turtle_controller/set_parameters"); //1检测服务端是否上线 while(!patrol_client_->wait_for_service(1s)){ RCLCPP_ERROR(this->get_logger(),"等待服务上线过程中,rclcpp异常,退出"); return nullptr; } RCLCPP_INFO(this->get_logger(),"等待服务上线...."); //2 构造请求对象 auto request = std::make_shared(); request->parameters.push_back(param);//添加数据 //3 发送请求 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; } /**更新参数 */ void update_param_k(double k) { //1 创建请求参数 auto param = rcl_interfaces::msg::Parameter(); param.name = "k"; //2 创建请求参数值 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; //3. 请求更新参数并处理 auto response = this->call_set_parameters(param); if(response == NULL){ 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(), "参数修改失败,reason:%s",result.reason.c_str()); } } } } private: rclcpp::TimerBase::SharedPtr timer_; rclcpp::Client::SharedPtr patrol_client_; }; int main(int argc,char *argv[]) { rclcpp::init(argc,argv); auto node = std::make_shared(); node->update_param_k(4.0); rclcpp::spin(node); rclcpp::shutdown(); return 0; } ``` 增加了call_set_parameters、update_param_k 两个方法,在main增加update_param_k调用。 构建后启动服务端、与客户端。日志分别如下: bohu@bohu-TM1701:\~/chapt4/chapt4_ws$ ros2 run demo_cpp_service turtle_control \[INFO\] \[1736431217.835118418\] \[turtle_controller\]: 更新参数的值k=4.000000 客户端: bohu@bohu-TM1701:\~/chapt4/chapt4_ws$ ros2 run demo_cpp_service patrol_client \[INFO\] \[1736431217.834569546\] \[patrol_client\]: 等待服务上线.... \[INFO\] \[1736431217.836297268\] \[patrol_client\]: 参数K已经修改为:4.000000

相关推荐
✿ ༺ ོIT技术༻6 分钟前
C++11:包装器(适配器模式)
开发语言·c++
_zwy22 分钟前
【C++ 多态】—— 礼器九鼎,釉下乾坤,多态中的 “风水寻龙诀“
c语言·开发语言·c++
倔强的石头10643 分钟前
【C++指南】vector(一):从入门到详解
开发语言·c++
珹洺2 小时前
C++从入门到实战(十)类和对象(最终部分)static成员,内部类,匿名对象与对象拷贝时的编译器优化详解
java·数据结构·c++·redis·后端·算法·链表
写bug的小屁孩2 小时前
移动零+复写零+快乐数+盛最多水的容器+有效三角形的个数
c++·算法·双指针
DARLING Zero two♡2 小时前
C++底层学习精进:模板进阶
开发语言·c++·模板
勘察加熊人3 小时前
c++生成html文件helloworld
开发语言·c++·html
羑悻的小杀马特3 小时前
【狂热算法篇】探寻图论幽径:Bellman - Ford 算法的浪漫征程(通俗易懂版)
c++·算法·图论·bellman_ford算法
basketball6167 小时前
C++ STL常用算法之常用排序算法
c++·算法·排序算法
moz与京7 小时前
[附C++,JS,Python题解] Leetcode 面试150题(10)——轮转数组
c++·python·leetcode