【学习总结】openvins中的IMU数据仿真

news2024/9/30 5:26:29

本文介绍 openvins 中IMU仿真时基于控制轨迹和SPline插值,并计算IMU输出,的原理和代码。

参考

Open-vins中关于仿真的描述:https://docs.openvins.com/simulation.html
Open-vins论文:https://pgeneva.com/downloads/papers/Geneva2020ICRA.pdf
Open-vins所采用的SE3插值论文:https://link.springer.com/article/10.1007/s11263-015-0811-3
上述论文提到的BSpline的矩阵表示:https://xiaoxingchen.github.io/2020/03/02/bspline_in_so3/general_matrix_representation_for_bsplines.pdf

open-vins中的仿真部分结构

open-vins的文件目录中,如下文件与仿真有关:

ov_core/
	src/
		sim/
			BsplineSE3.cpp
			BsplineSE3.h
ov_msckf/
	src/
		sim/
			Simulator.cpp
			Simulator.h
		test_sim_meas.cpp
ov_data/
	sim/
		xxx.txt

其中,test_sim_meas.cpp 是仿真程序入口,调用的主函数为 Simualtor 类,openvins中所有的内容需要基于 ov_core 这个核心,具体的插值部分用的是 BsplineSE3 这个类。而载入的轨迹数据格式,可以参考 ov_data 路径的文件。

test_sim_meas.cpp
里面核心的函数是 get_next_imu(time_imu, wm, am),其根据类内轨迹数据,计算再某一时刻的imu输出。

get_next_imu
位于 Simulator 类内,主要内容有两个:利用 Bspline 插值得到加速度和角速度, spline->get_acceleration;再添加随机游走和测量噪声。

get_acceleration
位于 BsplineSE3 类,主要内容包括:

  1. 获取轨迹的控制点:find_bounding_control_points()
  2. 计算 De Boor-Cox 矩阵系数
  3. 轨迹插值,获得当前时刻的pose
  4. 将pose转为加速度和角速度(世界系)
  5. 将世界系的加速度和角速度,转到 IMU 系

针对1,只是把轨迹中当前时刻点的前后各2个pose拿出来,即pose0,1,2,3。当前需要插值的时刻是位于1和2之间。

原理解释

De Boor-Cox矩阵系数与轨迹插值

首先,openvins论文中给出的插值公式如下:
在这里插入图片描述这个公式非常简略,看不出来在干什么。简单来说,就是为了计算 u(ts) 时刻得位姿 T,这个位姿是从S系转到G(世界)系的,那么此时需要用 (i-1)时刻的和 A 0 , A 1 , A 2 A_0, A_1,A_2 A0,A1,A2 这4个矩阵计算。式(29)和(30)给出了 A A A的表达式。

想要了解为什么这么算,就需要阅读参考文献[38]:
A Spline-Based Trajectory Representation for Sensor Fusion and Rolling Shutter Cameras

基于SE3的Bspline插值
这篇文章提出的动机是,多传感器融合时,不可能多个传感器完全在同一时刻获取数据,因此需要Bspline插值,因此提出了在SE3插值。

具体地,对于插值方法,有两种表示,分别是(1)和(2),里面的 B B B B ˜ \~{B} B˜是两种不同表示的基,但本质上一样。这里采用的是第二种表示。
在这里插入图片描述
这种表示对于 SE3 的公式为:
在这里插入图片描述这里的符号表示和openvins的不同,这里s表示插值时刻,w表示世界系。 Ω i \Omega_i Ωi 就是上面的 l o g ( T w , i − 1 − 1 , T w , i ) log(T_{w,i-1}^{-1}, T_{w,i}) log(Tw,i11,Tw,i),和上一位姿间的 s e 3 se3 se3

此时上述(3)式的变量只剩 B ˜ 0 , k ( t ) \~B_{0,k}(t) B˜0,k(t),这个的计算方式由 Qin2000(General Matrix Representations for B-Splines) 这篇论文给出。这篇论文太复杂了看不懂,简单概括就是将BSpline用矩阵进行了表示。这里略过。
在这里插入图片描述
由于目标是为IMU提供数据,因此希望加速度是连续的,因此轨迹曲线采用C2连续(即二阶导连续),C2连续只需要4个控制点,即前面2个后面2个,此时的矩阵是 4x4 的。上式的 u u u即插值相对于上一控制点的增量。同时,这里给出了 B ˜ \~B B˜的一阶导和二阶导。

接下来,论文给出了轨迹插值结果,以及插值的一阶导(速度)和二阶导(加速度)表达式。接下来的 A A A就和openvins的一致了。
在这里插入图片描述

