不一样的静态初始化——OpenVins

2023-05-16

今天讲一下黄国权老师实验室开源的OpenVins工程中的IMU初始化,一般VIO初始化分为两种,一种是静态初始化,一种是动态初始化,而OpenVins则利用加速度的方差差异将运动分为两种状态,一种是静止的,一种是刚开始运动的。个人比较符合应用情况,而且我觉得这个想法挺不错,很有意思。

VIO初始化就要任务一般是估计重力方向,速度,位置,IMU的偏置,尺度。而而在openvins中,只估计重力方向,IMU的偏置。

其实在代码里主要写了三个初始化模式,但是动态初始化好像没写出来,不知道现在有没有出来,大家可以去看看

1) GroundTruth初始化

2 )静止初始化

3 )动态初始化

而我们用到的是静态初始化,该初始化不同于smsckf开源代码中的初始化。

首先,将IMU数据分为两个部分,一个是静止的,一个是跳跃的。所谓“跳跃”是指相机从静止到运动的过程,如下图的w3阶段

 在代码中是通过时间的方式划分w2和w3。那么如何判断w3就是跳跃的窗口?openvins采用加速度的方差进行判断,如果方差大于一个阈值,则认为是跳跃窗口w3,如果方差小于阈值,则认为是静止的。然后通过静止的窗口w2进行初始化。这里个人觉得跳跃窗口的信息不应就这么不用了。

现在展示一下OpenVins初始化的大致流程:

 算法中用到了在估计重力坐标系的时候用到了施密特正交化,原理如下:

 代码中是这一样操作的,静止情况下,我们可以确定加速度在世界坐标系下为(0,0,g),将窗口w2的am2_avg除以其模长,得到平均加速度的方向(单位向量),即为世界系z轴的方向在imu坐标系上的投影:

,通过z轴我们可以利用正交化确定一个坐标系。

 这样我们又可以确定x轴,最后通过x与z叉乘,得到y轴。这样就可以确定初始旋转量了。

静止时刻的陀螺仪理想测量值(角速度)应该为0,因此陀螺仪的bias即窗口w2陀螺仪数据的平均值;静止时的加速度计bias为加速度平均值与实际重力加速度的差。

相关代码如下:

