ORB-SLAM3中的IMU预积分

ORB-SLAM3中IMU预积分

文章目录

  • ORB-SLAM3中IMU预积分
  • 1读取IMU参数
  • 2 预积分噪声递推与预测
    • 2.1 更新预积分测量值dP和dV
    • 2.2 更新预积分噪声项的递推模型的矩阵A和B部分元素
    • 2.3 位置、速度预积分测量值对零偏的雅可比矩阵
    • 2.4 更新旋转预积分测量
    • 2.5 补充A和B矩阵剩余部分,更新协方差
    • 2.6 旋转预积分量对零偏的雅可比矩阵
  • 3 预积分零偏更新
  • 4 预积分残差雅可比计算

  IMU预积分之前也博客也提到几次了,这次把ORB-SLAM3中相应的流程记录下,与推导公式一一对应,顺带复习。

1读取IMU参数

Tracking::newParameterLoader和ORB2类似,都在这个追踪里面读取参数,这里会把读取的连续噪声离散化!

//IMU parameters
// 3. 读取imu参数
Sophus::SE3f Tbc = settings->Tbc();
mInsertKFsLost = settings->insertKFsWhenLost();
mImuFreq = settings->imuFrequency();
mImuPer = 0.001; //1.0 / (double) mImuFreq;     //TODO: ESTO ESTA BIEN?
float Ng = settings->noiseGyro();
float Na = settings->noiseAcc();
float Ngw = settings->gyroWalk();
float Naw = settings->accWalk();

// 把配置文件中的连续噪声离散化!!!!!!!!
const float sf = sqrt(mImuFreq);
mpImuCalib = new IMU::Calib(Tbc,Ng*sf,Na*sf,Ngw/sf,Naw/sf);

mpImuPreintegratedFromLastKF = new IMU::Preintegrated(IMU::Bias(),*mpImuCalib);

读取得参数被扔到这里构建协方差

/** 
 * @brief imu标定参数的构造函数
 * @param calib imu标定参数
 */
Calib::Calib(const Calib &calib)
{
    mbIsSet = calib.mbIsSet;
    // Sophus/Eigen parameters
    mTbc = calib.mTbc;
    mTcb = calib.mTcb;
    Cov = calib.Cov;
    CovWalk = calib.CovWalk;
}

Calib::Set

/** 
 * @brief 设置参数
 * @param Tbc_ 位姿变换
 * @param ng 噪声
 * @param na 噪声
 * @param ngw 随机游走
 * @param naw 随机游走
 */
void Calib::Set(const Sophus::SE3<float> &sophTbc, const float &ng, const float &na, const float &ngw, const float &naw)
{
    mbIsSet = true;
    const float ng2 = ng * ng;
    const float na2 = na * na;
    const float ngw2 = ngw * ngw;
    const float naw2 = naw * naw;

    // Sophus/Eigen
    mTbc = sophTbc;
    mTcb = mTbc.inverse();
    // 噪声协方差
    Cov.diagonal() << ng2, ng2, ng2, na2, na2, na2;
    // 随机游走协方差
    CovWalk.diagonal() << ngw2, ngw2, ngw2, naw2, naw2, naw2;
}

赋值校准后IMU噪声协方差矩阵

Preintegrated::Preintegrated(const Bias &b_, const Calib &calib)
{
    Nga = calib.Cov;
    NgaWalk = calib.CovWalk;
    Initialize(b_);
}

2 预积分噪声递推与预测

写在前面,这里想简单的把ORB-SLAM3中imu部分公式与代码相对应,理清楚顺序关系。首先给出预积分中相关变量的定义

float dT;
Eigen::Matrix<float,15,15> C;	
Eigen::Matrix<float,15,15> Info;
Eigen::DiagonalMatrix<float,6> Nga, NgaWalk;    // δa δg δba δbg对应得协方差矩阵

// Values for the original bias (when integration was computed)
Bias b;
Eigen::Matrix3f dR;             // 预积分、
Eigen::Vector3f dV, dP;
Eigen::Matrix3f JRg, JVg, JVa, JPg, JPa;    // 预积分量对零偏得雅可比
Eigen::Vector3f avgA, avgW;

2.1 更新预积分测量值dP和dV

  由于位置预积分测量值依赖“旧”的速度和旋转速度预积分测量值依赖“旧”的旋转,因此这里的计算顺序不能乱,先用“旧”数据计算位置预积分测量值,再计算速度预积分测量值。然后计算A和B矩阵中“旧”数据对应的元素。

  下面这个函数中传入的IMU数据是经过线性插值后,进行中值积分得到的,插值主要是在两个图像帧附近。

