open_vins(三):imu静止初始化

2023-05-16

      • 一.静止初始化原理
      • 二.理论公式
      • 三.相关代码
      • 四.小结:

初始化是指在系统启动阶段,需要估计重力方向(gravity direction)、加速度计以及陀螺仪biases (accelerometer and gyroscope biases)、初始速度(initial velocity)、初始位置(initial position)等。

OpenVINS系统中,只估计了重力方向、加速度计/陀螺仪biases。
初始化函数位于:ov_msckf/src/core/VioManager.cpp 中
Manager::try_to_initialize()

一.静止初始化原理

静止初始化是指在视频序列开始阶段,需要有一段静止状态。
系统利用静止状态的IMU数据来估计重力方向、加速度计陀螺仪biases。

静止初始化需要检测imu的跳变过程:
其中包含两个状态:静止状态、跳变状态
在这里插入图片描述

通过设定一个阈值[_imu_excite_threshold],可以判断imu是否得到足够的激励,从得到运动激励前的一段静止状态下的imu测量值,根据静止状态测量值,估算出imu初始化参数。

主要步骤:

  1. 将imu数据按固定时间的窗口(0.5s - 2s)划分
  2. 求最新的窗口w1 中imu加速度的方差 a_var,判断是否出现"跳变"
  3. 若a_var1 < imu激励阈值,则说明窗口w1是一段静止状态,返回false;
    若a_var1 >= imu激励阈值,则说明窗口w1出现跳变,下步4 -> 对第二近的窗口w2进行判断
  4. 若a_var2 < imu激励阈值,则使用w2窗口的imu数据进行系统初始化;
    计算窗口w2的平均加速度与角速度 以及方差.
  5. 静止初始化求出重力方向(gravity direction)、初始速度(initial velocity)、初始位置(initial position)、加速度计以及陀螺仪biases (accelerometer and gyroscope biases)

代码框图如下:
在这里插入图片描述

二.理论公式

step1:计算初始旋转矩阵

窗口w2的加速度计平均值 : am2_avg
窗口w2的陀螺仪平均值 : wm2_avg

因为,在世界系下,静止时的加速度测量值为(0,0,g)
将窗口w2的am2_avg除以其模长,得到平均加速度的方向(单位向量),即为世界系z轴的方向在imu坐标系上的投影:
在这里插入图片描述
确定z轴方向后,通过施密特正交化构建单位坐标系。

假设,e1为imu系的xi轴对应的单位方向向量:
在这里插入图片描述
将xi轴投影到 zw-xw平面,求出xw轴在imu坐标系下的方向向量:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
y轴方向由x轴和z轴叉乘得到:
在这里插入图片描述
通过上述步骤,得到了从世界系w到imu坐标系的初始旋转 Rwi=[x y z]

step2:计算陀螺仪bias:
静止时刻的陀螺仪理想测量值(角速度)应该为0,因此陀螺仪的bias即窗口w2陀螺仪数据的平均值 [wm2_avg]
在这里插入图片描述
step3:计算加速度计bias:
静止时的加速度计bias为加速度平均值与实际重力加速度的差:
在这里插入图片描述
g为世界系下的重力加速度,R为第一步求出来的旋转矩阵,将重力矢量从世界系投影到imu坐标系下。

三.相关代码

在 feed_measurement_stereo/feed_measurement_monocular 过程中调用初始化函数try_to_initialize()