bool InertialInitializer::initialize_with_imu(double &time0, Eigen::Matrix<double,4,1> &q_GtoI0, Eigen::Matrix<double,3,1> &b_w0,
Eigen::Matrix<double,3,1> &v_I0inG, Eigen::Matrix<double,3,1> &b_a0, Eigen::Matrix<double,3,1> &p_I0inG, bool wait_for_jerk) {

// Return if we don't have any measurements
// 如果没有IMU数据,则返回
if(imu_data.empty()) {
return false;
}

// Newest imu timestamp
//最新的IMU时间戳
double newesttime = imu_data.at(imu_data.size()-1).timestamp;

// First lets collect a window of IMU readings from the newest measurement to the oldest
// 这里分为两个窗口,一个是从静态跳到动态,一个是就静态
std::vector<IMUDATA> window_newest, window_secondnew;
for(IMUDATA data : imu_data) {
if(data.timestamp > newesttime-1*_window_length && data.timestamp <= newesttime-0*_window_length) {
window_newest.push_back(data);
}
if(data.timestamp > newesttime-2*_window_length && data.timestamp <= newesttime-1*_window_length) {
window_secondnew.push_back(data);
}
}

// Return if both of these failed
if(window_newest.empty() || window_secondnew.empty()) {
//printf(YELLOW "InertialInitializer::initialize_with_imu(): unable to select window of IMU readings, not enough readings\n" RESET);
return false;
}

// Calculate the sample variance for the newest one
// a_avg平均加速度
Eigen::Matrix<double,3,1> a_avg = Eigen::Matrix<double,3,1>::Zero();
for(IMUDATA data : window_newest) {
a_avg += data.am;
}
a_avg /= (int)window_newest.size();
// a_var方差,通过方差可以判断运动的激励够不够
double a_var = 0;
for(IMUDATA data : window_newest) {
a_var += (data.am-a_avg).dot(data.am-a_avg);
}
a_var = std::sqrt(a_var/((int)window_newest.size()-1));

// If it is below the threshold and we want to wait till we detect a jerk
// 如果运动激励不足,说明是静止的,还没运动,那就不初始化了
if(a_var < _imu_excite_threshold && wait_for_jerk) {
printf(YELLOW "InertialInitializer::initialize_with_imu(): no IMU excitation, below threshold %.4f < %.4f\n" RESET,a_var,_imu_excite_threshold);
return false;
}

// Return if we don't have any measurements
//if(imu_data.size() < 200) {
// return false;
//}

// Sum up our current accelerations and velocities
// 静止窗口中的平均加速度和平均角速度,然后计算方差,判断激励够不够
Eigen::Vector3d linsum = Eigen::Vector3d::Zero();
Eigen::Vector3d angsum = Eigen::Vector3d::Zero();
for(size_t i=0; i<window_secondnew.size(); i++) {
linsum += window_secondnew.at(i).am;
angsum += window_secondnew.at(i).wm;
}

// Calculate the mean of the linear acceleration and angular velocity
Eigen::Vector3d linavg = Eigen::Vector3d::Zero();
Eigen::Vector3d angavg = Eigen::Vector3d::Zero();
linavg = linsum/window_secondnew.size();
angavg = angsum/window_secondnew.size();

// Calculate variance of the
double a_var2 = 0;
for(IMUDATA data : window_secondnew) {
a_var2 += (data.am-linavg).dot(data.am-linavg);
}
a_var2 = std::sqrt(a_var2/((int)window_secondnew.size()-1));

// If it is above the threshold and we are not waiting for a jerk
// Then we are not stationary (i.e. moving) so we should wait till we are
//静止的窗口运动激励要小于阈值才能继续初始化
if((a_var > _imu_excite_threshold || a_var2 > _imu_excite_threshold) && !wait_for_jerk) {
printf(YELLOW "InertialInitializer::initialize_with_imu(): to much IMU excitation, above threshold %.4f,%.4f > %.4f\n" RESET,a_var,a_var2,_imu_excite_threshold);
return false;
}

// Get z axis, which alines with -g (z_in_G=0,0,1)
// 静止时加速度计测量值为g
// 确定z轴方向后,我们利用施密特正交化构建单位坐标系。施密特正交化过程为
// v1 = x1 
// v2 = x2-(x2*v1)/(v1*v1)*v1
// 还剩下一个轴可以利用两个轴的叉乘来确定
Eigen::Vector3d z_axis = linavg/linavg.norm();

// Create an x_axis
// x轴
Eigen::Vector3d e_1(1,0,0);

// Make x_axis perpendicular to z
//根据施密特正交化可得
Eigen::Vector3d x_axis = e_1-z_axis*z_axis.transpose()*e_1;
x_axis= x_axis/x_axis.norm();

// Get z from the cross product of these two
// 通过叉乘确定y轴
Eigen::Matrix<double,3,1> y_axis = skew_x(z_axis)*x_axis;

// From these axes get rotation
//确定初始的旋转
Eigen::Matrix<double,3,3> Ro;
Ro.block(0,0,3,1) = x_axis;
Ro.block(0,1,3,1) = y_axis;
Ro.block(0,2,3,1) = z_axis;

// Create our state variables
Eigen::Matrix<double,4,1> q_GtoI = rot_2_quat(Ro);

// Set our biases equal to our noise (subtract our gravity from accelerometer bias)
//静止的时候,角速度应该就是bias了
Eigen::Matrix<double,3,1> bg = angavg;
//则加速度bias如下,因为静止加速度就是重力和bias了
Eigen::Matrix<double,3,1> ba = linavg - quat_2_Rot(q_GtoI)*_gravity;

// Set our state variables
time0 = window_secondnew.at(window_secondnew.size()-1).timestamp;
q_GtoI0 = q_GtoI;
b_w0 = bg;
v_I0inG = Eigen::Matrix<double,3,1>::Zero();
b_a0 = ba;
p_I0inG = Eigen::Matrix<double,3,1>::Zero();

// Done!!!
return true;

}

个人觉得这个想法在静态初始化中很不错,可以和动态初始化结合起来,更好的评估VIO联合初始化,不然那个动态窗口信息不是浪费了?

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

