ROS2 中的轻量级、自动化、受控回放

一、说明

这篇文章描述了一种在 ROS2 中实现受控重播器的轻量级方法。用以测试中将现象重新播放一遍,以实现调参或故障定位的目的。所有源代码都可以在这里找到。该帖子也可在此处获得。

二、问题:不同步重播

        任何曾经认真开发过 ROS2 的人都会知道这个问题:我们想调试我们的管道或改进算法的微小部分,但当我们反复运行管道时,我们得到了不同的结果。如果我们处于开发的早期阶段,并且我们的管道运行速度不够快,无法实时处理所有数据,我们最终会丢失消息。如果我们在代码中放置断点,我们最终会丢失消息。如果我们在后台的同一台机器上发生了一些完全不相关但半繁重的处理,我们最终会丢失消息。最糟糕的是,症状在每次运行之间可能会有所不同,从完全系统故障到对结果的影响最小,因此我们通常不会直接意识到消息丢失可能是问题所在。

        当然,我们可以非常缓慢地重播所有数据。但是,我们最终会永远等待,直到重播达到我们感兴趣的点。同样,如果我们想在CI服务器上运行管道,我们通常不知道有多少计算资源可用以及我们可以多快地运行我们的系统。

        总结:重播器以固定速率重播其消息,对于算法管道来说,这可能是快或慢。因此,我们要么失去时间,要么得到不确定的结果。

三、方法:受控回放

        解决这个问题的基本思想非常简单:我们需要一个考虑到管道当前状态的受控重放。然而,由于ROS2s的异步和松散耦合设计,实现这一点并非易事。特别是因为我们不想用“仅”开发所需的机制来混淆整个系统。

        不幸的是,ROS2 没有针对这个(在我看来非常明显)问题的构建解决方案。当然,它是开源的,我们可以着手实现我们自己的 ros bag 重播器。但是,如上所述,我们希望在框架内开发一种算法。我们不想先实现框架。幸运的是,到目前为止,ROS2工具已经发展了很多,并且只需相对较少的努力,我们就可以应用一种在实践中可以很好地工作的解决方法。

        这个概念是有一个额外的节点,就像重播者的遥控器一样。每当所有节点通知远程节点它们已准备就绪时,它都会触发新消息的重播。

四、实施

        使用服务客户端体系结构可以相对直接地完成实现,如下所述。包括一个小示例在内的所有代码都可以在这里找到。它也可以很容易地作为 ROS 包包含在内。

        远程是一个附加节点,充当rosbag2_replayer的代理。它使用“突发”服务每 T 秒触发接下来的 N 条消息,并等待每个节点的确认。实现自定义服务确实在调用方的身份旁边传输“就绪”信号。不幸的是,当我们使用突发调用“跳过”袋子时,重播者不会自动关闭。因此,额外的计时器会定期检查模拟时间是否仍在增加,以确定重播是否已结束。这要求重播者发布时钟(-clock),并使用 use-sim-time 参数集运行遥控器。然后,节点可以在重放结束时关闭自身/其整个组合。

        我们可以将其作为可组合节点包含,也可以通过以下方式启动它:

ros2 run controllable_replay remote --ros-args -p use_sim_time:=True -p batch_size:=10 -p period:=0.01 -p automatic_shutdown:=5

这将每 10 毫秒播放 10 条消息,并在重播者处于非活动状态 5 秒后关闭节点。

五、算法节点

        在算法方面,我们需要一些逻辑来通知遥控器我们已经准备好了。在简单节点中,我们可以在每个回调的末尾添加它。在更复杂的节点中,消息和回调之间可能没有一对一的映射。在这种情况下,需要一些额外的逻辑来监视节点的工作负载,例如通过观察输入队列大小。

        对于一个简单的示例,我们将创建一个字符串侦听器节点,该节点计算收到的消息数并模拟具有特定时间长度的繁重任务。任务完成后,它将发布自己的消息并通知远程设备已准备就绪。