ImuTypes.cc

预积分 = 预积分测量 + 预积分噪声

位置预积分测量值(是利用“旧”的旋转和“旧”的速度)

Δ p ~ i j ≐ ∑ k = i j − 1 [ Δ v ~ i k Δ t + 1 2 Δ R ~ i k ( a ~ k − b i a ) Δ t 2 ] \Delta\tilde{\boldsymbol{p}}_{ij}\doteq\sum_{k=i}^{j-1}\left[\Delta\tilde{\boldsymbol{v}}_{ik}\Delta t+\frac{1}{2}\Delta\tilde{\boldsymbol{R}}_{ik}\left(\tilde{\boldsymbol{a}}_{k}-\boldsymbol{b}_{i}^{a}\right)\Delta t^{2}\right] Δp~ijk=ij1[Δv~ikΔt+21ΔR~ik(a~kbia)Δt2]

速度预积分测量值(利用“旧”的旋转)

Δ v ~ i j = ∑ k = i j − 1 Δ R ~ i k ( a ~ k − b i a ) Δ t \Delta\tilde{\boldsymbol{v}}_{ij}=\sum_{k=i}^{j-1}\Delta\tilde{\boldsymbol{R}}_{ik}\left(\tilde{\boldsymbol{a}}_k-\boldsymbol{b}_i^a\right)\Delta t Δv~ij=k=ij1ΔR~ik(a~kbia)Δt

/**
 * @brief 预积分计算,更新noise
 * 
 * @param[in] acceleration  加速度计数据
 * @param[in] angVel        陀螺仪数据
 * @param[in] dt            两图像 帧之间时间差
 */
void Preintegrated::IntegrateNewMeasurement(const Eigen::Vector3f &acceleration, const Eigen::Vector3f &angVel, const float &dt)
{    // 考虑偏置后的加速度、角速度
    Eigen::Vector3f acc, accW;
    acc << acceleration(0) - b.bax, acceleration(1) - b.bay, acceleration(2) - b.baz;
    accW << angVel(0) - b.bwx, angVel(1) - b.bwy, angVel(2) - b.bwz;

    // 记录平均加速度和角速度
    avgA = (dT * avgA + dR * acc * dt) / (dT + dt);
    avgW = (dT * avgW + accW * dt) / (dT + dt);

    // Update delta position dP and velocity dV (rely on no-updated delta rotation)
    // 根据没有更新的dR来更新dP与dV  
    dP = dP + dV * dt + 0.5f * dR * acc * dt * dt;
    dV = dV + dR * acc * dt;
    
    ...
}

2.2 更新预积分噪声项的递推模型的矩阵A和B部分元素

  注意,A和B矩阵的部分元素使用的是“旧”数据,先更新这部分元素。

矩阵A

在这里插入图片描述

矩阵B

在这里插入图片描述

void Preintegrated::IntegrateNewMeasurement(const Eigen::Vector3f &acceleration, const Eigen::Vector3f &angVel, const float &dt){
    
	...
        
    // Step 1.构造协方差矩阵
    // 噪声矩阵的传递矩阵,这部分用于计算i到j-1历史噪声或者协方差
    Eigen::Matrix<float, 9, 9> A;
    A.setIdentity();
    // 噪声矩阵的传递矩阵,这部分用于计算j-1新的噪声或协方差,这两个矩阵里面的数都是当前时刻的,计算主要是为了下一时刻使用
    Eigen::Matrix<float, 9, 6> B;
    B.setZero();

    // 根据η_ij = A * η_i,j-1 + B_j-1 * η_j-1中的A矩阵和B矩阵对速度和位移进行更新
    Eigen::Matrix<float, 3, 3> Wacc = Sophus::SO3f::hat(acc);

    A.block<3, 3>(3, 0) = -dR * dt * Wacc;
    A.block<3, 3>(6, 0) = -0.5f * dR * dt * dt * Wacc;
    A.block<3, 3>(6, 3) = Eigen::DiagonalMatrix<float, 3>(dt, dt, dt);
    B.block<3, 3>(3, 3) = dR * dt;
    B.block<3, 3>(6, 3) = 0.5f * dR * dt * dt;
    
    ...
    
}

