【SLAM】VINS-MONO解析——sliding window

2023-05-16

8.sliding window

8.1 理论基础

实际上,这一部分跟后端非线性优化是一起进行的,这一部分对应的非线性优化的损失函数的先验部分。理论基础部分的代码基本在第7章部分。
8.1.1 上一次非线性优化结束,最后的H矩阵就是本轮非线性优化的先验矩阵的前身。
8.1.2 构造先验矩阵
(1)移动需要marg掉的pose和路标点
对应的,J矩阵的一些列需要删除掉;H矩阵的一些行需要删掉。在操作先验矩阵的时候,需要把要marg掉的行和列移动到H矩阵的左上角,b向量相应的部分移到上方去,方便采用shur的方法marg掉,如下式所示:
在这里插入图片描述
mm对应的是要被marg掉的部分,rr是要留下来的部分。

(2)边缘化:构造先验矩阵
在这里插入图片描述
这个就是边缘化操作,边缘化之后,得到的先验矩阵H和先验向量b分别是:
在这里插入图片描述
滑窗会导致H矩阵不再稀疏。

8.1.3 构造非线性优化的H矩阵
这一部分实际上就是非线性优化部分关于构造H矩阵的内容。
(1)对先验矩阵进行扩维,扩充的维度就是下一次优化增加的状态量的维度
在这里插入图片描述
和直接 Bundle Adjustment 相比,多了一个先验矩阵的维护。

(2)与IMU和视觉部分的H矩阵进行叠加
实际上,每一轮优化的时候,H矩阵都是一块一块地增加的,所以先加上H矩阵,之后每添加一个残差项,总的H矩阵都会对应地自动增加。

8.1.4 进行非线性优化(FEJ)
这一部分实际上就是非线性优化部分关于LM/DOGLEG算法求解部分的内容。最后得到优化后的状态量。
这块涉及到FEJ问题。
先说结论,FEJ的意思就是说在总的大H矩阵中,先验矩阵对应的部分在本次优化的迭代过程中的值保持不变。

再说理由,
(1)当状态量1被merg掉之后,原本相互独立的量会变的不独立,表现在H矩阵中就是产生fill-in现象。
在这里插入图片描述

(2)当再加入新的观测时,如8.1.3-(1)粉色部分,H矩阵有的部分,既与先验有关,也与新加入的信息有关。

(3)假如说这部分H矩阵块不固定,每次迭代会得到新的线性化点,这个新的线性化点会与先验的线性化点不一样,可能会导致信息矩阵的零空 间发生变化,从而在求解时引入错误信息。
为什么?
因为信息矩阵 Λ 不满秩。对应的零空间为 N, 用高斯牛顿求解时有
在这里插入图片描述
增量 δx 在零空间维度下变化,并不会改变我们的残差。这意味着 系统可以有多个满足最小化损失函数的解 x。

(4)假如说不固定先验部分对应的线性化点,会使原本不可观的信息变得可观,多个解的问题变成了一个确定解。而这个是错误的。
在这里插入图片描述

(5)所以,采用FEJ,也就是first estimated jacobian。不同残差对同一个状态求雅克比时,线性化点必须一致。这样就能避免零空间退化而使得不可观变量变得可观。也就是说,在总的大H矩阵中,先验矩阵对应的部分在本次优化的迭代过程中的值保持不变。

(6)先验矩阵不变,但是先验残差得变!
虽然先验信息矩阵固定不变,但随着迭代的推进,变量被 不断优化,先验残差需要跟随变化。否则,求解系统可能奔溃。
方法:先验残差的变化可以使用一阶泰勒近似。
在这里插入图片描述

其它部分,就和非线性优化一样了。但是有一点需要注意,就是在g20中,传入的是Jacobian,对于IMU残差和重投影残差,Jacobian都是知道的,但是这个先验部分,我们知道的是H,所以就需要根据marg后的状态量反解出一个Jacobian。