bool VioManager::try_to_initialize() {
    // Returns from our initializer
    double time0;
    Eigen::Matrix<double, 4, 1> q_GtoI0;
    Eigen::Matrix<double, 3, 1> b_w0, v_I0inG, b_a0, p_I0inG;
    // Try to initialize the system
    // We will wait for a jerk if we do not have the zero velocity update enabled
    // Otherwise we can initialize right away as the zero velocity will handle the stationary case
    bool wait_for_jerk = (updaterZUPT == nullptr);
    bool success = initializer->initialize_with_imu(time0, q_GtoI0, b_w0, v_I0inG, b_a0, p_I0inG, wait_for_jerk);
    // Return if it failed
    if (!success) {
        return false;
    }
    // Make big vector (q,p,v,bg,ba), and update our state
    // Note: start from zero position, as this is what our covariance is based off of
    Eigen::Matrix<double,16,1> imu_val;
    imu_val.block(0,0,4,1) = q_GtoI0;
    imu_val.block(4,0,3,1) << 0,0,0;
    imu_val.block(7,0,3,1) = v_I0inG;
    imu_val.block(10,0,3,1) = b_w0;
    imu_val.block(13,0,3,1) = b_a0;

    state->_imu->set_value(imu_val);
    state->_imu->set_fej(imu_val);
    state->_timestamp = time0;
    startup_time = time0;
    // Cleanup any features older then the initialization time
    trackFEATS->get_feature_database()->cleanup_measurements(state->_timestamp);
    if(trackARUCO != nullptr) {
        trackARUCO->get_feature_database()->cleanup_measurements(state->_timestamp);
    }
    // Else we are good to go, print out our stats
    printf(GREEN "[INIT]: orientation = %.4f, %.4f, %.4f, %.4f\n" RESET,state->_imu->quat()(0),state->_imu->quat()(1),state->_imu->quat()(2),state->_imu->quat()(3));
    printf(GREEN "[INIT]: bias gyro = %.4f, %.4f, %.4f\n" RESET,state->_imu->bias_g()(0),state->_imu->bias_g()(1),state->_imu->bias_g()(2));
    printf(GREEN "[INIT]: velocity = %.4f, %.4f, %.4f\n" RESET,state->_imu->vel()(0),state->_imu->vel()(1),state->_imu->vel()(2));
    printf(GREEN "[INIT]: bias accel = %.4f, %.4f, %.4f\n" RESET,state->_imu->bias_a()(0),state->_imu->bias_a()(1),state->_imu->bias_a()(2));
    printf(GREEN "[INIT]: position = %.4f, %.4f, %.4f\n" RESET,state->_imu->pos()(0),state->_imu->pos()(1),state->_imu->pos()(2));
    return true;
}

继而调用 initialize_with_imu (time0, q_GtoI0, b_w0, v_I0inG, b_a0, p_I0inG, wait_for_jerk);

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) {

    // 若无imu测量值,则返回
    if(imu_data.empty()) {
        return false;
    }
    // 最新的imu数据时间
    double newesttime = imu_data.at(imu_data.size()-1).timestamp;
    
   // _window_length 为launch中设定的imu初始化窗口的采用时间:0.5~2s
    // 取最近两段时间内的imu数据进行用于初始化
    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
    // 计算最近一个窗口内IMU加速度方差
    Eigen::Matrix<double,3,1> a_avg = Eigen::Matrix<double,3,1>::Zero();
    for(IMUDATA data : window_newest) {
        a_avg += data.am;
        //cout<<data.am<<endl;
    }
    a_avg /= (int)window_newest.size();
    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));

    //方差过小
   // _imu_excite_threshold 是launch中设定的判断imu激励的阈值,高于阈值则表示运动,低于阈值为静止
       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;
    }

    // 方差够大
    // 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();

    // 计算最近第二个窗口内IMU加速度方差
    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)
    Eigen::Vector3d z_axis = linavg/linavg.norm();
    // Create an x_axis
    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
    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)
    Eigen::Matrix<double,3,1> bg = angavg;
    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;
}

四.小结:

此处进行imu初始化,是通过静止时加速度计测量值与重力矢量方向一致的原理,得到世界坐标系w到imu坐标系的相对旋转R.(z轴(0,0,1))

在其他常用的vio系统中,通常将视觉的第一帧作为世界系,由于相机与imu之间的相对关系已知,因此可方便地得到相机系相对于世界系的位姿,以及imu系相对于世界系的位姿

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