2.3 位置、速度预积分测量值对零偏的雅可比矩阵

  用递推方式计算零偏更新后,预积分量对零偏的雅可比矩阵。先计算位置预积分量对零偏的雅可比矩阵,再计算速度预积分量对零偏的雅可比矩阵.当“旧”的旋转预积分测量值不再需要时再更新它

位置

∂ Δ p ~ i j ∂ b g = ∑ k = i j − 1 ( ∂ Δ v ~ i k ∂ b g Δ t − 1 2 Δ R ~ i k ( a ~ k − b i a ) ∧ ∂ Δ R ~ i k ∂ b g Δ t 2 ) = ∂ Δ p ~ i , j − 1 ∂ b g + ( ∂ Δ v ~ i , j − 1 ∂ b g Δ t − 1 2 Δ R ~ i , j − 1 ( a ~ j − 1 − b i a ) ∧ ∂ Δ R ~ i , j − 1 ∂ b g Δ t 2 ) ∂ Δ p ~ i j ∂ b a = ∑ k = i j − 1 ( ∂ Δ v ~ i k ∂ b a Δ t − 1 2 Δ R ~ i k Δ t 2 ) = ∂ Δ p ~ i , j − 1 ∂ b a + ( ∂ Δ v ~ i , j − 1 ∂ b a Δ t − 1 2 Δ R ~ i , j − 1 Δ t 2 ) (15-67) \begin{aligned} &\frac{\partial\Delta\tilde{\boldsymbol{p}}_{ij}}{\partial b^g} =\sum_{k=i}^{j-1}\left(\frac{\partial\Delta\tilde{\boldsymbol{v}}_{ik}}{\partial\boldsymbol{b}^{g}}\Delta t-\frac{1}{2}\Delta\tilde{\boldsymbol{R}}_{ik}\left(\tilde{\boldsymbol{a}}_{k}-\boldsymbol{b}_{i}^{a}\right)^{\wedge}\frac{\partial\Delta\tilde{\boldsymbol{R}}_{ik}}{\partial\boldsymbol{b}^{g}}\Delta t^{2}\right) \\ &=\frac{\partial\Delta\tilde{\boldsymbol{p}}_{i,j-1}}{\partial\boldsymbol{b}^{g}}+\left(\frac{\partial\Delta\tilde{\boldsymbol{v}}_{i,j-1}}{\partial\boldsymbol{b}^{g}}\Delta t-\frac{1}{2}\Delta\tilde{\boldsymbol{R}}_{i,j-1}\left(\tilde{\boldsymbol{a}}_{j-1}-\boldsymbol{b}_{i}^{a}\right)^{\wedge}\frac{\partial\Delta\tilde{\boldsymbol{R}}_{i,j-1}}{\partial\boldsymbol{b}^{g}}\Delta t^{2}\right) \\ &\frac{\partial\Delta\tilde{p}_{ij}}{\partial b^a} =\sum_{k=i}^{j-1}\left(\frac{\partial\Delta\tilde{\boldsymbol{v}}_{ik}}{\partial\boldsymbol{b}^a}\Delta t-\frac12\Delta\tilde{\boldsymbol{R}}_{ik}\Delta t^2\right) \\ &=\frac{\partial\Delta\tilde{\boldsymbol{p}}_{i,j-1}}{\partial\boldsymbol{b}^{a}}+\left(\frac{\partial\Delta\tilde{\boldsymbol{v}}_{i,j-1}}{\partial\boldsymbol{b}^{a}}\Delta t-\frac{1}{2}\Delta\tilde{\boldsymbol{R}}_{i,j-1}\Delta t^{2}\right) \text{(15-67)} \end{aligned} bgΔp~ij=k=ij1(bgΔv~ikΔt21ΔR~ik(a~kbia)bgΔR~ikΔt2)=bgΔp~i,j1+(bgΔv~i,j1Δt21ΔR~i,j1(a~j1bia)bgΔR~i,j1Δt2)baΔp~ij=k=ij1(baΔv~ikΔt21ΔR~ikΔt2)=baΔp~i,j1+(baΔv~i,j1Δt21ΔR~i,j1Δt2)(15-67)

速度