不一样的静态初始化——OpenVins 的相关文章

  • C++ shared_ptr的reset 用法

    include lt iostream gt include lt memory gt class Tmp public Tmp int a Tmp void print a std cout lt lt 34 value 61 34 lt
  • C++ 模板类的继承

    模板类 xff1a template lt typename T gt 说白了就是向之后的内容传递参数类型 xff0c 把T当作一个数据类型传递 xff0c 而在声明一个变量的时候 xff0c 通过base lt xxxx gt pp xx
  • linuxptp源码研究

    目录 1 检查网卡是否支持相应的时间戳 2 linuxptp的目录架构 3 ptp4l的大致流程分析 4 gptp协议对应的sync follow up delay request delay response消息在代码的位置 5 slav
  • xv6---Lab3: page tables

    目录 参考资料 RISC V页表的简化图如下所示 编辑 多级页表 xv6内核页表 3 6 Process Address Space 3 7 Code Sbrk 3 8 Code Exec Print a page table A kern
  • 内存管理---分页机制

    目录 物理内存管理带来的问题 直接映射 一级页表 二级页表 参考 xff1a xff08 C语言内存七 xff09 分页机制究竟是如何实现的 xff1f Smah 博客园 物理内存管理带来的问题 比如4GB的flash 如果应用程序可直接访
  • xv6---Lab4 traps

    参考 xff1a Lab Traps 关于寄存器s0和堆栈 https pdos csail mit edu 6 828 2020 lec l riscv slides pdf RISC V assembly Q 哪些寄存器包含函数的参数
  • stm32F4 hal库之CAN通信的实现

    本文的目的是为了能够实现功能 xff0c 故写的时候比较简略 参考资料 xff1a https blog csdn net u012308586 article details 81001102 正点原子开发手册 目标 xff1a 通过ca
  • 调试sim800L模块

  • 51单片机 串口中断

    1 什么是中断 广义上的中断是指一个过程 xff0c 举个简单的例子 xff0c 打开了电脑 xff0c 你正在放音乐 xff0c 点击了暂停按钮 xff0c 于是歌停了 这就是一个很明显的中断的例子 CPU正在做自己的事情 xff08 放
  • STM32CubeMX应用 -- 定时器输入脉冲计数

    目录 参考链接 一 实现过程 二 STM32CubeMX配置示例 三 C语言示例程序 参考链接 https blog csdn net m0 37845735 article details 105395643 一 实现过程 当选择外部的同
  • 机器人导航dwa(局部避障)分析

    前面部分引用http blog csdn net lqygame article details 72861439 xff08 1 xff09 初始化 xff1a 在move base节点中 xff0c 通过类加载模块载入了BaseLoca
  • 2019年最新VSLAM比较汇总

    2019年最新VSLAM比较汇总 闭源SOFTSOFT2ESOsGAN VOLG SLAMRotRocc 43 GDVOElbrusROCCMonoROCCcv4xv1 sc 开源 xff1a VINS FusionORB SLAM2Ste
  • CMSIS到底是个什么东西

    目录 一 前言 二 CMSIS标准 三 CMSIS文件 1 Include文件 2 Source文件 四 总结 一 前言 使用过ARM单片机的朋友肯定听说过CMSIS xff0c 可以说CMSIS是开启ARM单片机的金钥匙 xff0c 是不
  • TouchGFX介绍

    目录 一 关于TouchGFX 1 TouchGFX是一个图形框架 2 TouchGFX可以减轻CPU负载 3 TouchGFX充分利用了STM32的硬件图形外设 4 TouchGFX创建最佳性能的用户界面 5 TouchGFX可工作于ST
  • rt-thread应用篇(03)---基于STM32F429实现web服务器功能

    目录 参考示例 前言 一 需使用的组件与软件包及其ENV配置 1 文件系统相关组件与软件包 1 1 DFS 框架 1 2 fal 软件包 1 3 SFUD 组件 2 网络通信相关组件和软件包 2 1 SAL组件 2 2 netdev组件 2
  • rt-thread的at组件在freeRTOS上的移植与应用

    目录 一 AT命令 二 rtthread at组件简介 三 移植到freeRTOS 3 1 数据结构 3 2 API 3 3 at client 流程 3 4 串口数据接收处理 3 5 数据缓存 顺序队列 四 使用示例 4 1 串口配置信息