8.1.5 返回步骤8.1.1,进行下一次的非线性优化。
在vins中,实际上它是8.1.4是循环的第一步。另外,崔神说vins并没有采用FEJ。

8.2 代码

slideWhindow()这个函数在初始化和非线性优化部分都出现过。对于marg的是old还是new,这是在5.2.1部分进行的。

8.2.1 if (marginalization_flag == MARGIN_OLD)
删除的是滑窗第一帧。
(1) 保存最老帧信息

double t_0 = Headers[0].stamp.toSec();
back_R0 = Rs[0];
back_P0 = Ps[0];

(2) 依次把滑窗内信息前移

if (frame_count == WINDOW_SIZE)
{
    for (int i = 0; i < WINDOW_SIZE; i++)
    {
        Rs[i].swap(Rs[i + 1]);
        std::swap(pre_integrations[i], pre_integrations[i + 1]);
        dt_buf[i].swap(dt_buf[i + 1]);
        linear_acceleration_buf[i].swap(linear_acceleration_buf[i + 1]);
        angular_velocity_buf[i].swap(angular_velocity_buf[i + 1]);
        Headers[i] = Headers[i + 1];
        Ps[i].swap(Ps[i + 1]);
        Vs[i].swap(Vs[i + 1]);
        Bas[i].swap(Bas[i + 1]);
        Bgs[i].swap(Bgs[i + 1]);
    }

(3) 把滑窗末尾(10帧)信息给最新一帧(11帧)

Headers[WINDOW_SIZE] = Headers[WINDOW_SIZE - 1];
Ps[WINDOW_SIZE] = Ps[WINDOW_SIZE - 1];
Vs[WINDOW_SIZE] = Vs[WINDOW_SIZE - 1];
Rs[WINDOW_SIZE] = Rs[WINDOW_SIZE - 1];
Bas[WINDOW_SIZE] = Bas[WINDOW_SIZE - 1];
Bgs[WINDOW_SIZE] = Bgs[WINDOW_SIZE - 1];


注意,在(2)中,已经实现了所有信息的前移,此时,最新一帧已经成为了滑窗中的第10帧,这里只是把原先的最新一帧的信息作为下一次最新一帧的初始值。

(4) 新实例化一个IMU预积分对象给下一个最新一帧

delete pre_integrations[WINDOW_SIZE];
pre_integrations[WINDOW_SIZE] = new IntegrationBase{acc_0, gyr_0, Bas[WINDOW_SIZE], Bgs[WINDOW_SIZE]};

(5) 清空第11帧的buf

dt_buf[WINDOW_SIZE].clear();
linear_acceleration_buf[WINDOW_SIZE].clear();
angular_velocity_buf[WINDOW_SIZE].clear();

(6)删除最老帧对应的全部信息

map<double, ImageFrame>::iterator it_0;
it_0 = all_image_frame.find(t_0);//6.找到滑窗内最老一帧信息
delete it_0->second.pre_integration;//删掉这一帧的预积分信息
it_0->second.pre_integration = nullptr;//置空这一帧的预积分信息
 
for(map<double, ImageFrame>::iterator it = all_image_frame.begin(); it!= it_0; ++it)
{//7.把滑窗内最老一帧以前的帧的预积分信息全删掉
    if (it->second.pre_integration)
        delete it->second.pre_integration;
    it->second.pre_integration = NULL;
}
//8.删掉滑窗内最老帧以前的所有帧(不包括最老帧),和最老帧
all_image_frame.erase(all_image_frame.begin(), it_0);
all_image_frame.erase(t_0);   
}


(7) slideWindowOld()