∂ Δ v ~ i j ∂ b a = − ∑ k = i j − 1 ( Δ R ~ i k Δ t ) = ∂ Δ v ~ i , j − 1 ∂ b a − Δ R ~ i , j − 1 Δ t ∂ Δ v ~ i j ∂ b g = − ∑ k = i j − 1 ( Δ R ~ i k ( a ~ k − b i a ) ∧ ∂ Δ R ~ i k ∂ b g Δ t ) = ∂ Δ v ~ i , j − 1 ∂ b g − ( Δ R ~ i , j − 1 ( a ~ j − 1 − b i a ) ∧ ∂ Δ R ~ i , j − 1 ∂ b g Δ t ) \begin{aligned} &\frac{\partial\Delta\tilde{\boldsymbol{v}}_{ij}}{\partial b^{a}} =-\sum_{k=i}^{j-1}\left(\Delta\tilde{\boldsymbol{R}}_{ik}\Delta t\right) \\ &=\frac{\partial\Delta\tilde{\boldsymbol{v}}_{i,j-1}}{\partial\boldsymbol{b}^a}-\Delta\tilde{\boldsymbol{R}}_{i,j-1}\Delta t \\ &\frac{\partial\Delta\tilde{\boldsymbol{v}}_{ij}}{\partial b^g} =-\sum_{k=i}^{j-1}\left(\Delta\tilde{\boldsymbol{R}}_{ik}\left(\tilde{\boldsymbol{a}}_{k}-\boldsymbol{b}_{i}^{a}\right)^{\wedge}\frac{\partial\Delta\tilde{\boldsymbol{R}}_{ik}}{\partial\boldsymbol{b}^{g}}\Delta t\right) \\ &=\frac{\partial\Delta\tilde{\boldsymbol{v}}_{i,j-1}}{\partial\boldsymbol{b}^{g}}-\left(\Delta\tilde{\boldsymbol{R}}_{i,j-1}\left(\tilde{\boldsymbol{a}}_{j-1}-\boldsymbol{b}_{i}^{a}\right)^{\wedge}\frac{\partial\Delta\tilde{\boldsymbol{R}}_{i,j-1}}{\partial\boldsymbol{b}^{g}}\Delta t\right) \end{aligned} baΔv~ij=k=ij1(ΔR~ikΔt)=baΔv~i,j1ΔR~i,j1ΔtbgΔv~ij=k=ij1(ΔR~ik(a~kbia)bgΔR~ikΔt)=bgΔv~i,j1(ΔR~i,j1(a~j1bia)bgΔR~i,j1Δt)

void Preintegrated::IntegrateNewMeasurement(const Eigen::Vector3f &acceleration, const Eigen::Vector3f &angVel, const float &dt){
    
	...

// Update position and velocity jacobians wrt bias correction
// 因为随着时间推移,不可能每次都重新计算雅克比矩阵,所以需要做J(k+1) = j(k) + (~)这类事,分解方式与AB矩阵相同
// 论文作者对forster论文公式的基础上做了变形,然后递归更新,参见 https://github.com/UZ-SLAMLab/ORB_SLAM3/issues/212
JPa = JPa + JVa * dt - 0.5f * dR * dt * dt;
JPg = JPg + JVg * dt - 0.5f * dR * dt * dt * Wacc * JRg;
JVa = JVa - dR * dt;
JVg = JVg - dR * dt * Wacc * JRg;
    
    ...
        
}    

2.4 更新旋转预积分测量

已经利用完旧的旋转,现在来更新

Δ R ~ i j = ∏ k = i j − 1 Exp ⁡ ( ( ω ~ k − b i g ) Δ t ) \Delta\tilde{\boldsymbol{R}}_{ij}=\prod_{k=i}^{j-1}\operatorname{Exp}\left(\left(\tilde{\boldsymbol{\omega}}_k-\boldsymbol{b}_i^g\right)\Delta t\right) ΔR~ij=k=ij1Exp((ω~kbig)Δt)

void Preintegrated::IntegrateNewMeasurement(const Eigen::Vector3f &acceleration, const Eigen::Vector3f &angVel, const float &dt){
    
	...
// Update delta rotation
// Step 2. 构造函数,会根据更新后的bias进行角度积分
IntegratedRotation dRi(angVel, b, dt);
// 强行归一化使其符合旋转矩阵的格式
dR = NormalizeRotation(dR * dRi.deltaR);
    
     ...
        
}    

2.5 补充A和B矩阵剩余部分,更新协方差

  用最新的预积分测量值补充更新A和B矩阵中剩余的元素。

矩阵A

在这里插入图片描述

矩阵B

在这里插入图片描述

噪声递推模型实际并不是真的去递推噪声,而是为了递推预积分噪声协方差矩阵!我们用协方差的形式来记录噪声!

