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。但是,这超过了重播者的所有输出
- 最好找到更简单的方法来监视节点的工作负载,甚至可能是外部的工作负载。例如,如果我们能以某种方式访问待处理的回调,这已经有所帮助,但我没有找到做到这一点的方法。
相关文章:

ROS2 中的轻量级、自动化、受控回放
一、说明 这篇文章描述了一种在 ROS2 中实现受控重播器的轻量级方法。用以测试中将现象重新播放一遍,以实现调参或故障定位的目的。所有源代码都可以在这里找到。该帖子也可在此处获得。 二、问题:不同步重播 任何曾经认真开发过 ROS2 的人都会知道这个问…...

Egg使用jwt拦截jtoken验证
安装 npm install egg-jwt注册插件 在config文件夹子下 plugin,js下 use strict;module.exports {//mysqlmysql: {enable: true,package: egg-mysql},//jwtjwt: {enable: true,package: egg-jwt} };使用中间件 在app文件下创建 middleware 文件夹 在middleware 文件下创建…...

装饰器模式详解和实现(设计模式 二)
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许你动态地将对象添加到现有对象中,以提供额外的功能,同时又不影响其他对象。 实现示例 1.定义一个接口或抽象类,表示被装饰对象的公共接口 //抽…...

面试问到MySQL模块划分与架构体系怎么办
面试问到Mysql模块划分与架构体系怎么办 文章目录 1. 应用层连接管理器(Connection Manager)安全性和权限模块(Security and Privilege Module) 2. MySQL服务器层2.1. 服务支持和工具集2.2. SQL Interface2.3. 解析器举个解析器 …...
并查集及其优化
1.并查集 #define SIZE 100 int UFSets[SIZE];void Initial(int S[]) {for (int i 0; i < SIZE; i)S[i]-1; }int Find(int S[], int x) {//查while(S[x] > 0)x S[x];return x; }void Union(int S[], int Root1, int Root2) {//并if(Root1 Root2)return;S[Root2] Roo…...

LeetCode 周赛上分之旅 #48 一道简单的树上动态规划问题
⭐️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度…...

mysql报错:Column Count Doesn‘t Match Value Count at Row 1
mysql中执行insert、update、delete报错:Column Count Doesnt Match Value Count at Row 1 的解决方案 通常情况:字段不匹配 如:student有id, name, age字段 -- 错误写法 INSERT INTO student VALUES(5,horse)-- 正确写法 INSERT INTO stu…...

安卓 kuaishou 设备did和egid 学习分析
did和egid注册 接口 https://gdfp.ksapisrv.com/rest/infra/gdfp/report/kuaishou/android did 是本地生成的16进制 或者 获取的 android_id public static final Random f16237a new Random(System.currentTimeMillis()); public static long m19668a() { return f1623…...

基于Vue+ELement实现增删改查案例与表单验证(附源码)
🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《ELement》。🎯🎯 …...
webpack:使用externals配置来排除打包后的某个依赖插件IgnorePlugin的使用
背景 假设,我们写了一个库并使用 webpack 打包输出 bundle,但是这个库依赖一个第三方包,比如依赖 lodash,这时候我们不想把这个库打包进 bundle 里因为体积会变大,而且我们的主项目里已经安装了这个 lodash࿰…...

2023年中国工业脱水机行业供需分析:随着自动化和智能化技术的快速发展,销量同比增长4.9%[图]
工业脱水机行业是指专门从湿润的固体物料中去除水分的设备制造和相关服务。它广泛应用于食品加工、化工、制药、纺织、环保等行业,用于去除物料中的水分,提高产品质量和降低能耗。 工业脱水机行业分类 资料来源:共研产业咨询(共研…...
[论文笔记]MacBERT
引言 今天带来MacBERT的阅读笔记。论文题目是 重新审视中文自然语言处理的预训练模型。 本篇主要是探讨中文预训练语言模型在非英文语言中的有效性,然后提出了一种简单而有效的模型,称为MacBERT,它在多个方面改进了RoBERTa,特别是采用纠错型掩码语言模型(MLM as correcti…...
AI发展目前最大挑战是什么?
影响AI成本的因素包括多个方面: 首先,AI技术的复杂性是其成本高昂的一个重要原因。AI技术需要进行大量数据处理、模型训练和优化,这需要耗费大量的计算资源和时间。同时,AI技术需要高水平的专业人才进行设计、开发和维护…...
自然语言处理NLP:LTP、SnowNLP、HanLP 常用NLP工具和库对比
文章目录 常见NLP任务常见NLP工具英文NLP工具中文NLP工具 常见NLP任务 Word Segmentation 分词 – Tokenization Stem extraction 词干提取 - Stemming Lexical reduction 词形还原 – Lemmatization Part of Speech Tagging 词性标注 – Parts of Speech Named entity rec…...

百度交易中台之内容分润结算系统架构浅析
作者 | 交易中台团队 导读 随着公司内容生态的蓬勃发展,内容产出方和流量提供方最关注的“收益结算”的工作,也就成为重中之重。本文基于内容分润结算业务为入口,介绍了实现过程中的重难点,比如千万级和百万级数据量下的技术选型和…...
【索引】常见的索引、B+树结构、什么时候需要使用索引、优化索引方法、索引主要的数据结构、聚簇索引、二级索引、创建合适的索引等重点知识汇总
目录 索引的分类 什么时候需要 / 不需要创建索引? 有什么优化索引的方法 MySQL索引主要使用的两种数据结构是什么 为什么 MySQL 采用 B 树作为索引 聚簇索引和二级索引 根据给定的表,如何创建索引比较好 索引的分类 普通索引:最基本的…...

Egg 封装接口返回信息
中间件封装 代码 const msgArr {"200":成功,"401":token失效 } module.exports (option, app) > {return async function(ctx, next) {try{//成功是返回的信息ctx.emit(code,data,msg)>{console.log(1111,code,data,msg)ctx.body {code,data:dat…...
Android AMS——创建APP进程(五)
接上一篇,在 ActivityTaskSupervisor 中会判断进程是否存在,如果进程不存在,则会创建进程,执行 startProcessAsync() 方法。如果进程存在,则执行 realStartActivityLocked() 方法。在APP 的启动时,进程是不存在的。所以我们先来分析一下进程不存在的情况。 一、创建进程…...

凉鞋的 Unity 笔记 102. 场景层次 与 GameObject 的增删改查
102. 场景层次 与 GameObject 的增删改查 在上一篇,我们完成了 Unity 引擎的 Hello world 输出,并且完成了第一个基本循环: 通过这次基本循环的完成,我们获得了一点点的 Unity 使用经验,这非常重要。 有实践经验后再…...

信息安全:网络安全审计技术原理与应用.
信息安全:网络安全审计技术原理与应用. 网络安全审计是指对网络信息系统的安全相关活动信息进行获取、记录、存储、分析和利用的工作。网络安全审计的作用在于建立“事后“安全保障措施,保存网络安全事件及行为信息,为网络安全事件分析提供线…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...