void Estimator::slideWindowOld()
{
    sum_of_back++;//统计一共有多少次merge滑窗第一帧的情况

    bool shift_depth = solver_flag == NON_LINEAR ? true : false;
    if (shift_depth)
    {
        Matrix3d R0, R1;
        Vector3d P0, P1;
        R0 = back_R0 * ric[0];//滑窗原先的最老帧(被merge掉)的旋转(c->w)
        R1 = Rs[0] * ric[0];//滑窗原先第二老的帧(现在是最老帧)的旋转(c->w)
        P0 = back_P0 + back_R0 * tic[0];//滑窗原先的最老帧(被merge掉)的平移(c->w)
        P1 = Ps[0] + Rs[0] * tic[0];//滑窗原先第二老的帧(现在是最老帧)的平移(c->w)
        f_manager.removeBackShiftDepth(R0, P0, R1, P1);//把首次在原先最老帧出现的特征点转移到原先第二老帧的相机坐标里(仅在slideWindowOld()出现过)
    }
    else
        f_manager.removeBack();//当最新一帧是关键帧时,用于merge滑窗内最老帧(仅在slideWindowOld()出现过)
}



8.2.2 if (marginalization_flag == MARGIN_NEW)
删除的是滑窗第10帧。

(1)取出最新一帧的信息

else
{
    if (frame_count == WINDOW_SIZE)
    {
        for (unsigned int i = 0; i < dt_buf[frame_count].size(); i++)
        {
            double tmp_dt = dt_buf[frame_count][i];
            Vector3d tmp_linear_acceleration = linear_acceleration_buf[frame_count][i];
            Vector3d tmp_angular_velocity = angular_velocity_buf[frame_count][i];

(2) 当前帧和前一帧之间的 IMU 预积分转换为当前帧和前二帧之间的 IMU 预积分

    pre_integrations[frame_count - 1]->push_back(tmp_dt, tmp_linear_acceleration, tmp_angular_velocity);
    dt_buf[frame_count - 1].push_back(tmp_dt);
    linear_acceleration_buf[frame_count - 1].push_back(tmp_linear_acceleration);
    angular_velocity_buf[frame_count - 1].push_back(tmp_angular_velocity);
}


(3) 用最新一帧的信息覆盖上一帧信息

Headers[frame_count - 1] = Headers[frame_count];
Ps[frame_count - 1] = Ps[frame_count];
Vs[frame_count - 1] = Vs[frame_count];
Rs[frame_count - 1] = Rs[frame_count];
Bas[frame_count - 1] = Bas[frame_count];
Bgs[frame_count - 1] = Bgs[frame_count];

(4) 因为已经把第11帧的信息覆盖了第10帧,所以现在把第11帧清除

delete pre_integrations[WINDOW_SIZE];
pre_integrations[WINDOW_SIZE] = new IntegrationBase{acc_0, gyr_0, Bas[WINDOW_SIZE], Bgs[WINDOW_SIZE]};

dt_buf[WINDOW_SIZE].clear();
linear_acceleration_buf[WINDOW_SIZE].clear();
angular_velocity_buf[WINDOW_SIZE].clear();

(5) 滑窗

        slideWindowNew();//为什么这里可以不对前一帧进行边缘化而是直接丢弃,原因就是当前帧和前一帧很相似。
    }//因此当前帧与地图点之间的约束和前一帧与地图点之间的约束是接近的,直接丢弃并不会造成整个约束关系丢失信息
}

再看看slideWindowNew()里面的具体内容。

void Estimator::slideWindowNew()
{//因为已经把第11帧的信息覆盖了第10帧,所以现在把第11帧清除
    sum_of_front++;//统计一共有多少次merge滑窗第10帧的情况
    f_manager.removeFront(frame_count);//唯一用法:当最新一帧(11)不是关键帧时,用于merge滑窗内最新帧(10)(仅在slideWindowNew()出现过)
}

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

