Robot Operating System——初探动态配置Parameters

news2024/9/21 2:33:01

大纲

  • 同步模式
    • Node内使用declare_parameter方法声明Parameters
    • 创建Parameter同步访问客户端
    • 跨Node修改Parameters
    • 跨Node查询Parameters
    • 完整代码
    • 运行结果
  • 异步模式
    • 创建Node,设置Parameters
    • 创建Parameter异步访问客户端
    • 异步设置,同步等待
    • 异步查询,同步等待
    • 完整代码
  • 总结

当我们程序写完后,如果需要修改程序中的某个配置,可以通过三种方案进行:

  • 通过文件。修改文件内容,并让程序动态加载这个文件,进而动态修改配置。
  • 通过网路。可以通过网络接口,让程序暴露一些接口用于修改其内部配置。
  • 通过进程间通信。对于在一台机器上的进程,可以通过进程间通信,通知程序修改配置。

而在ROS 2中,它提供了一种叫做Parameters的技术,辅助我们快速修改配置。

需要注意的是,在ROS 2中,配置是和Node相关的,即Parameter从属于Node。

我们通过demo_nodes_cpp/src/parameters/set_and_get_parameters.cpp和demo_nodes_cpp/src/parameters/set_and_get_parameters_async.cpp的例子来讲解如何在外部设置、获取一个Node上的Parameters。

同步模式

我们在一个叫set_and_get_parameters的Node中做相关实验(demo_nodes_cpp/src/parameters/set_and_get_parameters.cpp)。这样我们就可以直接使用继承于Node的方法来操作。

需要注意的是,Node自身也是一个设置/获取Parameters值的服务端。后面我们会看到如何使用客户端来向这个服务端来设置和查询Parameters的值。

