Virtual time,多进程共享虚拟时间原型验证

周末抽空想了想数据回放的时间戳问题,想到了一个比较有意思的方案,就是使用虚拟时间。所以就尝试采用多进程共享虚拟时间的方式来劫持系统时间戳,尝试满足数据回放过程中的功能代码对系统时间戳需求。 一般而言,像ROS或者DDS的消息数据都是带有时间戳的,比如录制时间戳,消息内部header中保存的数据源时间戳或者数据对应的有效时刻的时间戳等等 对于实际生产环境中的功能逻辑代码,可能会依赖于系统时间戳来进行一些逻辑判断,比如超时判断,定时器;又或者对不同来源(不同topic、不同帧率)的时间戳的消息进行时间戳对齐或者插值等等,这些都是对时间戳的依赖。而如果软件没有对获取时间戳的接口进行封装,那么在采用类似于Pub/Sub的方式对数据回放的时候,就会出现问题,因为数据回放的时间戳是不可控的,可能会导致功能逻辑的错误。 对于单进程的数据回放程序,可以使用消息录制时的时间戳来作为虚拟的仿真系统时间戳,这样的话,原有的代码逻辑就可以直接使用这个时间戳来进行仿真 对于多进程节点,数据通过类似于DDS Pub/Sub的方式进行传输,那么就需要对时间戳进行额外的处理;对系统时间戳进行劫持,然后通过共享内存的方式来共享虚拟时间戳是一个看上去能走通的方案(当然,未必是最优的) 实现的思路非常简单,那就是可以根据消息对应的录制时间戳和消息内部的时间戳(其实一般前者应该就够了),来更新虚拟的时间戳,并将这个虚拟时间戳通过共享内存的方式共享给其他进程。这样的话,其他进程就可以通过读取共享内存的方式来获取虚拟时间戳。 该虚拟时间戳,可以通过劫持libc中的gettimeofday、clock_gettime等函数来实现,这样的话,就可以在不修改原有代码的情况下,来实现对系统时间戳的劫持;这可以通过将动态库指定到LD_PRELOAD的方式来实现。 具体原型代码实现可见 Virtual timestamp。该实现仅为虚拟时间戳多进程更新和共享的原型验证,实际应用中还需要考虑更多的问题,比如定时器回调的处理,进程异常退出后共享内存的释放等等。 其实ROS在设计中是采用 /clock topic 来发布时间戳的(ROS 2 Design: Clock and Time),这个主要受到网络通信延时的影响。共享内存的方式有可能会更快,不过没有考虑多机通信的情况。一般回放数据的时候,都是在一个机器上进行的,所以这个问题应该不大;要是真的有多机通信的需求,也估计还得靠消息传递的方式来实现。 时间戳在回放过程中是个比较重要的问题,这影响到功能逻辑的正确性。例如Timestamps and rosbags: discussing an alternative to clock and use_sim_time这里就谈到了录制消息时间戳乱序的问题,里面提到需要对文件进行后处理,来保证时间戳的顺序性。所以关于回放过程中的时间戳问题,还是要根据具体的应用场景来进行设计。……

Continue reading

Cling Jupyter Notebook

Cling Jupyter Notebook 最近开始学习C++20相关的特性,需要经常性地写一些代码进行验证工作,试用了一下cling,感觉不错,记录一下。 之前也留意到xeus-cling项目,尝试了用conda拉取失败,遂放弃,自己动手编译吧。 编译 按照Readme来编译还是有点小坑的,主要有以下: cmake 指令问题,大小写有点坑,这个issue算是解决了。 OOM问题:需要编译cling和root-project的llvm工程,如果采用多线程编译的话,笔记本32G的内存还是会有内存不够用的情况。将线程数量调小就可以避免,问题不大。编译完成后,cling-build目录竟然有95GB。 Jupyter notebook 默认的安装目录为/usr/local,不过Jupyter相关的文件并没有安装到这个目录下,需要自己到工程目录下去找 cling/tools/Jupyter。 自行安装配置好Python3的venv后,按照ReadMe的说明配置一下就可以。 如果要尝试一下C++20的特性,可以参考#520为Jupyter notebook增加 C++20 的入口。不过需要留意一下编译时gcc的版本,笔者用的Debian 12自带的默认gcc版本为12.2,支持大部分C++20的语言特性。gcc对C++语言标准的支持可参考C++20 Support in GCC。 效果 #include <ranges> #include <numeric> #include <vector> #include <iostream> namespace views = std::views; namespace ranges = std::ranges; std::vector ints{0, 1, 2, 3, 4}; auto rv = ints | views::reverse ; for(auto i : rv){ std::cout << i << " "; } 参考 Using cling to interpret C++ code ROOT ……

Continue reading

Know how to access name in templated base classes

模板基类成员如何在继承类中访问 如题,最近在C++标准库的学习过程中,产生了这样的疑问。标准库中解决这个问题一共有3种方式: 用using来指明该成员为依赖名称(dependent name) 直接把带模板参数的基类作用于成员名称前 采用this指针来指明该名称依赖于实例化后的类 这3种方式实际上都是在告知编译器,该成员是一个依赖名称,需要在实例化后才能找到。 但是为什么呢?找寻了很久才发现了满意的答案。 Short answer: in order to make x a dependent name, so that lookup is deferred until the template parameter is known.……

Continue reading

Kalman Filter小结