【SLAM】VINS-MONO解析——sliding window 的相关文章

  • 在新选项卡或窗口中打开链接[重复]

    这个问题在这里已经有答案了 是否可以开一个a href链接在新选项卡而不是同一选项卡中 a href http your url here html Link a 您应该添加target blank and rel noopener nor
  • 任务返回类型出错 - “x 有错误的返回类型”

    我有一行代码 即 bool stop await Task
  • 扩展 Mono C# 编译器:有任何文档或先例吗?

    我目前正在参与一些有趣的编程语言研究 到目前为止 这些研究的重点是通过一些非常强大的基于程序员生产力的功能来扩展即将推出的 Java 7 0 编译器 这项工作应该同样适用于 C 等相关编程语言 我目前正在研究用于对该功能的 C 端口进行原型
  • umbraco 适用于单声道吗?

    我想跑Umbraco http umbraco org 在单声道上 这可能吗 目前 Umbraco 无法在 Mono 上正常运行 但人们已经在努力实现这一目标 This http kevinfitzgerald net articles u
  • 如何创建一个没有边框且只能通过手柄调整大小的 WPF 窗口?

    如果你设置ResizeMode CanResizeWithGrip 在 WPF 上Window然后右下角会出现一个调整大小的夹点 如下 如果你设置WindowStyle None 标题栏也会消失 但灰色斜边仍然保留 直到您设置ResizeM
  • 使用 mono/nunit-console/4 在 Mac OS X 控制台上运行测试

    我安装了 Max OS X 10 11 1 上面装有 Xamarin 我编写了简单的测试类 只是为了测试在 Mac OS X 和 Ubuntu 上运行 Nunit 测试 该类实际上有一个返回字符串的方法 using System names
  • WPF 模式进度窗口

    如果这个问题已经被回答了很多次 我很抱歉 但我似乎找不到适合我的答案 我想创建一个模式窗口 在我的应用程序执行长时间运行的任务时显示各种进度消息 这些任务在单独的线程上运行 我能够在过程的不同阶段更新进度窗口上的文本 跨线程通信一切正常 问
  • ExtJS打开窗口的最大高度

    我试图通过单击按钮 Ext Button 来打开一个窗口 Ext Window 问题是该窗口的尺寸必须为用户屏幕的 80 宽度和 100 高度 即它应该覆盖所有垂直空间 我真的无法创建一个工作示例 我使用的按钮是隐藏 显示这个窗口 它的大小
  • .NET 和 Mono 之间的开发差异

    我正在研究 Mono 和 NET C 将来当项目开发时我们需要在 Linux 服务器上运行代码 此时我一直在研究 ASP NET MVC 和 Mono 我运行 Ubuntu 发行版 想要开发 Web 应用程序 其他一些开发人员使用 Wind
  • C# 中的 Unix 套接字

    我正在尝试使用 Mono 的 UnixEndPoint 但在使用它之前就失败了 我在 64 位 Windows 7 系统上运行 Xamarind net 4 5 下面是一些代码 证明单一组合不起作用 foreach SocketType s
  • jQuery .slideRight 效果

    我需要一个 div 标签在屏幕右侧滑出 如何使用 jQuery 获得这种效果 我一直在这里寻找 http api jquery com category effects sliding http api jquery com categor
  • 重新创建窗口而不破坏上下文

    这个问题是关于使用 OpenGL 的图形应用程序 当时我正在使用 GLFW 框架 但我考虑更改它 我的目标是让用户 尽可能 在全屏模式和窗口模式之间不断切换 此过程应该花费不到一秒的时间 并且可以在运行时发生 例如 看看游戏 我的世界 用户
  • 可移植 C# 的最佳实践 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我希望为 linux windows mac 任何其他平台编写一些 C 代码 并且正在寻找可移植代码的最佳实践 Project mono htt
  • Mono-LibreOffice System.TypeLoadException

    过去 我编写了一个 C 库来与 OpenOffice 一起使用 并且在 Windows 中比在带有 Mono 的 Ubuntu 下运行得更好 该库的部分内容已发布here https stackoverflow com questions
  • C# 代码在 IIS 上运行速度快,但在 Mono 上运行速度慢 - 如何改进?

    我有一个 ASP NET 应用程序 它在我的 Windows 开发计算机上运行良好 不过 服务器是运行 Mono 的 Linux 一旦上传 相同的代码在 Windows 上的运行速度会比在 Windows 机器上慢 4 到 5 倍 例如 一
  • 在 Mono 上使用 Mono for android

    将 MonoDevelop 的编译器切换为 Mono 工具而不是 NET 看起来非常容易 您只需在 IDE 的设置下选择不同的框架即可 然而 在切换到 Mono 并使用 Mono 工具编译项目后 Mono for android 似乎不再是
  • 如何确定命名空间位于哪个程序集中?

    The MSDN documentation doesn t generally specify the assembly a namespace is in so there s no easy way to add the necess
  • 是否可以通知 Mac OS X 上的 DTrace 动态生成的代码?

    我们想扩展 Mono 的 VM 来生成可以被使用的信息DTrace http en wikipedia org wiki DTrace和仪器 我正在考虑对 Mono 运行时进行更改 以使其注册或通知它已动态生成的代码 以便 DTrace 可
  • 使用 mono 在命令行上创建 .Net 解决方案

    我运行 Linux 并安装了 Mono 但没有安装 MonoDevelop 我想从命令行创建解决方案和 csproj 文件 我该怎么做呢 类似的问题已被问到 https stackoverflow com questions 6454212
  • 有没有办法用 Tkinter 创建透明窗口?

    最终 我尝试使用 Tkinter 模块用 Python 创建 奇怪形状的窗口 但现在我会满足于能够使背景透明 同时保持子部件完全可见 我知道这是使用 wxPython 和其他一些模块完成的 但我想了解 Tkinter 的限制 Tkinter