Σ i j {\Sigma}_{ij} Σij表示预积分噪声协方差矩阵C(9×9), Σ η {\Sigma}_{\boldsymbol{\eta}} Ση表示IMU测量噪声协方差Nga(6×6,只有陀螺仪和加速度计的高斯噪声,偏置游走用另外一个变量NgaWalk表示,就是把测量噪声和偏置噪声分开计算)

Σ i j = A j − 1 Σ i , j − 1 A j − 1 ⊺ + B j − 1 Σ η B j − 1 ⊺ \boldsymbol{\Sigma}_{ij}=\boldsymbol{A}_{j-1}\boldsymbol{\Sigma}_{i,j-1}\boldsymbol{A}_{j-1}^{\intercal}+\boldsymbol{B}_{j-1}\boldsymbol{\Sigma}_{\boldsymbol{\eta}}\boldsymbol{B}_{j-1}^{\intercal} Σij=Aj1Σi,j1Aj1+Bj1ΣηBj1

void Preintegrated::IntegrateNewMeasurement(const Eigen::Vector3f &acceleration, const Eigen::Vector3f &angVel, const float &dt){
    
	...

// Compute rotation parts of matrices A and B
// 补充AB矩阵
A.block<3, 3>(0, 0) = dRi.deltaR.transpose();
B.block<3, 3>(0, 0) = dRi.rightJ * dt;

// 小量delta初始为0,更新后通常也为0,故省略了小量的更新
// Step 3.更新协方差,frost经典预积分论文的第63个公式,推导了噪声(ηa, ηg)对dR dV dP 的影响
C.block<9, 9>(0, 0) = A * C.block<9, 9>(0, 0) * A.transpose() + B * Nga * B.transpose();  // B矩阵为9*6矩阵 Nga 6*6对角矩阵,3个陀螺仪噪声的平方,3个加速度计噪声的平方
// 这一部分最开始是0矩阵,随着积分次数增加,每次都加上随机游走,偏置的信息矩阵
C.block<6, 6>(9, 9) += NgaWalk;

    ...
        
}    

2.6 旋转预积分量对零偏的雅可比矩阵

旋转预积分量对零偏的雅可比矩阵

∂ Δ R ~ i j ∂ b g = ∑ k = i j − 1 ( − Δ R ~ k + 1 , j ⊤ J r k Δ t ) = ∑ k = i j − 2 ( − Δ R ~ k + 1 , j ⊤ J r k Δ t ) − Δ R ~ j j ⊤ j r j − 1 Δ t = ∑ k = i j − 2 ( − ( Δ R ~ k + 1 , j − 1 Δ R ~ j − 1 , j ) ⊤ J r k Δ t ) − Δ R ~ j j ⊤ J r j − 1 Δ t = Δ R ~ j , j − 1 ∑ k = i j − 2 ( − ( Δ R ~ k + 1 , j − 1 ) ⊤ J r k Δ t ) − J r j − 1 Δ t = Δ R ~ j , j − 1 ∂ Δ R ~ i , j − 1 ∂ b g − J r j − 1 Δ t \begin{aligned} \frac{\partial\Delta\tilde{\boldsymbol{R}}_{ij}}{\partial b^g}& =\sum_{k=i}^{j-1}\left(-\Delta\tilde{R}_{k+1,j}^{\top}J_{r}^{k}\Delta t\right) \\ &=\sum_{k=i}^{j-2}\left(-\Delta\tilde{\boldsymbol{R}}_{k+1,j}^{\top}\boldsymbol{J}_{r}^{k}\Delta t\right)-\Delta\tilde{\boldsymbol{R}}_{jj}^{\top}\boldsymbol{j}_{r}^{j-1}\Delta t \\ &\begin{aligned}=\sum_{k=i}^{j-2}\left(-\left(\Delta\tilde{\boldsymbol{R}}_{k+1,j-1}\Delta\tilde{\boldsymbol{R}}_{j-1,j}\right)^\top J_{r}^k\Delta t\right)-\Delta\tilde{\boldsymbol{R}}_{jj}^\top J_{r}^{j-1}\Delta t\end{aligned} \\ &=\Delta\tilde{\boldsymbol{R}}_{j,j-1}\sum_{k=i}^{j-2}\left(-\left(\Delta\tilde{\boldsymbol{R}}_{k+1,j-1}\right)^\top\boldsymbol{J}_r^k\Delta t\right)-\boldsymbol{J}_r^{j-1}\Delta t \\ &=\Delta\tilde{\boldsymbol{R}}_{j,j-1}\frac{\partial\Delta\tilde{\boldsymbol{R}}_{i,j-1}}{\partial\boldsymbol{b}^{g}}-\boldsymbol{J}_{r}^{j-1}\Delta t \end{aligned} bgΔR~ij=k=ij1(ΔR~k+1,jJrkΔt)=k=ij2(ΔR~k+1,jJrkΔt)ΔR~jjjrj1Δt=k=ij2((ΔR~k+1,j1ΔR~j1,j)JrkΔt)ΔR~jjJrj1Δt=ΔR~j,j1k=ij2((ΔR~k+1,j1)JrkΔt)Jrj1Δt=ΔR~j,j1bgΔR~i,j1Jrj1Δt



    // Update rotation jacobian wrt bias correction
    // 计算偏置的雅克比矩阵,r对bg的导数,∂ΔRij/∂bg = (ΔRjj-1) * ∂ΔRij-1/∂bg - Jr(j-1)*t
    // 论文作者对forster论文公式的基础上做了变形,然后递归更新,参见 https://github.com/UZ-SLAMLab/ORB_SLAM3/issues/212
    // ? 为什么先更新JPa、JPg、JVa、JVg最后更新JRg? 答:这里必须先更新dRi才能更新到这个值,但是为什么JPg和JVg依赖的上一个JRg值进行更新的?
    JRg = dRi.deltaR.transpose() * JRg - dRi.rightJ * dt;

    // Total integrated time
    // 更新总时间
    dT += dt;
}