由pose计算IMU系得加速度与角速度

上面计算完,只是得到了轨迹相对于轨迹所在坐标系(即世界系)的轨迹、速度和加速度,接下来要求相对于IMU系。这个模型就比较简单:
在这里插入图片描述
加速度,加上重力后,转到IMU系;
角速度,需要经过旋转矩阵求导,再转到IMU系。

代码与原理的对应

直接复制出来 openvins 中 BsplineSE3 中获取加速度和角速度的代码:

//~ 输入:待插值的时间戳;
/*~ 输出:IMU的加速度、角速度,以及一些姿态量;

~*/
bool BsplineSE3::get_acceleration(double timestamp, Eigen::Matrix3d &R_GtoI, Eigen::Vector3d &p_IinG, 
	Eigen::Vector3d &w_IinI, Eigen::Vector3d &v_IinG, Eigen::Vector3d &alpha_IinI, Eigen::Vector3d &a_IinG) {

  // Get the bounding poses for the desired timestamp
  double t0, t1, t2, t3;
  Eigen::Matrix4d pose0, pose1, pose2, pose3;
  bool success = find_bounding_control_points(timestamp, control_points, t0, pose0, t1, pose1, t2, pose2, t3, pose3);

  // Return failure if we can't get bounding poses
  if (!success) {
    alpha_IinI.setZero();
    a_IinG.setZero();
    return false;
  }
  //~ 这里就是计算上述B矩阵,B的一阶导,二阶导矩阵;
  // Our De Boor-Cox matrix scalars
  double DT = (t2 - t1);
  double u = (timestamp - t1) / DT;
  double b0 = 1.0 / 6.0 * (5 + 3 * u - 3 * u * u + u * u * u);
  double b1 = 1.0 / 6.0 * (1 + 3 * u + 3 * u * u - 2 * u * u * u);
  double b2 = 1.0 / 6.0 * (u * u * u);
  double b0dot = 1.0 / (6.0 * DT) * (3 - 6 * u + 3 * u * u);
  double b1dot = 1.0 / (6.0 * DT) * (3 + 6 * u - 6 * u * u);
  double b2dot = 1.0 / (6.0 * DT) * (3 * u * u);
  double b0dotdot = 1.0 / (6.0 * DT * DT) * (-6 + 6 * u);
  double b1dotdot = 1.0 / (6.0 * DT * DT) * (6 - 12 * u);
  double b2dotdot = 1.0 / (6.0 * DT * DT) * (6 * u);

  // Cache some values we use alot
  Eigen::Matrix<double, 6, 1> omega_10 = log_se3(Inv_se3(pose0) * pose1);
  Eigen::Matrix<double, 6, 1> omega_21 = log_se3(Inv_se3(pose1) * pose2);
  Eigen::Matrix<double, 6, 1> omega_32 = log_se3(Inv_se3(pose2) * pose3);
  Eigen::Matrix4d omega_10_hat = hat_se3(omega_10);
  Eigen::Matrix4d omega_21_hat = hat_se3(omega_21);
  Eigen::Matrix4d omega_32_hat = hat_se3(omega_32);

	// 这里计算了A0~A2,以及一阶导、二阶导
  // Calculate interpolated poses
  Eigen::Matrix4d A0 = exp_se3(b0 * omega_10);
  Eigen::Matrix4d A1 = exp_se3(b1 * omega_21);
  Eigen::Matrix4d A2 = exp_se3(b2 * omega_32);
  Eigen::Matrix4d A0dot = b0dot * omega_10_hat * A0;
  Eigen::Matrix4d A1dot = b1dot * omega_21_hat * A1;
  Eigen::Matrix4d A2dot = b2dot * omega_32_hat * A2;
  Eigen::Matrix4d A0dotdot = b0dot * omega_10_hat * A0dot + b0dotdot * omega_10_hat * A0;
  Eigen::Matrix4d A1dotdot = b1dot * omega_21_hat * A1dot + b1dotdot * omega_21_hat * A1;
  Eigen::Matrix4d A2dotdot = b2dot * omega_32_hat * A2dot + b2dotdot * omega_32_hat * A2;

  // Get the interpolated pose
  Eigen::Matrix4d pose_interp = pose0 * A0 * A1 * A2;
  R_GtoI = pose_interp.block(0, 0, 3, 3).transpose();
  p_IinG = pose_interp.block(0, 3, 3, 1);

  // Get the interpolated velocities
  // NOTE: Rdot = R*skew(omega) => R^T*Rdot = skew(omega) 
  //~ 式(5),计算角速度插值,角速度转回IMU系
  Eigen::Matrix4d vel_interp = pose0 * (A0dot * A1 * A2 + A0 * A1dot * A2 + A0 * A1 * A2dot);
  w_IinI = vee(pose_interp.block(0, 0, 3, 3).transpose() * vel_interp.block(0, 0, 3, 3));
  v_IinG = vel_interp.block(0, 3, 3, 1);

  // Finally get the interpolated velocities
  // NOTE: Rdot = R*skew(omega)
  // NOTE: Rdotdot = Rdot*skew(omega) + R*skew(alpha) => R^T*(Rdotdot-Rdot*skew(omega))=skew(alpha)
  //~ 式(6),计算速度插值,加速度转回IMU系
  Eigen::Matrix4d acc_interp = pose0 * (A0dotdot * A1 * A2 + A0 * A1dotdot * A2 + A0 * A1 * A2dotdot + 2 * A0dot * A1dot * A2 + 2 * A0 * A1dot * A2dot + 2 * A0dot * A1 * A2dot);   
  Eigen::Matrix3d omegaskew = pose_interp.block(0, 0, 3, 3).transpose() * vel_interp.block(0, 0, 3, 3);
  alpha_IinI = vee(pose_interp.block(0, 0, 3, 3).transpose() * (acc_interp.block(0, 0, 3, 3) - vel_interp.block(0, 0, 3, 3) * omegaskew));		
  a_IinG = acc_interp.block(0, 3, 3, 1);
  return true;
}

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

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

