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

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

4.5.1 参数声明与设置

打开src/demo_cpp_service/src/turtle_control.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.

#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代码

#include <chrono>
#include <cstdlib>
#include <ctime>
#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>("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<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 发送请求
            this->patrol_client_->async_send_request(request,[&](rclcpp::Client<Patrol>::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 &param)
    {
        auto param_client_ = this->create_client<SetP>("/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<SetP::Request>();
        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<Patrol>::SharedPtr patrol_client_;
};

int main(int argc,char *argv[])
{
    rclcpp::init(argc,argv);
    auto node = std::make_shared<PatrolClient>();
    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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/951295.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java agent

‌ Java Agent是一种特殊的Java程序&#xff0c;它可以在JVM启动时或运行时动态加载&#xff0c;用于监控和修改其他Java应用程序的行为‌。通过Java Agent&#xff0c;开发者可以在不修改目标应用程序源码的情况下&#xff0c;动态地插入功能&#xff0c;如性能分析、日志记录…

Cannot run program “docker“: CreateProcess error=2,系统找不到指定的文件

今天被这个问题坑了, 网上教程全是直接装插件就行 ,结果我连接可以成功 但是执行docker compose 就会出错, 检测配置 报错com.intellil,execution,process.ProcessNotCreatedException: Cannot run program “docker”: CreateProcess error2,系统找不到指定的文件 gpt 要我去…

二、模型训练与优化(4):模型优化-实操

下面我将以 MNIST 手写数字识别模型为例&#xff0c;从 剪枝 (Pruning) 和 量化 (Quantization) 两个常用方法出发&#xff0c;提供一套可实际动手操作的模型优化流程。此示例基于 TensorFlow/Keras 环境&#xff0c;示范如何先训练一个基础模型&#xff0c;然后对其进行剪枝和…

免费图片批量压缩工具-支持批量修改分辨率

工作需求&#xff0c;需要支持修改分辨率上限的同时进行图片压缩&#xff0c;设计此工具。 1.支持批量文件夹、子文件 2.支持最大分辨率上限&#xff08;高于设定分辨率的图片&#xff0c;强制修改为指定分辨率&#xff0c;解决大图的关键&#xff09; 3.自定义压缩质量&#x…

Github上传项目

写在前面&#xff1a; 本次博客仅仅是个人学习记录&#xff0c;不具备教学作用。内容整理来自网络&#xff0c;太多了&#xff0c;所以就不放来源了。 在github页面的准备&#xff1a; 输入标题。 往下滑&#xff0c;创建 创建后会跳出下面的页面 进入home就可以看到我们刚…

并发编程 之 Java内存模型(详解)

Java 内存模型&#xff08;JMM&#xff0c;Java Memory Model&#xff09;可以说是并发编程的基础&#xff0c;跟众所周知的Java内存区域(堆、栈、程序计数器等)并不是一个层次的划分&#xff1b; JMM用来屏蔽各种硬件和操作系统的内存访问差异&#xff0c;以实现让Java程序在各…

[QCustomPlot] 交互示例 Interaction Example

本文是官方例子的分析: Interaction Example 推荐笔记: qcustomplot使用教程–基本绘图 推荐笔记: 4.QCustomPlot使用-坐标轴常用属性 官方例子需要用到很多槽函数, 这里先一次性列举, 自行加入到qt的.h中.下面开始从简单的开始一个个分析. void qcustomplot_main_init(void); …

WPF控件Grid的布局和C1FlexGrid的多选应用

使用 Grid.Column和Grid.Row布局&#xff0c;将多个C1FlexGrid布局其中&#xff0c;使用各种事件来达到所需效果&#xff0c;点击复选框可以加载数据到列表&#xff0c;移除列表的数据&#xff0c;自动取消复选框等 移除复选框的要注意&#xff01;&#xff01;&#xff01;&am…

04、Redis深入数据结构

一、简单动态字符串SDS 无论是Redis中的key还是value&#xff0c;其基础数据类型都是字符串。如&#xff0c;Hash型value的field与value的类型&#xff0c;List型&#xff0c;Set型&#xff0c;ZSet型value的元素的类型等都是字符串。redis没有使用传统C中的字符串而是自定义了…

生物医学信号处理--随机信号的数字特征

前言 概率密度函数完整地表现了随机变量和随机过程的统计性质。但是信号经处理后再求其概率密度函数往往较难&#xff0c;而且往往也并不需要完整地了解随机变量或过程的全部统计性质只要了解其某些特定方面即可。这时就可以引用几个数值来表示该变量或过程在这几方面的特征。…

LabVIEW数据库管理系统

LabVIEW数据库管理系统&#xff08;DBMS&#xff09;是一种集成了数据库技术与数据采集、控制系统的解决方案。通过LabVIEW的强大图形化编程环境&#xff0c;结合数据库的高效数据存储与管理能力&#xff0c;开发人员可以实现高效的数据交互、存储、查询、更新和报告生成。LabV…

合并模型带来的更好性能

研究背景与问题提出 在人工智能领域&#xff0c;当需要处理多个不同任务时&#xff0c;有多种方式来运用模型资源。其中&#xff0c;合并多个微调模型是一种成本效益相对较高的做法&#xff0c;相较于托管多个专门针对不同任务设计的模型&#xff0c;能节省一定成本。然而&…

Virgo:增强慢思考推理能力的多模态大语言模型

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

本地缓存:Guava Cache

这里写目录标题 一、范例二、应用场景三、加载1、CacheLoader2、Callable3、显式插入 四、过期策略1、基于容量的过期策略2、基于时间的过期策略3、基于引用的过期策略 五、显示清除六、移除监听器六、清理什么时候发生七、刷新八、支持更新锁定能力 一、范例 LoadingCache<…

Android adb shell GPU信息

Android adb shell GPU信息 先 adb shell 进入控制台。 然后&#xff1a; dumpsys | grep GLES Android adb shell命令捕获systemtrace_android 抓trace-CSDN博客文章浏览阅读2.5k次&#xff0c;点赞2次&#xff0c;收藏8次。本文介绍了如何使用adbshell命令配合perfetto工…

ElasticSearch | Elasticsearch与Kibana页面查询语句实践

关注&#xff1a;CodingTechWork 引言 在当今大数据应用中&#xff0c;Elasticsearch&#xff08;简称 ES&#xff09;以其高效的全文检索、分布式处理能力和灵活的查询语法&#xff0c;广泛应用于各类日志分析、用户行为分析以及实时数据查询等场景。通过 ES&#xff0c;用户…

RK3588平台开发系列讲解(系统篇)Linux Kconfig的语法

文章目录 一、什么是Kconfig二、config模块三、menuconfig四、menu 和 endmenu五、choice 和 endchoice六、source七、depends on八、default九、help十、逻辑表达式沉淀、分享、成长,让自己和他人都能有所收获!😄 一、什么是Kconfig Kconfig的语法及代码结构非常简单。本博…

STM32 USB组合设备 MSC CDC

STM32 USB组合设备 MSC CDC实现 教程 教程请看大佬niu_88 手把手教你使用USB的CDCMSC复合设备&#xff08;基于stm32f407&#xff09; 大佬的教程很好&#xff0c;很详细&#xff0c;我调出来了&#xff0c;代码请见我绑定的资源 注意事项 值得注意的是&#xff1a; 1、 cu…

深入学习RabbitMQ的Direct Exchange(直连交换机)

RabbitMQ作为一种高性能的消息中间件&#xff0c;在分布式系统中扮演着重要角色。它提供了多种消息传递模式&#xff0c;其中Direct Exchange&#xff08;直连交换机&#xff09;是最基础且常用的一种。本文将深入介绍Direct Exchange的原理、应用场景、配置方法以及实践案例&a…

Node.js——path(路径操作)模块

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…