3 预积分零偏更新

利用上面求得预积分测量对零偏的雅可比进行预积分测量更新

Δ R ~ ‾ i j ≐ Δ R ~ i j Exp ⁡ ( ∂ Δ R ~ i j ∂ b g δ b i g ) \begin{aligned} &\Delta\overline{\tilde{R}}_{ij} \doteq\Delta\tilde{\boldsymbol{R}}_{ij}\operatorname{Exp}\left(\frac{\partial\Delta\tilde{\boldsymbol{R}}_{ij}}{\partial\boldsymbol{b}^{g}}\delta\boldsymbol{b}_{i}^{g}\right) \\ \end{aligned} ΔR~ijΔR~ijExp(bgΔR~ijδbig)


/** 
 * @brief 根据新的偏置计算新的dR
 * @param b_ 新的偏置
 * @return dR
 */
Eigen::Matrix3f Preintegrated::GetDeltaRotation(const Bias &b_)
{
    std::unique_lock<std::mutex> lock(mMutex);
    // 计算偏置的变化量
    Eigen::Vector3f dbg;
    dbg << b_.bwx - b.bwx, b_.bwy - b.bwy, b_.bwz - b.bwz;
    // 考虑偏置后,dR对偏置线性化的近似求解,邱笑晨《预积分总结与公式推导》P13~P14
    // Forster论文公式(44)yP17也有结果(但没有推导),后面两个函数GetDeltaPosition和GetDeltaPosition也是基于此推导的
    return NormalizeRotation(dR * Sophus::SO3f::exp(JRg * dbg).matrix());
}

Δ v ~ ‾ i j ≐ Δ v ~ i j + ∂ Δ v ~ i j ∂ b g δ b i g + ∂ Δ v ~ i j ∂ b a δ b i a \Delta\overline{\tilde{v}}_{ij} \doteq\Delta\tilde{\boldsymbol{v}}_{ij}+\frac{\partial\Delta\tilde{\boldsymbol{v}}_{ij}}{\partial\boldsymbol{b}^{g}}\delta\boldsymbol{b}_{i}^{g}+\frac{\partial\Delta\tilde{\boldsymbol{v}}_{ij}}{\partial\boldsymbol{b}^{a}}\delta\boldsymbol{b}_{i}^{a} \\ Δv~ijΔv~ij+bgΔv~ijδbig+baΔv~ijδbia

/** 
 * @brief 根据新的偏置计算新的dV
 * @param b_ 新的偏置
 * @return dV
 */
Eigen::Vector3f Preintegrated::GetDeltaVelocity(const Bias &b_)
{
    std::unique_lock<std::mutex> lock(mMutex);
    Eigen::Vector3f dbg, dba;
    dbg << b_.bwx - b.bwx, b_.bwy - b.bwy, b_.bwz - b.bwz;
    dba << b_.bax - b.bax, b_.bay - b.bay, b_.baz - b.baz;
    // 考虑偏置后,dV对偏置线性化的近似求解,邱笑晨《预积分总结与公式推导》P13,JPg和JPa在预积分处理中更新 
    return dV + JVg * dbg + JVa * dba;
}