class SetAndGetParameters : public rclcpp::Node
{
public:
  DEMO_NODES_CPP_PUBLIC
  explicit SetAndGetParameters(const rclcpp::NodeOptions & options)
  : Node("set_and_get_parameters", options)
  {
    setvbuf(stdout, NULL, _IONBF, BUFSIZ);

Node内使用declare_parameter方法声明Parameters

Node的declare_parameter方法用于设置一些parameter的Key和Value。

    this->declare_parameter("foo", 0);
    this->declare_parameter("bar", "");
    this->declare_parameter("baz", 0.);
    this->declare_parameter("foobar", false);
    this->declare_parameter("foobarbaz", std::vector<bool>{});
    this->declare_parameter("toto", std::vector<uint8_t>{});

创建Parameter同步访问客户端

构建rclcpp::SyncParametersClient时,我们传入的this指针就是即将创建的客户端要访问的Node节点。

    auto parameters_client = std::make_shared<rclcpp::SyncParametersClient>(this);
    while (!parameters_client->wait_for_service(1s)) {
      if (!rclcpp::ok()) {
        RCLCPP_ERROR(this->get_logger(), "Interrupted while waiting for the service. Exiting.");
        rclcpp::shutdown();
      }
      RCLCPP_INFO(this->get_logger(), "service not available, waiting again...");
    }

SyncParametersClient有三个参数。如果只指定了Node节点,说明这个节点是在我们程序内部创建的。这样就不需要跨网络,而是可以直接启动一个线程来访问,形成异步请求。

  template<typename NodeT>
  explicit SyncParametersClient(
    std::shared_ptr<NodeT> node,
    const std::string & remote_node_name = "",
    const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
  : SyncParametersClient(
      std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
      node,
      remote_node_name,
      qos_profile)
  {}

跨Node修改Parameters

SyncParametersClient的set_parameters接收一个rclcpp::Parameter组成的vector,返回表达操作结果的std::vector<rcl_interfaces::msg::SetParametersResult>。我们可以遍历这个返回结果,查看哪个设置失败了。

    // Set several different types of parameters.
    auto set_parameters_results = parameters_client->set_parameters(
      {
        rclcpp::Parameter("foo", 2),
        rclcpp::Parameter("bar", "hello"),
        rclcpp::Parameter("baz", 1.45),
        rclcpp::Parameter("foobar", true),
        rclcpp::Parameter("foobarbaz", std::vector<bool>({true, false})),
        rclcpp::Parameter("toto", std::vector<uint8_t>({0xff, 0x7f})),
      });
    // Check to see if they were set.
    for (auto & result : set_parameters_results) {
      if (!result.successful) {
        RCLCPP_ERROR(this->get_logger(), "Failed to set parameter: %s", result.reason.c_str());
      }
    }

跨Node查询Parameters

SyncParametersClient的get_parameters方法也接收一个由Key做成的vector。我们可以通过它来查询到该客户端连接的Node中,这些Key对应的Value。

    std::stringstream ss;
    // Get a few of the parameters just set.
    for (
      auto & parameter : parameters_client->get_parameters(
        {"foo", "baz", "foobarbaz", "toto"}))
    {
      ss << "\nParameter name: " << parameter.get_name();
      ss << "\nParameter value (" << parameter.get_type_name() << "): " <<
        parameter.value_to_string();
    }
    RCLCPP_INFO(this->get_logger(), "%s", ss.str().c_str());

完整代码

// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <chrono>
#include <memory>
#include <sstream>
#include <vector>

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_components/register_node_macro.hpp"

#include "demo_nodes_cpp/visibility_control.h"

using namespace std::chrono_literals;

namespace demo_nodes_cpp
{

class SetAndGetParameters : public rclcpp::Node
{
public:
  DEMO_NODES_CPP_PUBLIC
  explicit SetAndGetParameters(const rclcpp::NodeOptions & options)
  : Node("set_and_get_parameters", options)
  {
    setvbuf(stdout, NULL, _IONBF, BUFSIZ);
    this->declare_parameter("foo", 0);
    this->declare_parameter("bar", "");
    this->declare_parameter("baz", 0.);
    this->declare_parameter("foobar", false);
    this->declare_parameter("foobarbaz", std::vector<bool>{});
    this->declare_parameter("toto", std::vector<uint8_t>{});

    auto parameters_client = std::make_shared<rclcpp::SyncParametersClient>(this);
    while (!parameters_client->wait_for_service(1s)) {
      if (!rclcpp::ok()) {
        RCLCPP_ERROR(this->get_logger(), "Interrupted while waiting for the service. Exiting.");
        rclcpp::shutdown();
      }
      RCLCPP_INFO(this->get_logger(), "service not available, waiting again...");
    }

    // Set several different types of parameters.
    auto set_parameters_results = parameters_client->set_parameters(
      {
        rclcpp::Parameter("foo", 2),
        rclcpp::Parameter("bar", "hello"),
        rclcpp::Parameter("baz", 1.45),
        rclcpp::Parameter("foobar", true),
        rclcpp::Parameter("foobarbaz", std::vector<bool>({true, false})),
        rclcpp::Parameter("toto", std::vector<uint8_t>({0xff, 0x7f})),
      });
    // Check to see if they were set.
    for (auto & result : set_parameters_results) {
      if (!result.successful) {
        RCLCPP_ERROR(this->get_logger(), "Failed to set parameter: %s", result.reason.c_str());
      }
    }

    std::stringstream ss;
    // Get a few of the parameters just set.
    for (
      auto & parameter : parameters_client->get_parameters(
        {"foo", "baz", "foobarbaz", "toto"}))
    {
      ss << "\nParameter name: " << parameter.get_name();
      ss << "\nParameter value (" << parameter.get_type_name() << "): " <<
        parameter.value_to_string();
    }
    RCLCPP_INFO(this->get_logger(), "%s", ss.str().c_str());

    rclcpp::shutdown();
  }
};

}  // namespace demo_nodes_cpp

RCLCPP_COMPONENTS_REGISTER_NODE(demo_nodes_cpp::SetAndGetParameters)

运行结果

./build/demo_nodes_cpp/set_and_get_parameters

在这里插入图片描述
可以看到查询到的值都是修改后的值。

异步模式

我们参考demo_nodes_cpp/src/parameters/set_and_get_parameters_async.cpp的例子,看看异步设置和查询Parameters是如何做到的。

创建Node,设置Parameters

这次我们不在Node中执行逻辑,而是在Main函数中。这样我们就需要创建一个Node,然后给这个Node声明一批Parameters。

int main(int argc, char ** argv)
{
  // Force flush of the stdout buffer.
  setvbuf(stdout, NULL, _IONBF, BUFSIZ);

  rclcpp::init(argc, argv);

  auto node = rclcpp::Node::make_shared("set_and_get_parameters_async");

  // Declare parameters that may be set on this node
  node->declare_parameter("foo", 0);
  node->declare_parameter("bar", "");
  node->declare_parameter("baz", 0.);
  node->declare_parameter("foobar", false);
  node->declare_parameter("foobarbaz", std::vector<bool>{});
  node->declare_parameter("toto", std::vector<uint8_t>{});

创建Parameter异步访问客户端

这次我们创建的对象是rclcpp::AsyncParametersClient,它要操作的Node就是上面我们创建的"set_and_get_parameters_async"。

  auto parameters_client = std::make_shared<rclcpp::AsyncParametersClient>(node);
  while (!parameters_client->wait_for_service(1s)) {
    if (!rclcpp::ok()) {
      RCLCPP_ERROR(node->get_logger(), "Interrupted while waiting for the service. Exiting.");
      return 0;
    }
    RCLCPP_INFO(node->get_logger(), "service not available, waiting again...");
  }

异步设置,同步等待

由于这次是异步设置Parameters,所以我们需要等待set_parameters返回的结果。直到rclcpp::spin_until_future_complete完成了针对上述Node的等待,再遍历这个结构体,查询是不是每个设置都是成功的。

  // Set several different types of parameters.
  auto results = parameters_client->set_parameters(
  {
    rclcpp::Parameter("foo", 2),
    rclcpp::Parameter("bar", "hello"),
    rclcpp::Parameter("baz", 1.45),
    rclcpp::Parameter("foobar", true),
    rclcpp::Parameter("foobarbaz", std::vector<bool>({true, false})),
    rclcpp::Parameter("toto", std::vector<uint8_t>({0xff, 0x7f})),
  });
  // Wait for the results.
  if (rclcpp::spin_until_future_complete(node, results) !=
    rclcpp::FutureReturnCode::SUCCESS)
  {
    RCLCPP_ERROR(node->get_logger(), "set_parameters service call failed. Exiting tutorial.");
    return -1;
  }
  // Check to see if they were set.
  for (auto & result : results.get()) {
    if (!result.successful) {
      RCLCPP_ERROR(node->get_logger(), "Failed to set parameter: %s", result.reason.c_str());
    }
  }

异步查询,同步等待

AsyncParametersClient的get_parameters也是异步请求,返回的是std::vector<rclcpp::Parameter>。我们还是需要使用rclcpp::spin_until_future_complete来等到Node完成此次查询请求。等到查询完成才可以遍历访问查询到的数据。

  auto parameters = parameters_client->get_parameters({"foo", "baz", "foobarbaz", "toto"});
  if (rclcpp::spin_until_future_complete(node, parameters) !=
    rclcpp::FutureReturnCode::SUCCESS)
  {
    RCLCPP_ERROR(node->get_logger(), "get_parameters service call failed. Exiting tutorial.");
    return -1;
  }
  std::stringstream ss;
  for (auto & parameter : parameters.get()) {
    ss << "\nParameter name: " << parameter.get_name();
    ss << "\nParameter value (" << parameter.get_type_name() << "): " <<
      parameter.value_to_string();
  }
  RCLCPP_INFO(node->get_logger(), "%s", ss.str().c_str());

完整代码

// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <chrono>
#include <memory>
#include <sstream>
#include <vector>

#include "rclcpp/rclcpp.hpp"

using namespace std::chrono_literals;

int main(int argc, char ** argv)
{
  // Force flush of the stdout buffer.
  setvbuf(stdout, NULL, _IONBF, BUFSIZ);

  rclcpp::init(argc, argv);

  auto node = rclcpp::Node::make_shared("set_and_get_parameters_async");

  // Declare parameters that may be set on this node
  node->declare_parameter("foo", 0);
  node->declare_parameter("bar", "");
  node->declare_parameter("baz", 0.);
  node->declare_parameter("foobar", false);
  node->declare_parameter("foobarbaz", std::vector<bool>{});
  node->declare_parameter("toto", std::vector<uint8_t>{});

  auto parameters_client = std::make_shared<rclcpp::AsyncParametersClient>(node);
  while (!parameters_client->wait_for_service(1s)) {
    if (!rclcpp::ok()) {
      RCLCPP_ERROR(node->get_logger(), "Interrupted while waiting for the service. Exiting.");
      return 0;
    }
    RCLCPP_INFO(node->get_logger(), "service not available, waiting again...");
  }

  // Set several different types of parameters.
  auto results = parameters_client->set_parameters(
  {
    rclcpp::Parameter("foo", 2),
    rclcpp::Parameter("bar", "hello"),
    rclcpp::Parameter("baz", 1.45),
    rclcpp::Parameter("foobar", true),
    rclcpp::Parameter("foobarbaz", std::vector<bool>({true, false})),
    rclcpp::Parameter("toto", std::vector<uint8_t>({0xff, 0x7f})),
  });
  // Wait for the results.
  if (rclcpp::spin_until_future_complete(node, results) !=
    rclcpp::FutureReturnCode::SUCCESS)
  {
    RCLCPP_ERROR(node->get_logger(), "set_parameters service call failed. Exiting tutorial.");
    return -1;
  }
  // Check to see if they were set.
  for (auto & result : results.get()) {
    if (!result.successful) {
      RCLCPP_ERROR(node->get_logger(), "Failed to set parameter: %s", result.reason.c_str());
    }
  }

  // Get a few of the parameters just set.
  auto parameters = parameters_client->get_parameters({"foo", "baz", "foobarbaz", "toto"});
  if (rclcpp::spin_until_future_complete(node, parameters) !=
    rclcpp::FutureReturnCode::SUCCESS)
  {
    RCLCPP_ERROR(node->get_logger(), "get_parameters service call failed. Exiting tutorial.");
    return -1;
  }
  std::stringstream ss;
  for (auto & parameter : parameters.get()) {
    ss << "\nParameter name: " << parameter.get_name();
    ss << "\nParameter value (" << parameter.get_type_name() << "): " <<
      parameter.value_to_string();
  }
  RCLCPP_INFO(node->get_logger(), "%s", ss.str().c_str());

  rclcpp::shutdown();

  return 0;
}

总结

本文的两个例子,分别使用SyncParametersClient和AsyncParametersClient从Node外部设置和查询Node的Parameters。实际我们在Node内部可以通过Node类中的set_parameter方法操作本Node的Parameters。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VMware三种网络模式---巨细

文章目录 目录 ‘一.网络模式概述 二.桥接模式 二.NAT模式 三.仅主机模式 四.案例演示 防火墙配置&#xff1a; 虚拟电脑配置 前言 本文主要介绍VMware的三种网络模式 ‘一.网络模式概述 VMware中分为三种网络模式&#xff1a; 桥接模式&#xff1a;默认与宿主机VMnet0绑…

CSP-J模拟赛day1——解析+答案

题目传送门 yjq的吉祥数 题解 送分题&#xff0c;暴力枚举即可 Code #include<bits/stdc.h> using namespace std;int l,r; int num1,tmp0,q[10000],a[10000]; int k (int x){for (int j1;j<tmp;j){if (xq[j])return 0;}return 1; } int main(){while (num<100…

php连接sql server

php连接sqlserver有三种方式 一&#xff1a;odbc连接&#xff0c;废话不多说直接上代码,封装了一个单例 <?php /*** odbcServer.php* Author: Erekys*/namespace App\Model; class odbcServer{public static $server;public static $username;public static $password;pu…

dora-rs学习之Rust 和机器人

最近在研究一个网红机器人框架 dora-rs&#xff0c;也看到一些具身智能相关&#xff0c;做机器人遥操作与数据采集及可视化系统的公司使用rust来开发&#xff0c;这里探讨一下dora-rs和rust给机器人带来什么&#xff0c;引述官方的描述&#xff1a;Hello from dora-rs | dora-r…

svelte - 5. 动画

svelte/motion模块导出两个函数&#xff1a; tweened 和 spring。 用于创建writable&#xff08;可写&#xff09;store&#xff0c;其值会在set 和 update之后更新&#xff0c;而不是立即更新。 &#xff08;人话&#xff1a;用 svelte 提供的tweened 和 spring可以达成流程变…

数学建模学习(1)遗传算法

一、简介 遗传算法&#xff08;Genetic Algorithm, GA&#xff09;是一种用于解决优化和搜索问题的进化算法。它基于自然选择和遗传学原理&#xff0c;通过模拟生物进化过程来寻找最优解。 以下是遗传算法的主要步骤和概念&#xff1a; 初始化种群&#xff08;Initialization&a…

react中嵌套路由以及默认显示二级路由

1.安装插件 npm install react-router-dom 2.新建文件及页面 在scr/page下新建layout、about、home文件夹&#xff0c;分别在对应的文件夹下新建入口文件index.js&#xff1b;src下新建router文件夹&#xff0c;该文件夹下新建入口文件index.js 3.配置路由 如何配置路由&am…

昇思学习打卡-25-自然语言处理/RNN实现情感分类

文章目录 数据下载加载预训练词向量数据集预处理模型构建损失函数与优化器训练逻辑评估指标和逻辑模型训练与保存模型加载与测试自定义输入测试测试 情感分类是自然语言处理中的经典任务&#xff0c;是典型的分类问题。本节使用MindSpore实现一个基于RNN网络的情感分类模型&…

android audio不同音频流,(六)settings内音频流音量调整

&#xff08;1&#xff09;settings内&#xff0c;可设置音频流音量&#xff0c;如下图&#xff1a; &#xff08;2&#xff09;settings调整音量条进度&#xff0c;会触发SeekBarVolumizer对象&#xff1a; SeekBarVolumizer文件路径&#xff1a; frameworks/base/core/java/…

设计模式13-单件模式

设计模式13-单件模式 写在前面对象性能模式典型模式1. 单例模式&#xff08;Singleton Pattern&#xff09;2. 享元模式&#xff08;Flyweight Pattern&#xff09;3. 原型模式&#xff08;Prototype Pattern&#xff09;4. 对象池模式&#xff08;Object Pool Pattern&#xf…

WebRTC QoS方法十三.2(Jitter延时的计算)

一、背景介绍 一些报文在网络传输中&#xff0c;会存在丢包重传和延时的情况。渲染时需要进行适当缓存&#xff0c;等待丢失被重传的报文或者正在路上传输的报文。 jitter延时计算是确认需要缓存的时间 另外&#xff0c;在检测到帧有重传情况时&#xff0c;也可适当在渲染时…

无人机图像目标检测技术详解

当前研究领域的热点之一。无人机搭载的高清摄像头能够实时捕获大量图像数据&#xff0c;对这些数据进行有效的目标检测对于军事侦察、环境监测、灾害救援等领域具有重要意义。本文将对无人机图像目标检测技术进行详解&#xff0c;包括图像处理技术、目标检测算法、关键技术应用…

LoFTR关键点特征匹配算法环境构建与图像匹配测试Demo

0&#xff0c;LoFTR CVPR 2021论文《LoFTR: Detector-Free Local Feature Matching with Transformers》开源代码 1&#xff0c;项目主页 LoFTR: Detector-Free Local Feature Matching with Transformers 2&#xff0c;GItHub主页 GitHub - zju3dv/LoFTR: Code for "…

Gen AI核心技术发展趋势分析

Gen AI核心技术解析及发展趋势 判别式模型&#xff0c;适用于处理回归与分类任务&#xff0c;其核心在于精准区分各类数据。与生成模型的生成新数据不同&#xff0c;判别模型专注于揭示输入特征与输出标签之间的紧密联系&#xff0c;从而实现准确分类或预测。在众多应用领域&am…

VS Code打开新文件会覆盖之前的窗口,解决办法

当我在VS Code中打开文件夹时&#xff0c;文件夹中只有一个文件能展示在窗口中&#xff0c;如果点击打开另外一个文件&#xff0c;之前打开的文件又会被覆盖。这样是无法进行文件之间的关联查找的。 要保证窗口可以打开多个文件&#xff0c;有不同的tab显示&#xff0c;设置如下…

好用的电脑屏幕监控软件推荐,什么软件能够监控电脑?

在当今信息化时代&#xff0c;电脑屏幕监控软件成为了企业管理、家长监管以及教育培训等领域的必备工具。通过实时监控电脑屏幕&#xff0c;这类软件可以有效提高工作效率&#xff0c;防止信息泄露&#xff0c;保障网络安全。本文将详细盘点几款主流的电脑屏幕监控软件&#xf…

PHP基础语法(四)

一、字符串类型 1、字符串定义语法 1&#xff09;单引号字符串&#xff1a;在单引号内部&#xff0c;所有的字符都会按照字面意义解释&#xff0c;不会进行变量替换或转义处理&#xff0c;除了 \ 表示单引号本身。 $str1 Hello, World!;2&#xff09;双引号字符串&#xff…

【机器学习算法基础】(基础机器学习课程)-08-决策树和随机森林-笔记

一、决策树之信息论基础 决策树是一种用来做决策的工具&#xff0c;就像我们生活中的选择树。例如&#xff0c;你在选择今天穿什么衣服时&#xff0c;会根据天气情况、出行活动等进行判断。决策树的构建过程涉及一些信息论的概念&#xff0c;用来衡量和选择最好的“分叉点”来进…

Unity打包设置

1.Resolution and Presentation (分辨率和显示) Fullscreen Window (全屏窗口): 应用程序将以全屏窗口模式运行&#xff0c;但不会独占屏幕。适用于想要全屏显示但仍需访问其他窗口的情况。 Resizable Window (可调整大小的窗口): 允许用户调整应用程序窗口的大小。适用于窗口…

Action通信 实践案例

Action通信 Server端实现 创建服务端功能包&#xff08;注意目录层级&#xff09;&#xff1a; ros2 pkg create my_exer05_action_server --build-type ament_cmake --node-name nav_server --dependencies rclcpp rclcpp_action my_exer_interfaces nav_msgs /*需求&#x…