open_vins(三):imu静止初始化 的相关文章

  • vins 解读_代码解读 | VINS_Mono中的鱼眼相机模型

    本文作者是计算机视觉life公众号成员蔡量力 xff0c 由于格式问题部分内容显示可能有问题 xff0c 更好的阅读体验 xff0c 请查看原文链接 xff1a 代码解读 VINS Mono中的鱼眼相机模型 VINS Mono中的鱼眼相机模
  • VINS-Mono跑Kitti数据集

    参考文章 xff1a VINS Mono KITT00 测试 知乎 如何在kitti raw data上跑起vins mono 知乎 实际上我参考的是LIO SAM里将KITTI转化为bag的方法 Debug https blog csdn
  • VINS中陀螺仪零偏的估计

    VINS中关于陀螺仪零偏的初始化估计 对于窗口中得连续两帧 b k b k b k 和 b
  • 星网宇达(惯导+IMU)设备实现自动采点

    一 创建和打开gps Road txt文件 xff0c 准备往里写数据 FILE span class token operator span p span class token operator 61 span span class t
  • 关于VINS-MONO与VIO轨迹漂移问题定位的一些方向

    整个VINS MONO系统 xff0c 较容易在系统静止或外力给予较大冲击时产生轨迹漂移 xff0c 原因是imu的bias在预积分中持续发散 xff0c 视觉重投影误差产生的约束失效 如静止 xff0c 先验约束可能会在LM的线性求解器中
  • VINS-Mono

    文章目录 初始化框架缺点ORB SLAM的Local Map VINS的滑窗 逐次逼近式去畸变给后端提供的特征点信息光流追踪对极约束F去除外点 rejectWithF 特征点均匀化预积分系统初始化初始化时不校正bias a误差卡尔曼滤波误差
  • NVIDIA Jetson Xavier NX部署VINS-fusion-GPU

    NVIDIA Jetson Xavier NX部署VINS fusion GPU 一 环境配置 xff08 Ubuntu 18 04 xff09 1 Cuda 10 2的安装 span class token function sudo s
  • VINS-FUSION-GPU在jetson nx上的实现

    需要安装经过修改的Ubuntu18系统 https span class token operator span span class token comment developer nvidia com zh cn embedded do
  • realsense d435i标定imu与camera

    realsense d435i标定imu与camera 1 标定目的 realsense d435i包含两个红外相机 红外发射器 RGB相机和IMU四个模块 xff0c 显然四个传感器的空间位置是不同的 xff0c 我们在处理图像和IMU数
  • vins-fusion代码解读[五] imu在vins里的理解

    SLAM新手 xff0c 欢迎讨论 IMU作用 vins中 xff0c IMU只读取IMU六轴的信息 xff0c 3轴线加速度 xff08 加速度计 xff09 和3轴角速度 xff08 陀螺仪 xff09 通过对陀螺仪的一次积分 xff0
  • VINS-Mono视觉初始化代码详解

    摘要 视觉初始化的过程是至关重要的 xff0c 如果在刚开始不能给出很好的位姿态估计 xff0c 那么也就不能对IMU的参数进行精确的标定 这里就体现了多传感器融合的思想 xff0c 当一个传感器的数据具有不确定性的时候 xff0c 我们需
  • Ardupilot IMU恒温控制代码学习

    目录 文章目录 目录 摘要 第一章原理图学习 第二章恒温代码学习 1 目标温度怎么设置 摘要 本节主要学习ardupilot的IMU恒温控制代码 采用的飞控是pixhawk v5 欢迎一起交流学习 第一章原理图学习
  • Ubuntu 18.04 ———(Intel RealSense D435i)运行VINS-Mono

    Intel RealSense D435i 一 准备工作二 修改参数rs camera launchrealsense color config yaml 参考文献 一 准备工作 1 Intel Realsense D435i Ubuntu
  • 【VINS论文翻译】VINS-Mono: A Robust and Versatile Monocular Visual-Inertial State Estimator

    回到目录 写在前面 港科大的VINS Mono作为目前state of the art的开源VIO项目 xff0c 是研究视觉与IMU紧耦合的必读算法 xff0c 网上的论文解读与代码实现也非常丰富 xff08 感谢 xff01 xff09
  • 武汉大学研究生组合导航课程合集【2022年春】

    第四公式中kk是权重 zk hx 为innovation新息 即真实的观测 估计的观测 前者包含观测误差 gps的电离层 多径 后者包含估计误差 kk近似1 则无限相信新观测 kk 0 相信估计
  • IMU+摄像头实现无标记运动捕捉

    惯性传感和计算机视觉的进步为在临床和自然环境中获得精准数据带来了新可能 然而在临床应用时需要仔细地将传感器与身体对齐 这减慢了数据收集过程 随着无标记运动捕捉的发展 研究者们提出了一个新的深度学习模型 利用来自视觉 惯性传感器及其噪声数据来
  • Linux的c编程-文件节点的打开与读写操作

    1 open 打开文件 相关函数 read write fcntl close link stat umask unlink fopen 表头文件 include
  • 2021-08-06

    在编译OKVIS中 执行make j8时报错的解决方法 1 根据github上OKVIS的安装步骤一步一步执行 由于github经常进不去 我就进了gitee网站查到OKVIS的安装步骤 参考链接 https gitee com bill4
  • 四元素与旋转矩阵

    如何描述三维空间中刚体的旋转 是个有趣的问题 具体地说 就是刚体上的任意一个点P x y z 围绕过原点的轴 i j k 旋转 求旋转后的点P x y z 旋转矩阵 旋转矩阵乘以点P的齐次坐标 得到旋转后的点P 因此旋转矩阵可以描述旋转 x
  • IMU姿态计算

    总述 IMU即惯性测量单元 主要用于对机体的加速度与角速度的测算 使用场景很多 例如 平衡车 惯性导航等等 姿态 姿态角 Euler angles 是用于描述物体在三维空间中的旋转姿态的一种表示方法 它由三个角度组成 通常表示物体绕三个轴