相关文章

蜂鸟空间数据引擎助力设施管理解决方案

随着产业价值分解和专业化发展&#xff0c;资产和物业管理领域出现了精深精细化的趋势&#xff0c;并逐渐从劳动密集型向知识密集型进行转变&#xff0c;在此基础上&#xff0c;资产和物业管理产生了一个新型的细分领域——设施管理&#xff08;Facility Management&#xff0c…

typescript中array.filter的用法和ts中is的作用

interface A {a:number; } interface B {b:number; } type C A|B; const arr:C[{a:1},{b&#xff1a;2},{b:1}];当我要帅选出所有A类型数据时,用filter判断是否有a属性; const filterArrarr.filter(i> i.hasOwnProperty(a));此时你会发现 ts的推导类型并没有改变&#xff…

阿趣课堂丨一作解读,定量代谢组学临床应用

代谢组学是继基因组学和蛋白质组学之后新发展起来的一门学科&#xff0c;它通过对人体内小分子代谢物进行精准定性定量&#xff0c;分析代谢物与人体生理病理变化的关系&#xff0c;研究疾病发生发展、寻找疾病生物标记物、预测疾病预后等。 代谢组学在临床诊断上将有广阔的发…

Android系统的HAL层分析 (1)-- HAL的架构分析

目录 说明1. Android系统内为何会要有HAL &#xff1f;2. HAL_legacy和HAL对比3. HAL module的架构分析3.1 hw_module_t3.2 hw_module_methods_t3.3 hw_device_t 4. 分析hardware.c5. 分析HAL的加载过程6. 分析硬件访问服务7. 官方实例mokoid分析 说明 在Android系统中有一个很…

HDFS集群部署成功但网页无法打开如何解决(显示配置通过浏览器访问hdfs的端口)

在学习黑马2023大数据教程过程中&#xff0c;首先依照视频完成了如下配置&#xff1a;【必须】 【黑马2023大数据实战教程】大数据集群环境准备过程记录&#xff08;3台虚拟机&#xff09; 黑马2023大数据实战教程】VMWare虚拟机部署HDFS集群详细过程 最后node1的hadoop用户下…

共建智能汽车数据管理方案 | 4.15 IoTDB X EMQ 主题 Meetup 回顾

4 月 15 日&#xff0c;IoTDB X EMQ 智能汽车主题 Meetup 在上海成功举办。工业物联网时序数据库研发商天谋科技、物联网数据基础设施软件供应商 EMQ 的两位技术大牛&#xff0c;深度分享了企业如何应对智能汽车制造、智慧汽车联网平台普遍面临的海量车况、车产数据“采、存、取…

2023年Chat GPT 应用前景分析

从2022年12月初刚上线至今&#xff0c;不到半年时间ChatGPT月活就超过了1亿用户&#xff01;可谓火的一塌糊涂&#xff0c;比尔盖茨都称&#xff1a;ChatGPT的历史意义重大&#xff0c;不亚于PC或互联网诞生。以至于ChatGPT官网长期都处于满负荷运转的状态&#xff01; 由于Ch…

S7-200 SMART 和 S7-1200PLC进行PROFINET IO通信

从 S7-200 SMART V2.5 版本开始,S7-200 SMART 开始支持做 PROFINET IO 通信的智能设备。因此,两个 S7-200 SMART 之间可以进行 PROFINET IO 通信,一个CPU 作PROFINET IO 控制器,一个 CPU 作 PROFINET 通信的设备。组态的时候有两种方法,一种是通过硬件目录组态另外一种是通…

008+limou+CSS|CSS简介

1、CSS简介 &#xff08;1&#xff09;CSS是什么 指的是“Cascading Style Sheet&#xff08;层叠样式表&#xff09;”&#xff0c;是用来控制网页外观的一门技术 &#xff08;2&#xff09;CSS和CSS3 CSS历经CSS1.0、CSS2.0、CSS2.1、CSS3.0这几个版本&#xff0c;这几个…

java企业级信息系统开发学习笔记07 基于java配置方式使用Spring MVC

文章目录 一、学习目标二、基于java配置方式使用Spring MVC&#xff08;一&#xff09;创建Maven项目&#xff08;二&#xff09;添加相关依赖&#xff08;三&#xff09;创建日志属性文件&#xff08;四&#xff09;创建首页文件&#xff08;五&#xff09;创建Spring MVC配置…

学会Spring Batch 批处理框架,效率翻倍,上班轻松又快乐

一、SpringBatch 介绍 Spring Batch 是一个轻量级、全面的批处理框架&#xff0c;旨在支持开发对企业系统的日常操作至关重要的健壮的批处理应用程序。Spring Batch 建立在人们期望的 Spring Framework 特性&#xff08;生产力、基于 POJO 的开发方法和一般易用性&#xff09;…

uniapp-TypeError: Cannot convert undefined or null to object

问题详情 INFO Starting development server...ERROR TypeError: Cannot convert undefined or null to object TypeError: Cannot convert undefined or null to objectat Function.assign (<anonymous>)at uniapp-cli\node_modules\dcloudio\vue-cli-plugin-uni\lib…

Java EE企业级应用开发(SSM)第7章

第7章Spring MVC拦截器 一.预习笔记 1.拦截器是一个运行在服务器端的程序&#xff0c;主要用于拦截用户的请求并进行相应的处理&#xff0c;即实现对控制器请求的预处理或后处理 2.拦截器的实现 2-1&#xff1a;实现Spring的HandlerInterceptor接口 2-2&#xff1a;实现Spri…

基于html+css的图片展示17

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

Activiti的基本使用

目录 1、Activiti使用 1.1、数据库支持 1.2、Activiti环境 1.2.1、引入依赖 1.2.2、添加配置 1.2.3、启动项目 1.2.4、数据库表介绍 1.3、Activiti常用Service服务接口 1.4、流程设计工具 1.4.1、下载activiti-explorer 1.4.2、解压获取部署包 1.4.3、部署activiti…

mysql的启动关闭原理和实战,及常见的错误排查

前言 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的 RDBMS (Relational Database Management System&#xff0c;关系…

【数据结构】顺序表和链表(上)(附leetcode练习题)

☃️个人主页&#xff1a;fighting小泽 &#x1f338;作者简介&#xff1a;目前正在学习C语言和数据结构 &#x1f33c;博客专栏&#xff1a;数据结构 &#x1f3f5;️欢迎关注&#xff1a;评论&#x1f44a;&#x1f3fb;点赞&#x1f44d;&#x1f3fb;留言&#x1f4aa;&…

春秋云境:CVE-2022-30887(文件上传漏洞)

目录 一.题目 二.蚁剑方式 三.POC方式 一.题目 该CMS中php_action/editProductImage.php存在任意文件上传漏洞&#xff0c;进而导致任意代码执行。 进入页面&#xff1a;登录页面 随意输入用户名和密码&#xff1a;admingmail.com admin 用于burp抓包&#xff1a; burp抓包…

基于PCL抓取Velodyne激光雷达数据包可视化

Velodyne 高清激光雷达 (HDL) 采集器 Velodyne HDL 是一种基于网络的 3D LiDAR 系统&#xff0c;每秒生成包含超过 700,000 个点的 360 度点云。 PCL 中提供的 HDL Grabber 模仿其他 Grabbers&#xff0c;使其几乎可以即插即用。 然而&#xff0c;由于 HDL 设备是基于网络的&…

线性表总结

线性表 目录&#xff1a; 文章目录 线性表概念一、线性表的定义二、线性表的基本操作三、线性表的实现方式四、线性表的应用总结 概念 线性表是一种基本的数据结构&#xff0c;由一系列具有相同类型的数据元素构成&#xff0c;这些元素之间具有线性的顺序关系&#xff0c;每个…