Δ p ~ ‾ i j = ˙ Δ p ~ i j + ∂ Δ p ~ i j ∂ b g δ b i g + ∂ Δ p ~ i j ∂ b a δ b i a \Delta\overline{\tilde{p}}_{ij} \dot{=}\Delta\tilde{\boldsymbol{p}}_{ij}+\frac{\partial\Delta\tilde{\boldsymbol{p}}_{ij}}{\partial\boldsymbol{b}^g}\delta\boldsymbol{b}_{i}^g+\frac{\partial\Delta\tilde{\boldsymbol{p}}_{ij}}{\partial\boldsymbol{b}^a}\delta\boldsymbol{b}_{i}^a Δp~ij=˙Δp~ij+bgΔp~ijδbig+baΔp~ijδbia

/** 
 * @brief 根据新的偏置计算新的dP
 * @param b_ 新的偏置
 * @return dP
 */
Eigen::Vector3f Preintegrated::GetDeltaPosition(const Bias &b_)
{
    std::unique_lock<std::mutex> lock(mMutex);
    Eigen::Vector3f dbg, dba;
    dbg << b_.bwx - b.bwx, b_.bwy - b.bwy, b_.bwz - b.bwz;
    dba << b_.bax - b.bax, b_.bay - b.bay, b_.baz - b.baz;
    // 考虑偏置后,dP对偏置线性化的近似求解,邱笑晨《预积分总结与公式推导》P13,JPg和JPa在预积分处理中更新
    return dP + JPg * dbg + JPa * dba;
}

4 预积分残差雅可比计算

这个在G2oTypes.h,有时间补充吧

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot整合系列】SpringBoot整合Shiro——权限控制

目录 安全框架?安全框架都有哪些&#xff1f; 什么是RBAC?ShiroShiro核心组件Shiro的运行机制 SpringBoot整合Shiro整合思路1.引入依赖2.项目结构及配置3.创建前端页面index.jsplogin.jsp 4.自定义Realm5.自定义配置类6.启动测试 认证和退出1.在index.jsp添加a标签2.Controll…

IIS服务器更换即将过期的SSL证书

公司IIS服务器证书快要过期&#xff0c;替换证书的步骤&#xff1a; Winr输入mstsc命令&#xff0c;显示远程登录&#xff1b;输入服务器IP以及密码&#xff0c;进行远程登陆登陆IIS服务器&#xff0c;winr输入inetmgr命令显示IIS操控器&#xff1b;选择服务器证书--点击服务器…

【数据结构】05树

树 树1.2 结点的分类1.3 结点间的关系1.4 树的其他概念1.5 树的性质 2. 二叉树2.1 满二叉树2.2 完全二叉树2.3 二叉排序树&#xff08;二叉查找树&#xff09; 3. 二叉树的存储结构3.1 二叉树顺序存储结构3.2 二叉树的链式存储结构 4. 二叉树的遍历4.1 层次遍历4.1 前序遍历4.2…

服务器代理

服务器代理 配置&#xff1a;64G内存1 3090&#xff08;24g&#xff09;1P4000&#xff08;8g&#xff09; SSH连接 工作路径&#xff1a;/home/ubuntu/workspace/python Anaconda路径&#xff1a;/home/Ubuntu 1.在工作路径下创建自己的文件夹作为workspace 2.以用户ubunbtu登…

Java技术学习|SpringBoot面试篇

学习材料声明 黑马程序员黑马程序员SpringBoot3Vue3全套视频教程&#xff0c;springbootvue企业级全栈开发从基础、实战到面试一套通关 经过了基础知识后端开发前端开发&#xff0c;终于到了面试篇。 前置知识 1.ApplicationContextInitializer 首先&#xff0c;SpringBoot…

(学习日记)2024.04.16:UCOSIII第四十四节:内存管理

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

【GD32】MQ-8氢气检测传感器

2.36 MQ-8氢气检测传感器 MQ-8气体传感器所使用的气敏材料是在清洁空气中电导率较低的二氧化锡(Sn0s)。当传感器所处环境中存在氢气时&#xff0c;传感器的电导率随空气中氢气浓度的增加而增大。使用简单的电路即可将电导率的变化转换为与该气体浓度相对应的输出信号。MQ-8气体…

数字乡村发展新模式:科技创新引领农业现代化与乡村振兴协同发展