随机推荐

  • 相机标定和双目相机标定标定原理推导及效果展示

    文章目录 前言一 相机标定1 相机的四个坐标系2 相机的畸变 二 张正友标定法1 求解内参矩阵与外参矩阵的积2 求解内参矩阵3 求解外参矩阵4 标定相机的畸变参数5 双目标定6 极线矫正 xff08 立体校正 xff09 三 视差图与深度图
  • keras:tensor从全连接层输出到卷积层

    一 tensor从卷积层输出到全连接层 用过keras的都知道 xff0c 想从卷积层输出tensor到全连接层 xff0c 只需加一层 xff1a model add Flatten shape就不会出现错误 二 但是如果从全连接层输出t
  • 保研面试复习之数据结构篇

    数据项 数据元素和数据结构的概念 数据项是组成数据元素的 xff0c 有独立含义的 xff0c 不可分割的最小单位 数据元素是数据的基本单位 数据结构是带结构的数据元素的集合 数据结构包括逻辑结构和存储结构两个层次 数据结构的三要素是逻辑结
  • 视觉里程计的重定位问题1——SVO的重定位部分

    SVO的重定位部分代码解析与分析 SVO的重定位功能体现在 xff1a 运动跟踪丢失后通过与上一关键帧匹配以及地图点投影 xff0c 找回当前相机位姿 由于没有后端和回环 xff0c SVO的重定位并不是回环校正后的重定位 代码部分被放在运
  • 组合导航(一):定位技术分类与介绍

    组合导航 xff08 一 xff09 xff1a 导航定位技术分类与介绍 一 定位技术分类1 1 基于相对测量的定位 xff08 航位推算 xff09 1 2 基于绝对测量的定位1 3 组合定位 一 定位技术分类 1 1 基于相对测量的定位
  • git bash可以正常commit,但是 VSCode 里不能正常commit使用的解决方法

    问题描述 同一路径下的源码 xff0c 使用git bash可以正常commit xff0c 但是使用vscode提交commit就会一直卡住 xff0c 转圈圈 参考方案链接 xff1a VS CODE GIT 500 问题处理 pudn
  • 组合导航(四):惯性导航系统

    1 惯性导航系统的物理平台2 惯性测量单元IMU3 惯性传感器的测量值3 1静止状态下的加速度测量3 2静止与运动状态下的角速度测量 4 惯性传感器误差4 1 系统误差 xff08 可通过实验进行校正 xff09 4 2 随机误差4 3 惯
  • 组合导航(七):卡尔曼滤波

    Kalman滤波1 离散卡尔曼滤波2 卡尔曼滤波的流程2 1 预测与时间更新2 2 测量更新与校正 3 卡尔曼滤波 算法步骤4 非线性卡尔曼滤波4 1 线性化kalman滤波4 2 扩展kalman滤波 5 卡尔曼滤波发散控制5 1 KF过
  • 组合导航(八):INS/GPS组合导航

    INS GPS组合导航1 误差反馈1 1 开环INS GPS架构1 2 闭环INS GPS架构 2 组合导航的类型2 1 松耦合 的INS GPS组合导航2 2 紧耦合 的INS GPS组合导航2 3 深度耦合的 INS GPS组合导航 3
  • 组合导航(九):三维简化的INS/GPS组合导航系统

    简化INS与GPS组合系统在三维路面上的导航1 MEMS级IMU的三维定位的性能分析2 解决MEMS级IMU在路面导航中存在的问题3 三维简化的惯性传感器系统3 1 3D RISS概述3 2 xff08 轮式车辆 xff09 采用3D RI
  • PX4安装与编译

    第一步 xff1a 下载源码 下载方式一 xff1a git clone https github com PX4 Firmware git recursive 默认下载版本为master 下载时间比较长 xff0c 包含各种包以及依赖工具
  • PX4:【系统架构】

    PX4系统架构 由两个层组成 xff1a 一是飞行控制栈 xff08 flight stack xff09 二是中间件 xff08 middleware xff09 flight stack xff1a 集成了各种自主无人机的制导 导航以及
  • PX4:【uORB通讯机制】

    uORB xff1a Micro Object Request Broker PX4进程间的通讯机制 xff1a 多对多的信息发布与订阅方式 发布消息 xff1a 1 公告 advertise xff1a 相当于初始化 xff0c 在发布消
  • PX4:【传感器校准】

    sensor的校准校准步骤 xff1a 文件目录 xff1a 代码入口 xff1a 求解模型计算公式 sensor的校准 校准步骤 xff1a 首先通过地面站QGC进行校准 xff0c QGC将校准参数设置到sh文件中 此后再基于QGC的校
  • PX4:【sensor_combined】

    功能介绍消息内容sensor combined 产生机制 amp 代码流程 功能介绍 sensor combined 是一个冗余传感器集合的消息 xff0c 通过订阅多个传感器的数据 xff0c 将冗余的数据经过VoteSensorsUpd
  • PX4:【地面站传感器数据校准】

    上电 gt rsC 运行 sensor start commander start 入口函数 xff1a 位于commander文件夹中 Commader cpp Commander run xff08 xff09 commander lo
  • Windows和Linux双系统安装教程

    最近刚刚完成了Windows和Linux双系统 xff08 这里以Ubuntu安装为例 xff09 的安装 xff0c 应某奔同学要求 xff0c 这里简单记录下安装过程 系统启动盘准备Windows系统安装分出给Linux系统的磁盘空间安
  • MSCKF系列论文阅读与代码流程

    MSCKF原理与代码总结 算法原理前端理论 xff08 图像的特征提取与跟踪 xff09 后端理论 xff08 误差状态卡尔曼滤波模型 xff09 1 IMU状态预测1 1 IMU状态传播 xff08 p v q 4阶Runge Kutta
  • open_vins(二):rosbag精度测试

    一 xff0e ros读取与轨迹保存二 xff0e euroc数据集测试三 结论 一 xff0e ros读取与轨迹保存 运行open vins launch 读取ros数据包 xff1a roslaunch pgeneva ros eth
  • open_vins(三):imu静止初始化

    一 xff0e 静止初始化原理二 xff0e 理论公式三 xff0e 相关代码四 xff0e 小结 xff1a 初始化是指在系统启动阶段 xff0c 需要估计重力方向 gravity direction 加速度计以及陀螺仪biases ac