卡尔曼滤波小结 最近复习了一下卡尔曼滤波,并在Coursera上完成了课程与练习1,做些简单的笔记备忘。 1. 线性卡尔曼滤波 简单来说,对于一个线性系统的状态,可以通过模型计算获取到一个基于模型的预测状态,再通过实际测量的值来纠正系统的状态。 通过模型来更新状态 系统的控制方程为: $$ \check{x}_k = F_{k-1} \hat{x}{k-1} + G{k-1}u_{k-1} $$ 更新状态协方差矩阵: $$ \check{P}_{k}= F_{k-1} \hat{P}{k-1} F{k-1}^{T} + L_{k-1} Q_{k-1} L_{k-1}^{T} $$……

Continue reading

台式机折腾记

配置 趁着618攒了一台主机,犹豫了很久还是决定上车AMD,配置如下: CPU: AMD Ryzen-9 5900x 主板:TUF Gaming X570-Plus WIFI 硬盘: 1TB SSD KC2500 4TB HDD 西部数据蓝盘 Fury 32GB DDR4 3600MHz 美商海盗船AIR540中塔机箱 美商海盗船HX1200,1200W电源 GTX 750Ti显卡(等矿难) 装机的过程略去不表。记录一些配置工作:……

Continue reading

Richardson-Lucy Deconvolution

RL反卷积都干了些啥 RL反卷积是通过迭代的方法来优化损失函数,利用噪声性质和成像系统的点分布函数(Point Spread Function)对图像进行去噪的一种方法。 损失函数是啥样的呢? $$ J(O) = \Sigma(O**PSF - I \cdot ln(O ** PSF)) $$ 且有: $J$,损失函数,为最小化的目标 $O(x,y)$,不受椒盐噪声和点分布函数模糊效应影响的理想原始图像 $PSF(x,y)$,Point Spread Function,点分布函数 $I(x,y)$,实际拍摄到的图像 $**$,二维卷积 $\cdot$,按元素相乘 既然要优化$J(O)$,那么就对O求导:……

Continue reading

树莓派实时内核编译与测试

1. 简介 本文档主要根据LeMaRiva的博客内容整理并基于最新的rt分支代码复现,简述以下2个方面: 如何为树莓派编译实时内核 测试实时内核的进程调度延时性能 实验所需硬件: 树莓派3B 8G TF卡 2. 编译 1.获取代码和工具: # From LeMaRiva mkdir rpi-rt cd rpi-rt mkdir rt-kernel # 用于存放编译产生的文件 cd rt-kernel mkdir boot cd .……

Continue reading

从伯德图说起

在当初学《自动控制原理》的时候,并没有去理解公式背后的意义,囫囵吞枣式地做题、计算、画图。现在想来,传递函数的计算、根轨迹的绘制甚至是伯德图的快速绘制方法都记不得了,但是在实践和仿真中,对于概念的理解更深入了些,所以写下。本文从伯德图说起,讲了以下3个方面: 伯德图表示什么 开环伯德图表示什么 伯德积分定理意味着什么 伯德图表示什么 伯德图是从频域的概念来描述系统的性质、表现的。如果我们考虑最简单的系统——比例环节: $$G_{p} = K_{p}$$ 当 $K_{p} = 1$ 时,其传递函数如下图所示: 那么这张图代表什么呢?代表着任意频率的正弦信号通过比例环节之后输出的信号的幅值依然不变——增益为0dB;同时输出信号和输入信号是同相位的,没有相位延迟。 那么如果我们考虑常见的一阶惯性环节呢: $$ G_{rc} = \frac{1}{T_{s}s + 1} $$ 令$T_{s}=0.1$时,一节惯性环节的伯德图是什么样子的呢? 可见,一阶惯性环节在低频处的增益近似为0dB,而随着频率的增加,增益逐渐下降,而相位也随着频率的增加而滞后,相位滞后的极限为90°。其实一阶惯性环节这样的传递特性对应于电阻电容串联的电路,系统输入为施加在串联阻容上的电压;系统输出为电容两端的电压。如果输入电压为直流电压,那么电容的稳态电压就是直流电压;而如果施加低频正弦电压,那么输出的信号的衰减和相位滞后就会很小;而如果施加高频正弦信号的话,那么输出信号的幅度相对于输入信号就会产生衰减,相位滞后也会随之增大。……

Continue reading

Windows的MATLAB中用C语言写SFunction的一些坑

1.测试环境 操作系统:Windows 10, 64bit 编译器:MinGW64 32位系统请下载对应的32位版本 MATLAB2017a 2017a之后会略有不同 2. 配置环境与流程 下载编译器MinGW64,对于64位系统而言,需要下载个安装器,可以安装相应版本的gcc编译器,我选择的是gcc-4.9.4,在测试环境中可以正常运行 安装器是mingw-w64-install,安装时注意选择64位,同时安装完了还有一个坑:空格。 下载器默认的安装路径"C:Files-w64_64-4.9.4-win32-seh-rt_v5-rev0"是包含有空格的,MATLAB并不能识别该路径,所以可以把mingw64移动到不含空格的路径下,比如"C:"。 验证一下: setenv('MW_MINGW64_LOC','C:\mingw64') % 先配置环境 mex -setup 输出如下图所示,这样MinGW编译器就配置好了。 3. a + b 编译测试 setenv('MW_MINGW64_LOC','C:\mingw64') myFunctionName = 'SFunctionName' def = legacy_code('initialize'); def.……

Continue reading