MSCKF第6讲:状态与协方差

2024-03-22 01:36
文章标签 状态 协方差 msckf

本文主要是介绍MSCKF第6讲:状态与协方差,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

MSCKF中状态与协方差

文章目录

  • MSCKF中状态与协方差
  • 1 状态
  • 2 IMU状态与噪声协方差
    • 2.1 相关定义
    • 2.2 运动方程—IMU连续噪声协方差
    • 2.3 误差状态协方差矩阵
  • 3 cam状态

1 状态

msckf_vio.h

状态 StateServer state_server;

注意到,实际上imu_statecam_states近似同步,并不是所有的imu数据都会建立一个状态。但是会处理区间内所有的imu数据。

在这里插入图片描述

struct StateServer {IMUState imu_state;Cam cam_states;// State covariance matrix	Eigen::MatrixXd state_cov;				// 误差状态(包括IMU和Cam)协方差矩阵Eigen::Matrix<double, 12, 12> continuous_noise_cov;		// IMU连续噪声协方差 4*3,即运动方程中的噪声方差
};// state_cov = A*state_cov*A + continuous_noise_cov 就是满足高斯运算,误差状态协方差由上一个时刻递推,然后再加上噪声协方差矩阵。

  下面G表示世界系globalI表示IMU坐标系(作为body系),cam0表示左目相机系。关于坐标系表示的申明,下面这种表达方式 G I R ^I_G{R} GIR等价于 R I G {R}_{IG} RIG,是一种常见的转换关系。

2 IMU状态与噪声协方差

2.1 相关定义

(4+3+3+3+3)×1 = 16×1
X I = [ G I q ˉ T b g T G v I T b a T G p I T ] T \mathbf{X}_\mathrm{I}=\begin{bmatrix}^I_G\bar{q}^T&\mathbf{b}_g^T&^G\mathbf{v}_I^T&\mathbf{b}_a^T&^G\mathbf{p}_I^T\end{bmatrix}^T XI=[GIqˉTbgTGvITbaTGpIT]T

  • G I q ˉ T ^I_G\bar{q}^T GIqˉT表示 the rotation from frame {G} to frame {I},描述世界系到惯性系的旋转,用单位四元数表示,4维。
  • G p I T ^G\mathbf{p}_I^T GpIT G v I T ^G\mathbf{v}_I^T GvIT表示位置和速度,即平移量,the IMU position and velocity with respect to {G},在世界系下表示。
  • b g T \mathbf{b}_g^T bgT b a T \mathbf{b}_a^T baT分别表示the biases affecting the gyroscope and accelerometer measurements,即陀螺仪和加速度计的偏差。

imu_state.h

状态量含义
Eigen::Vector4d orientation q i w q_{iw} qiw
Eigen::Vector3d position t w i t_{wi} twi表示IMU在世界坐标系中的位置
Eigen::Vector3d velocity w v ^wv wv表示IMU在世界坐标系中的速度
Eigen::Vector3d gyro_bias b g b_{g} bg 角速度偏差,IMU静态初始化计算
Eigen::Vector3d acc_bias b a b_{a} ba加速度偏差,IMU静态初始化计算
Eigen::Matrix3d R_imu_cam0 R c 0 i R_{c_0i} Rc0i
Eigen::Vector3d t_cam0_imu t i c 0 t_{ic_0} tic0
static double gyro_noise、acc_noise n g n_{g} ng n a n_{a} na,均值为0的高斯噪声,主要利用协方差
static double gyro_bias_noise、acc_bias_noise n b g n_{bg} nbg n b a n_{ba} nba
static Eigen::Isometry3d T_imu_bodyidentity
static Eigen::Vector3d gravity w g ^wg wg
Eigen::Vector4d orientation_null可观性约束
Eigen::Vector3d position_null
Eigen::Vector3d velocity_null

  注意gyro_biasgyro_noise的区别,一个是角速度偏置(均值),一个是角速度噪声方差

2.2 运动方程—IMU连续噪声协方差

   state_server.continuous_noise_cov是运动方程中的噪声方差,由使用者提供,计算一次后不再发生变化。

imu参数—噪声标准差


nh.param<double>("noise/gyro", IMUState::gyro_noise, 0.001);
nh.param<double>("noise/acc", IMUState::acc_noise, 0.01);
nh.param<double>("noise/gyro_bias", IMUState::gyro_bias_noise, 0.001);
nh.param<double>("noise/acc_bias", IMUState::acc_bias_noise, 0.01);
// 特征的噪声
nh.param<double>("noise/feature", Feature::observation_noise, 0.01);

对应方差