随机推荐

  • Docker 镜像 Tag 管理

    Author xff1a rab 良好的镜像版本命名习惯能让我们更好的管理和使用镜像 xff08 如项目上线失败后可有效的进行版本回退等 xff09 xff0c 以下是 Docker 社区常用的 tag 方案 比如我现在已经构建了一个 co
  • APM与Pixhawk间的关系

    1 APM 本文APM指代 xff1a https github com ArduPilot ardupilot 2 Pixhawk 本文Pixhawk指代 xff1a https github com PX4 Firmware 3 关系
  • Pixhawk串口名称与硬件接口对应关系

    Pixhawk提供的串口较多 xff0c 通过ls dev 可以看到有如下7个tty设备 xff1a ttyACM0 ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 ttyS5 ttyS6 但每个串口名称对应到Pixhawk硬件
  • Linux系统大小端判断

    大端模式 大端模式 xff0c 是指数据的低位保存在内存的高地址中 xff0c 而数据的高位保存在内存的低地址中 小端模式 小端模式 xff0c 是指数据的低位保存在内存的低地址中 xff0c 而数据的高位保存在内存的高地址中 判断程序 文
  • C preprocessor fails sanity check

    编译某一产品固件时 xff0c 遇到如下现象 xff1a checking how to run the C preprocessor opt mipsel 24kec linux uclibc bin mipsel 24kec linux
  • VLC同时开启播放多个视频流BAT脚本

    工作中 xff0c 难免会遇到要用同一个程序连续打开多个URL资源 路径的情况 xff0c 一个窗口一个窗口的启动效率太低 这里以VLC同时播放多个码流图像为例 xff0c 写个简单的BAT脚本 xff0c 供需要者参考 PS 1 使用方式
  • 【AI】Ubuntu14.04安装OpenCV3.2.0

    在ubuntu14 04系统上安装OpenCV3 2 0 环境要求 GCC 4 4 x or later CMake 2 8 7 or higher Git if failed you can replace it with git cor
  • 若依代码生成器(mybatis-plus)

    看这篇文章之前 xff0c 先去看一下我前面的文章 xff1a 若依前后端分离整合mybatis plus wjdsg的博客 CSDN博客 用过若依都知道 xff0c 若依自带的代码生成器 xff0c 是下载下来 xff0c 然后自己粘贴到
  • 【AI】基于OpenCV开发自定义程序编译方法

    基于OpenCV开发自定义程序编译方法 OpenCV自带的程序 xff0c 编译均采用cmake统一编译 若我们要基于OpenCV开发自己的程序 xff0c 如何快速编译 xff1f 本文以OpenCV库自带的facedetect cpp程
  • H3C SNMPv3 配置

    1 xff09 H3C SNMPv3 配置 snmp agent mib view included MIB 2 mib 2 noAuthNoPriv xff1a snmp agent group v3 mygroup read view
  • 【SLAM】VINS-MONO解析——综述

    目前网上有很多分析文章 xff0c 但是都只是一些比较基础的原理分析 xff0c 而且很多量 xff0c 虽然有推倒 xff0c 但是往往没有讲清楚这些量是什么 xff0c 为什么要有这些量 xff0c 这些量是从哪来的 xff0c 也没有
  • 【SLAM】VINS-MONO解析——前端

    各个部分的讲解如下链接 xff1a SLAM VINS MONO解析 综述 SLAM VINS MONO解析 feature tracker SLAM VINS MONO解析 IMU预积分 SLAM VINS MONO解析 vins est
  • 【SLAM】VINS-MONO解析——IMU预积分

    4 IMU预积分 IMU预积分主要干了2件事 xff0c 第一个是IMU预积分获得 值 xff0c 另一个是误差传递函数的获取 本部分的流程图如下图所示 各个部分的讲解如下链接 xff1a SLAM VINS MONO解析 综述 SLAM
  • 【SLAM】VINS-MONO解析——vins_estimator流程

    5 vins estimator 基本上VINS里面绝大部分功能都在这个package下面 xff0c 包括IMU数据的处理 前端 xff0c 初始化 我觉得可能属于是前端 xff0c 滑动窗口 后端 xff0c 非线性优化 后端 xff0
  • 【SLAM】VINS-MONO解析——初始化(理论部分)

    6 初始化 第一个问题 xff0c 为什么要初始化 xff1f 对于单目系统而言 xff0c 1 视觉系统只能获得二维信息 xff0c 损失了一维信息 深度 所以需要动一下 xff0c 也就是三角化才能重新获得损失的深度信息 xff1b 2
  • 【SLAM】VINS-MONO解析——初始化(代码部分)

    6 2 代码解析 这部分代码在estimator processImage 最后面 初始化部分的代码虽然生命周期比较短 xff0c 但是 xff0c 代码量巨大 xff01 主要分成2部分 xff0c 第一部分是纯视觉SfM优化滑窗内的位姿
  • 【SLAM】VINS-MONO解析——后端优化(理论部分)

    7 后端非线性优化 7 1 理论基础 7 1 1 bayes模型 xff0c 因子图和最小二乘 这一部分主要是对董靖博士在公开课 因子图的理论基础 上的回忆和总结 1 bayes模型 假设有黄色是机器人在不同时刻的位姿 xff0c 蓝色是机
  • 【SLAM】VINS-MONO解析——后端优化(代码部分)

    7 2 代码 在estimator cpp的processImage 的最后 xff0c 代码如下 xff1a span class token keyword else span span class token comment solv
  • 51单片机通过两个按键控制流水灯方向

    按键一接单片机P3 1 xff0c 按键2接P3 0 8个流水灯接P2口 以下是代码 xff1a include lt regx52 H gt include lt INTRINS H gt 延时函数 xff0c xms等于1 xff0c
  • 【SLAM】VINS-MONO解析——sliding window

    8 sliding window 8 1 理论基础 实际上 xff0c 这一部分跟后端非线性优化是一起进行的 xff0c 这一部分对应的非线性优化的损失函数的先验部分 理论基础部分的代码基本在第7章部分 8 1 1 上一次非线性优化结束 x