随机推荐

  • rt-thread驱动篇(04)---STM32F429单片机模拟SPI FLASH驱动添加

    目录 一 添加驱动 1 新增模拟SPI驱动文件 drv soft spi c h 2 新增模拟SPI配置文件 soft spi config h 二 向工程添加文件 1 修改 board Kconfig 2 修改 rt thread com
  • RT-Thread实时操作系统简介

    目录 一 概述 二 架构 三 版本选择 四 内核启动流程 五 自动初始化机制 六 内核对象模型 七 I O设备模型 1 框架 2 设备驱动使用序列图 3 设备类型 八 FinSH控制台 九 ENV工具 1 menuconfig 2 Scon
  • Altium Allegro PADS到底该选哪个EDA设计软件

    废话少说 xff0c 就像之前 学好数理化 xff0c 走遍天下都不怕 一样 xff0c 在如今快速发展的电子时代 xff0c 掌握一门电子设计EDA软件工具 xff0c 在职场上真的走遍天下都不怕 哪哪都有可能跟电沾边 xff0c 跟控制
  • QML学习笔记【07】:QML访问复杂组件的子项

    1 访问复杂组件的子项 gt Row Column Grid Flow布局子项或Repeater子项 访问复杂组件的子项 gt Row Column Grid Flow布局子项或Repeater子项 Window width 640 hei
  • tslib-1.4在I.MX6ULL开发板上电容屏不能触摸问题

    一 前言 在采用触摸屏的移动终端中 xff0c 触摸屏性能的调试是个重要问题之一 xff0c 因为电磁噪声的缘故 xff0c 触摸屏容易存在点击不准确 有抖动等问题 Tslib是一个开源的程序 xff0c 能够为触摸屏驱动获得的采样提供诸如
  • C++与QML混合编程

    一 前言 简单来说 xff0c 混合编程就是通过Qml高效便捷的构建UI界面 xff0c 而使用C 43 43 来实现业务逻辑和复杂算法 Qt集成了QML引擎和Qt元对象系统 xff0c 使得QML很容易从C 43 43 中得到扩展 xff
  • 卸载ROS功能包

    步骤方法 xff1a 1 首先卸载包 sudo apt get purge ros indigo 2 然后卸载依赖包 sudo apt get autoremove
  • 要点初见:通过ROS包nmea_navsat_driver读取GPS、北斗定位信息(C/C++)

    先前在树莓派上用C C 43 43 读取过GPS北斗双模定位模块 xff0c 但因为定位模块的若干条定位数据无法立刻读取 xff0c 需要用delay 延迟1到2秒的时间才能把所有定位数据都读取进程序 xff0c 又不想写多线程 xff0c
  • 自动驾驶-使用卡尔曼滤波算法定位和跟踪

    参加过科一的人都知道 xff0c 学车的第一步不是操控车辆而是遵守交规 xff0c 行车礼让 xff0c 确保安全 可见安全驾驶才是行车的第一原则 为了确保安全 xff0c 司机应该观察周围车辆和行人的位置 xff0c 保持安全距离 自动驾
  • ROS使用笔记

    文章目录 1 提取bag中固定topic或者固定时间段数据2 提取pcd数据3 记录数据4 service amp action5 roslaunch文件6 自定义消息7 from raw velodyne packets to velod
  • linux安装Android Studio

    linux安装Android Studio 1 先在https developer android google cn studio hl 61 zh cn下载源码安装包 2 安装64位所需要的库 2 1如果使用的是Ubuntu的话执行以下
  • OpenCV中Mat的初始化与赋值

    1 type数据类型 常量类型的命名规则为 xff1a CV 位数 43 数据类型 43 通道数 关系如下 xff1a C1 C2 C3 C4 CV 8U 0 8 16 24 CV 8S 1 9 17 25 CV 16U 2 10 18 2
  • 近十年的VI-SLAM算法综述与发展

    本文主要总结一下这几年工作中遇到过以及改进过相关VIO算法 1 背景介绍 一个完整的 SLAM simultaneous localization and mapping 框架包括传感器数据 前端 后端 回环检测与建图 xff0c 如图1所
  • 当前开源的SLAM方案汇总2021.02

    感谢SLAMer前辈们不断的拼搏与进取 xff0c 才有了现在的丰富的学习资料 xff01 以下是至今SLAM开源代码的资料汇总 xff0c 后续将会更新主流slam开源代码的注释版本 xff0c 希望对研究SLAM的同学们有帮助 PTAM
  • VSLAM算法中的数学基础知识详细了解

    学习SLAM经验告诉我 xff0c 入门SLAM一般只需要两种两个方面的条件 xff0c 一是要有扎实的数学基础 xff0c 二是要有强大的动手编程能力 xff0c 但是这两个条件对于刚入门的同学来说 xff0c 极具挑战性 学习SLAM的
  • 2021互联网大厂职级对应薪资一览表

    原文连接 xff1a https mp weixin qq com s nYNZjJJzrO0Sc5h2AEPnaQ 互联网大厂新入职员工各职级薪资对应表 xff08 技术线 xff09 图片数据来源 xff1a 知乎加 上面的表格不排除有
  • “undefined reference to“ 问题及解决方法 实例分析

    在实际编译代码的过程中 xff0c 我们经常会遇到 34 undefined reference to 34 的问题 xff0c 简单的可以轻易地解决 xff0c 但有些却隐藏得很深 xff0c 需要花费大量的时间去排查 工作中遇到了各色各
  • int 占几个字节

    4个字节或2个字节 xff0c 主要看操作系统 xff0c 和编译器有关 xff0c 一个int的大小是操作系统的一个字长 TC是16位系统程序 xff0c 所以int是16bit xff0c 也就是两个字节 在32位linux和32位或6
  • ORBSLAM3 VIO初始化

    按照规矩 xff0c 先讲一下ORBSLAM3中的初始化大致流程 根据ORB SLAM3的论文介绍 xff0c IMU的初始化方法是基于下面3点 xff1a 1 xff09 纯视觉SLAM可以提供很好的位姿估计 xff0c 所以可以用纯视觉
  • 不一样的静态初始化——OpenVins

    今天讲一下黄国权老师实验室开源的OpenVins工程中的IMU初始化 xff0c 一般VIO初始化分为两种 xff0c 一种是静态初始化 xff0c 一种是动态初始化 xff0c 而OpenVins则利用加速度的方差差异将运动分为两种状态