IMUState::gyro_noise *= IMUState::gyro_noise;
IMUState::acc_noise *= IMUState::acc_noise;
IMUState::gyro_bias_noise *= IMUState::gyro_bias_noise;
IMUState::acc_bias_noise *= IMUState::acc_bias_noise;
Feature::observation_noise *= Feature::observation_noise;

构建连续噪声协方差

state_server.continuous_noise_cov = Matrix<double, 12, 12>::Zero();
state_server.continuous_noise_cov.block<3, 3>(0, 0) = Matrix3d::Identity() * IMUState::gyro_noise;
state_server.continuous_noise_cov.block<3, 3>(3, 3) = Matrix3d::Identity() * IMUState::gyro_bias_noise;
state_server.continuous_noise_cov.block<3, 3>(6, 6) = Matrix3d::Identity() * IMUState::acc_noise;
state_server.continuous_noise_cov.block<3, 3>(9, 9) = Matrix3d::Identity() * IMUState::acc_bias_noise;

应用:卡尔曼滤波应用阶段–计算先验误差状态协方差矩阵

state_cov = A*state_cov*A + continuous_noise_cov

Matrix<double, 21, 21> Q =Phi * G * state_server.continuous_noise_cov * G.transpose() * Phi.transpose() * dtime;state_server.state_cov.block<21, 21>(0, 0) =Phi * state_server.state_cov.block<21, 21>(0, 0) * Phi.transpose() + Q;

2.3 误差状态协方差矩阵

配置文件yaml中提供了误差状态初始协方差state_server.state_cov

<!-- These values should be covariance --><param name="initial_covariance/velocity" value="0.25"/><param name="initial_covariance/gyro_bias" value="0.01"/><param name="initial_covariance/acc_bias" value="0.01"/><param name="initial_covariance/extrinsic_rotation_cov" value="2.742e-3"/><param name="initial_covariance/extrinsic_translation_cov" value="4e-4"/>

初始化:旋转和平移误差状态协方差初始置为0,每一个变量是3维矩阵,7个变量一共21维度。一开始这个误差状态协方差的值是通过配置文件给出的!

外参

(4+3)×1
C I q ⊤ I p C ⊤ _C^I\mathbf{q}^\top\quad{}^I\mathbf{p}_C^\top CIqIpC

state_server.state_cov = MatrixXd::Zero(21, 21);
for (int i = 3; i < 6; ++i)state_server.state_cov(i, i) = gyro_bias_cov;
for (int i = 6; i < 9; ++i)state_server.state_cov(i, i) = velocity_cov;
for (int i = 9; i < 12; ++i)state_server.state_cov(i, i) = acc_bias_cov;
for (int i = 15; i < 18; ++i)// 外参 Rbcstate_server.state_cov(i, i) = extrinsic_rotation_cov;
for (int i = 18; i < 21; ++i)// 外参tbcstate_server.state_cov(i, i) = extrinsic_translation_cov;

卡尔曼滤波预测阶段

state_server.state_cov.block<21, 21>(0, 0) =Phi * state_server.state_cov.block<21, 21>(0, 0) * Phi.transpose() + Q;

预测之后更新cam部分,就是imu变了,cam也改变

    // 7. 如果有相机状态量,那么更新imu状态量与相机状态量交叉的部分if (state_server.cam_states.size() > 0){// 起点是0 21  然后是21行 state_server.state_cov.cols() - 21 列的矩阵// 也就是整个协方差矩阵的右上角,这部分说白了就是imu状态量与相机状态量的协方差,imu更新了,这部分也需要更新state_server.state_cov.block(0, 21, 21, state_server.state_cov.cols() - 21) =Phi * state_server.state_cov.block(0, 21, 21, state_server.state_cov.cols() - 21);.....}

状态增广(new cam come from)后的误差状态协方差

// 4. 增广协方差矩阵
// 简单地说就是原来的协方差是 21 + 6n 维的,现在新来了一个伙计,维度要扩了
// 并且对应位置的值要根据雅可比跟这个时刻(也就是最新时刻)的imu协方差计算
// 4.1 扩展矩阵大小 conservativeResize函数不改变原矩阵对应位置的数值
// Resize the state covariance matrix.
size_t old_rows = state_server.state_cov.rows();
size_t old_cols = state_server.state_cov.cols();
state_server.state_cov.conservativeResize(old_rows + 6, old_cols + 6);

卡尔曼滤波更新阶段

// 4. 更新协方差
MatrixXd I_KH = MatrixXd::Identity(K.rows(), H_thin.cols()) - K * H_thin;
state_server.state_cov = I_KH * state_server.state_cov;