#include "Listener.h"
using namespace std::chrono_literals; 
namespace controlled_replay_example { 
Listener::Listener(const rclcpp::NodeOptions& options) : 
rclcpp::Node("Listener", options),
_cliReady{create_client<controlled_replay_interfaces::srv::Ready>("/ready")},
_pub{create_publisher<std_msgs::msg::String>("/hearsay", 10)},
_sub{create_subscription<std_msgs::msg::String>( "/chatter", 10, [&](std_msgs::msg::String::ConstSharedPtr msg) { _ctr++; std::this_thread::sleep_for(get_parameter("task_time").as_double() * 1000ms); // heavy taskauto rq = std::make_shared<controlled_replay_interfaces::srv::Ready::Request>();rq->isready = true; _cliReady->async_send_request(rq); // inform replayer})}, _timer{create_wall_timer(1s, [&]() { RCLCPP_INFO(get_logger(), "Received messages: %ld", _ctr); })} 
{ declare_parameter("task_time", 1.0); } } 
// namespace controlled_replay_example 
#include "rclcpp_components/register_node_macro.hpp" 
RCLCPP_COMPONENTS_REGISTER_NODE(controlled_replay_example::Listener)

我们使用一个包含 464 个字符串消息的包以 100hz 的速率测试上面的示例。我们将模拟一个算法管道,其中包含两个具有不同时间长度的链节点。第一个节点将以 100hz 运行,但第二个节点仅以 2hz 运行。因此,从理论上讲,第一个节点应该能够处理所有消息,但第二个节点会错过一些消息。

在第一次运行中,我们将在没有远程的情况下简单地运行管道。

#!/bin/bash 
ros2 run controlled_replay_example listener --ros-args -p task_time:=0.01 -r __node:=listener1 & 
ros2 run controlled_replay_example listener --ros-args -p task_time:=0.5 -r __node:=listener2 -r chatter:=hearsay -r hearsay:=hearsay1& 
ros2 bag play bag

重放期间的节点图

[INFO] [1695973373.033875499] [listener2]: Received messages: 8 
[INFO] [1695973373.732552274] [listener1]: Received messages: 445

我们可以看到,即使是第一个节点也丢失了一些消息。但是,第一个只处理了8个!

在第二次运行中,我们将使用远程运行管道。


#!/bin/bash
ros2 run controlled_replay_example listener --ros-args -p task_time:=0.01 -r __node:=listener1 &
ros2 run controlled_replay_example listener --ros-args -p task_time:=0.5 -r __node:=listener2 -r chatter:=hearsay -r hearsay:=hearsay1 &
ros2 run controlled_replay remote --ros-args -p batch_size:=1 -p use_sim_time:=True &
ros2 bag play --clock --start-paused bag

具有受控回放的节点图

[INFO] [1695973373.033875499] [listener2]: Received messages: 464 
[INFO] [1695973373.732552274] [listener1]: Received messages: 464

我们可以看到两个节点都收到了所有消息。

六、结论

        我们已经看到了一种在 ROS2 中获得可控重放的简单方法。通过添加一个额外的远程节点,我们可以将大部分任务封装在远离实际管道的地方。遥控器将重播速度减慢到节点可以处理的任何速度,从而避免丢失消息。

此处提供的远程,可以通过 ROS2 包管理包含在内。

七、未解决的问题和未来工作

  • 很快,重播者应该可以作为可组合节点使用。我希望这将进一步提高重播速度。它应该与上述实现顺利配合。
  • 使用这些服务时,ros bag 重播器会向终端发送垃圾邮件,其中包含每个服务的消息,我没有找到一种方法来阻止日志记录部分将其重定向到 /dev/null。但是,这超过了重播者的所有输出
  • 最好找到更简单的方法来监视节点的工作负载,甚至可能是外部的工作负载。例如,如果我们能以某种方式访问待处理的回调,这已经有所帮助,但我没有找到做到这一点的方法。

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

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

相关文章

cloudCompare教程:一、可视化、点、线编辑

依据高度等准则(都在Scalar Fields中)渲染点云&#xff08;首先要打开Tools -> Projection -> Export coordinate to SF&#xff09; 在上述准则之外的&#xff0c;设置为不显示&#xff1a; 软件的显示设置&#xff08;首先打开右边的彩色柱状图&#xff0c;点击左边属性…

ECharts多个数据视图进行自适应大小的解决方案

项目场景&#xff1a; 在制作数据视图时经常会遇到多个数据视图的情况&#xff0c;在多个数据视图的情况下做自适应是比较麻烦的&#xff0c;这里就详细的分析一下该如何去制作&#xff0c;分享一下我的解决办法及思路。 定义 DOM 容器 这里需要注意一个地方&#xff0c;在定…

idea Springboot 校园助学贷款系统VS开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 校园助学贷款系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统 具有完整的源代码和数据库&…

2023.09.30使用golang1.18编译Hel10-Web/Databasetools的windows版

#Go 1.21新增的 log/slog 完美解决了以上问题&#xff0c;并且带来了很多其他很实用的特性。 本次编译不使用log/slog 包 su - echo $GOPATH ;echo $GOROOT; cd /tmp; busybox wget --no-check-certificate https://go.dev/dl/go1.18.linux-amd64.tar.gz;\ which tar&&am…

C++核心编程--继承篇

4.6、继承 继承是面向对象三大特征之一 有些类与类之间存在特殊的关系&#xff0c;例如下图中&#xff1a; ​ 我们发现&#xff0c;定义这些类的定义时&#xff0c;都拥有上一级的一些共性&#xff0c;还有一些自己的特性。那么我们遇到重复的东西时&#xff0c;就可以考虑使…

用go实现http服务端和请求端

一、概述 本文旨在学习记录下如何用go实现建立一个http服务器&#xff0c;同时构造一个专用格式的http客户端。 二、代码实现 2.1 构造http服务端 1、http服务处理流程 基于HTTP构建的服务标准模型包括两个端&#xff0c;客户端(Client)和服务端(Server)。HTTP 请求从客户端…

泰国数字加密平台Bitkub创始人到访上海和数集团

2023年9月21日&#xff0c;泰国数字加密货币交易平台Bitkub创始人兼首席执行官&#xff08;CEO&#xff09;Jirayut Srupsrisopa (Topp)先生到访上海和数集团总部。董事长唐毅先生热情会见了来宾&#xff0c;双方进行了友好深入的交流。 和数集团国际部经理晋松&#xff1b;苏州…

BUUCTF reverse wp 76 - 80

[CISCN2018]2ex 四处游走寻找关键代码 int __fastcall sub_400430(int a1, unsigned int a2, int a3) {unsigned int v3; // $v0int v4; // $v0int v5; // $v0int v6; // $v0unsigned int i; // [sp8h] [8h]unsigned int v9; // [sp8h] [8h]int v10; // [spCh] [Ch]v10 0;for…

在 Python 中列出虚拟环境

文章目录 在Python中列出虚拟环境使用lsvirtualenv命令使用Conda命令使用workon命令 总结 虚拟环境是一个独立的环境&#xff0c;我们可以在其中安装库、包、脚本和Python解释器。如果你的项目需要不同版本的库或Python解释器&#xff0c;你可以为每个项目创建单独的虚拟环境。…

2.索引操作

1. 创建索引 创建索引就等于创建数据库&#xff0c;ES使用put操作创建索引&#xff0c;我们创建一个students的索引&#xff0c;只需要发生put请求&#xff1a;http://127.0.0.1:9200/students 2. 查看索引 2.1 查看所有索引&#xff1a; 使用http://127.0.0.1:9200/_cat/ind…

Firefox 开发团队对 Vue 3 进行优化效果显著

Mozilla 官方博客近日发表文章《Faster Vue.js Execution in Firefox》&#xff0c;介绍了 Firefox 开发团队对 Vue 3 进行的优化。 文章写道&#xff0c;在使用 Speedometer 3 对 Firefox 进行基准测试时&#xff0c;他们发现 Vue.js test 的测试结果从 Vue 2 升级到 Vue 3 后…

ElasticSearch 同步数据变少了

一、前言 这几天对接ES遇到几个坑&#xff0c;我们将一张库存表同步到ES发现Docs Count和我们表中的数据对不上&#xff0c;需要加上Docs deleted才对得上&#xff0c;也不知道批量写入数据为什么有些数据就会成 Docs deleted。 二、ID和版本号 ES中每一个Document都有一个_…

大规模语言模型--中文 LLaMA和Alpaca

中文LLaMA 尽管 LLaMA 和 Alpaca 在 NLP 领域取得了重大进展&#xff0c; 它们在处理中文语言任务时&#xff0c; 仍存在一些局限性。这 些原始模型在字典中仅包含数百个中文 tokens (可以理解为单词)&#xff0c;导致编码和解码中文文本的效率受到了很大 影响。 之前已经对…

数据结构--队列

一、队列是什么 队列是一种特殊的线性表&#xff0c;特殊之处在于它只允许在表的前端&#xff08;front&#xff09;进行删除操作&#xff0c;而在表的后端&#xff08;rear&#xff09;进行插入操作&#xff0c;队列是一种操作受限制的线性表。进行插入操作的端称为队尾&…

GEO生信数据挖掘(一)数据集下载和初步观察

检索到目标数据集后&#xff0c;开始数据挖掘&#xff0c;本文以阿尔兹海默症数据集GSE1297为例 目录 GEOquery 简介 安装并加载GEOquery包 getGEO函数获取数据&#xff08;联网下载&#xff09; 更换下载数据源 对数据集进行初步观察处理 GEOquery 简介 GEOquery是一个…

第1篇 目标检测概述 —(4)目标检测评价指标

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。目标检测评价指标是用来衡量目标检测算法性能的指标&#xff0c;可以分为两类&#xff0c;包括框级别评价指标和像素级别评价指标。本节课就给大家重点介绍下目标检测中的相关评价指标及其含义&#xff0c;希望大家学习之后…

【中秋国庆不断更】HarmonyOS对通知类消息的管理与发布通知(上)

一、通知概述 通知简介 应用可以通过通知接口发送通知消息&#xff0c;终端用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用。 通知常见的使用场景&#xff1a; 显示接收到的短消息、即时消息等。显示应用的推送消息&#xff0c;如广告、版本更新等。显示…

【中秋国庆不断更】OpenHarmony多态样式stateStyles使用场景

Styles和Extend仅仅应用于静态页面的样式复用&#xff0c;stateStyles可以依据组件的内部状态的不同&#xff0c;快速设置不同样式。这就是我们本章要介绍的内容stateStyles&#xff08;又称为&#xff1a;多态样式&#xff09;。 概述 stateStyles是属性方法&#xff0c;可以根…

机器人中的数值优化(十九)—— SOCP锥规划应用:时间最优路径参数化(TOPP)

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考&#xff0c;主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等&#xff0c;本系列文章篇数较多&#xff0c;不定期更新&#xff0c;上半部分介绍无约束优化&#xff0c;…

Vue3父子组件数据传递

getCurrentInstance方法 Vue2中&#xff0c;可以通过this来获取当前组件实例&#xff1b; Vue3中&#xff0c;在setup中无法通过this获取组件实例&#xff0c;console.log(this)打印出来的值是undefined。 在Vue3中&#xff0c;getCurrentInstance()可以用来获取当前组件实例…