随着信息技术的飞速发展&#xff0c;数字乡村已成为新时代农业现代化与乡村振兴协同发展的新模式。科技创新作为推动这一模式的核心动力&#xff0c;正引领着乡村产业结构的优化升级&#xff0c;促进农村经济的全面振兴&#xff0c;让农民在现代化的进程中共享发展成果。 一、科…

VUE_H5页面跳转第三方地图导航,兼容微信浏览器

当前项目是uniapp项目&#xff0c;若不是需要替换uni.showActionSheet选择api onMap(address , organName , longitude 0, latitude 0){var ua navigator.userAgent.toLowerCase();var isWeixin ua.indexOf(micromessenger) ! -1;if(isWeixin) {const mapUrl_tx "…

Python数据分析案例39——电商直播间评论可视化分析(LDA)

1. 引言 1.1 直播电商的发展背景 随着互联网技术的飞速发展&#xff0c;电商行业迎来了新的变革——直播电商。直播电商是一种结合了直播技术和电子商务的新型销售模式。在这种模式下&#xff0c;商家或主播通过实时视频直播的方式&#xff0c;展示产品并与消费者互动&#x…

ipad协议847最新版

iPad协议是一种模拟iPad端微信的人工操作&#xff0c;并与微信服务器进行通信的协议。该协议涉及到一些关键点&#xff0c;包括PB协议、mmtls、07加密算法、rqt算法、aes加密、rsa加密等。只要理解了这些关键点&#xff0c;就可以模拟官方微信的所有功能&#xff0c;并且还可以…

AndroidAutomotive模块介绍(二)应用及接口介绍

前言 上一篇文章中从整体角度描述了 Android Automotive 模块。本篇文章将对 Android Automotive 中的 APP 以及 API 部分展开描述。 上一篇&#xff1a;AndroidAutomotive模块介绍&#xff08;一&#xff09;整体介绍 下一篇&#xff1a;AndroidAutomotive模块介绍&#xff0…

自然语言处理NLP:文本预处理Text Pre-Processing

大家好&#xff0c;自然语言处理(NLP)是计算机科学领域与人工智能领域中的一个重要方向&#xff0c;其研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。本文将介绍文本预处理的本质、原理、应用等内容&#xff0c;助力自然语言处理和模型的生成使用。 1.文本…

SqlServer功能性配置选择

功能性配置 下面的是必选的

SpringBoot整合Nacos

文章目录 nacosnacos下载nacos启动nacos相关配置demo-dev.yamldemo-test.yamluser.yaml 代码pom.xmlUserConfigBeanAutoRefreshConfigExampleValueAnnotationExampleDemoApplicationbootstrap.yml测试结果补充.刷新静态配置 nacos nacos下载 下载地址 一键傻瓜试安装即可,官…

5.0 HDFS 集群

5.0 HDFS 集群 分类 编程 HDFS 集群是建立在 Hadoop 集群之上的&#xff0c;由于 HDFS 是 Hadoop 最主要的守护进程&#xff0c;所以 HDFS 集群的配置过程是 Hadoop 集群配置过程的代表。 使用 Docker 可以更加方便地、高效地构建出一个集群环境。 每台计算机中的配置 Hado…

【Python】读取时间判定操作次数问题和一些解决办法

几种类 datetime.striptime() 计算两个字符串之间的时间差 datetime.striptime()计算两个字符串之间的时间差 datatime类提供函数处理日期和时间 Striptime()分析字符串值以固定格式表示时间然后存储为函数参数 输出就是&#xff1a; time.sleep() time模块打印时间按照对…

动态规划-路径问题

文章目录 1. 不同路径&#xff08;62&#xff09;2. 不同路径 II&#xff08;63&#xff09;3. 珠宝的最高价值&#xff08;LCR 166&#xff09;4. 下降路径最小和&#xff08;931&#xff09;5. 最小路径和&#xff08;64&#xff09;6. 地下城游戏&#xff08;174&#xff09…

程序员Java.vue,python前端后端爬虫开发资源分享

bat面试资料 bat面试题汇总 提取码&#xff1a;724z 更多资料

【日常记录】【CSS】生成动态气泡小球

文章目录 1、分析2、实现 1、分析 核心有两点&#xff0c;通过这两个不一样就可以实现每个小球的颜色、动画时间不一致 给每个元素都设置一个css 变量 bgc 用于控制每一个小球的颜色给每个元素都设置一个css 变量 duration 用于控制每一个小球的时间 2、实现 <!DOCTYPE ht…