滑动窗口溢出后

if (cam_state_end < state_server.state_cov.rows())
{state_server.state_cov.block(cam_state_start, 0,state_server.state_cov.rows() - cam_state_end,state_server.state_cov.cols()) =state_server.state_cov.block(cam_state_end, 0,state_server.state_cov.rows() - cam_state_end,state_server.state_cov.cols());state_server.state_cov.block(0, cam_state_start,state_server.state_cov.rows(),state_server.state_cov.cols() - cam_state_end) =state_server.state_cov.block(0, cam_state_end,state_server.state_cov.rows(),state_server.state_cov.cols() - cam_state_end);state_server.state_cov.conservativeResize(state_server.state_cov.rows() - 6, state_server.state_cov.cols() - 6);
}
else
{state_server.state_cov.conservativeResize(state_server.state_cov.rows() - 6, state_server.state_cov.cols() - 6);
}

3 cam状态

  利用滑动窗口来记录的,不只是一帧的相机姿态。at any time instant the EKF state vector comprises (i) the evolving IMU state (ii)a history of up to N max past poses of the camera
X C = [ T m T ⋯ T n T ] T \mathbf{X}_\mathrm{C}=\begin{bmatrix}\mathbf{T}_m^T\cdots\mathbf{T}_n^T\end{bmatrix}^T XC=[TmTTnT]T
  注意相机的每个T都是由 C q G ^C{q}_G CqG G p C a m 0 ^G\mathbf{p}_{Cam0} GpCam0表示(C也是cam0,简单表示,(4+3)×1×N

  说白了就是给每一帧创建了一个结构体,里面存储了基本变量,类似于ORB中的Frame

cam_state.h

状态量含义
Eigen::Vector4d orientation q c w q_{cw} qcw
Eigen::Vector3d position t w c t_{wc} twc
Eigen::Isometry3d T_cam0_cam1 T c 1 c 0 T_{c_1c_0} Tc1c0
Eigen::Vector4d orientation_null修改测量雅可比矩阵,后面再细看
Eigen::Vector3d position_null
StateIDType id当前帧状态id
double time当前帧对应时间戳

这篇关于MSCKF第6讲:状态与协方差的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/834269

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

hdu1565(状态压缩)

本人第一道ac的状态压缩dp,这题的数据非常水,很容易过 题意:在n*n的矩阵中选数字使得不存在任意两个数字相邻,求最大值 解题思路: 一、因为在1<<20中有很多状态是无效的,所以第一步是选择有效状态,存到cnt[]数组中 二、dp[i][j]表示到第i行的状态cnt[j]所能得到的最大值,状态转移方程dp[i][j] = max(dp[i][j],dp[i-1][k]) ,其中k满足c

状态dp总结

zoj 3631  N 个数中选若干数和(只能选一次)<=M 的最大值 const int Max_N = 38 ;int a[1<<16] , b[1<<16] , x[Max_N] , e[Max_N] ;void GetNum(int g[] , int n , int s[] , int &m){ int i , j , t ;m = 0 ;for(i = 0 ;

hdu3006状态dp

给你n个集合。集合中均为数字且数字的范围在[1,m]内。m<=14。现在问用这些集合能组成多少个集合自己本身也算。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.Inp

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

qml states 状态

states 状态 在QML中,states用于定义对象在不同状态下的属性变化。每个状态可以包含一组属性设置,当状态改变时,这些属性设置会被应用到对象上。 import QtQuick 2.15import QtQuick.Controls 2.15// 定义应用程序的主窗口ApplicationWindow {visible: true // 使窗口可见width: 640 /

[轻笔记] ubuntu Shell脚本实现监视指定进程的运行状态,并能在程序崩溃后重启动该程序

根据网上博客实现,发现只能监测进程离线,然后对其进行重启;然而,脚本无法打印程序正常状态的信息。自己通过不断修改测试,发现问题主要在重启程序的命令上(需要让重启的程序在后台运行,不然会影响监视脚本进程,使其无法正常工作)。具体程序如下: #!/bin/bashwhile [ 1 ] ; dosleep 3if [ $(ps -ef|grep exe_name|grep -v grep|

在Webmin上默认状态无法正常显示 Mariadb V11.02及以上版本

OS: Armbian OS 24.5.0 Bookworm Mariadb V11.02及以上版本 Webmin:V2.202 小众问题,主要是记录一下。 如题 Webmin 默认无法 Mariadb V11.02及以上版本 如果对 /etc/webmin/mysql/config 文件作相应调整就可以再现Mariadb管理界面。 路径+文件:/etc/webmin/mysql/config