【SLAM】VINS-MONO解析——初始化(理论部分)

2023-05-16

6.初始化

第一个问题,为什么要初始化?
对于单目系统而言,
(1)视觉系统只能获得二维信息,损失了一维信息(深度),所以需要动一下,也就是三角化才能重新获得损失的深度信息;
(2)但是,这个三角化恢复的深度信息,是个“伪深度”,它的尺度是随机的,不是真实的,所以就需要IMU来标定这个尺度;
(3)要想让IMU标定这个尺度,IMU也需要动一下,得到PVQ的P;
(4)另外,IMU存在bias,视觉获得的旋转矩阵不存在bias,所以可以用视觉来标定IMU的旋转bias;
(5)需要获得世界坐标系这个先验信息,通过初始化能借助g来确定;

对于双目系统而言,
初始化的难度会低一些,因为双目可以一下确定深度,只需要通过g的方向(先验)来确定世界坐标系。

注意,这个初始化只进行一次就够了,或者是在系统重启时执行一次,大部分时候,系统都处于NON_LINEAR的状态。因为,初始化的时候,就能确定尺度scaler和bias初始值,scaler确定后,在初始化获得的这些路标点都是准的了,后续通过PnP或者BA得到的特征点都是真实尺度的了。而bias初始值确定以后,在后续的非线性优化过程中,会实时更新。

6.1 基础原理

初始化的逻辑图如下:
在这里插入图片描述

6.1.1 如果旋转外参数 qbc 未知, 则先估计旋转外参数
实际上讲,这部分并不是vins代码中初始化的内容,而是初始化之前就需要完成的判断和操作,见5.2-4。根据IMU和视觉部分的旋转关系,可以得到下面的关系式:
在这里插入图片描述 在这里插入图片描述在这里插入图片描述将多个帧之间的等式关系一起构建超定方程Ax=0。对A进行svd分解,其中最小奇异值对应的奇异向量便为需要求解的qbc。
虽然这里IMU的旋转部分并没有标定,得到的外参数可能不太准。但是问题不大,因为初始化所占用的总运行时间不长,而更长生命周期的后端会持续的优化这部分的值。

6.1.2 利用SfM确定各个pose和特征点的相对于c0帧的位置关系
这一部分和基于图像的三维重建比较像,可以用三角化和PnP把这一串的ck帧的位姿和特征点位置确定下来(特征点是伪深度),在加上外参数qbc和pbc,一系列bk帧的位姿也确定下来。注意,这里把c0帧作为基础帧,实际上,c0帧旋转一下使gc0和gw方向一致时获得的坐标系就是vins的世界坐标系,也就是先验。在vins代码中,这一部分篇幅很长,但是这一部分也是很重要的部分。
在这里插入图片描述
首先我们先推导论文式(14),所有帧的位姿(Rc0ck,qc0ck)表示相对于第一帧相机坐标系(·)c0。相机到IMU的外参为(Rbc,qbc),得到姿态从相机坐标系转换到IMU坐标系的关系。
在这里插入图片描述
将T展开有成R与p有:
在这里插入图片描述
左侧矩阵的两项写开:
在这里插入图片描述
在这里插入图片描述

6.1.3 利用相机旋转约束标定IMU角速度bias
求解的目标函数如下公式所示:

在这里插入图片描述
在SfM完成且外参数标定完之后,头两个值是已知的了,而且我们假设头两个值是准的。理想状态下,这三个数乘积应该是单位四元数,很可惜,第三个值是IMU预积分得到的,而预积分里面是有bias的。所以,通过最小化这个目标函数的,可以把旋转bias标定出来!
在IMU预积分部分,也就是4.1.1最后的那个公式,有:
在这里插入图片描述
带入到损失函数里,可以得到:
在这里插入图片描述
或者是:
在这里插入图片描述
带入bias的残差后,得到,
在这里插入图片描述
实部没有需要标定的量,所以只用考虑虚部,也就是:
在这里插入图片描述
两侧再乘以 ,可以构造出Ax=B的形式,在采用LDLT分解,就可以求出状态量:
在这里插入图片描述
其实这里不像那种用高斯牛顿法迭求解,而更像是用直接法,也就是矩阵运算的方式来求待优化的状态量,6.1.4也是一样的思路。代具体代码见:initial_aligment.cpp 函数 solveGyroscopeBias()。

接下来是代码解析,
(1)参数的传入和容器的定义

void solveGyroscopeBias(map<double, ImageFrame> &all_image_frame, Vector3d* Bgs)
{
    Matrix3d A;
    Vector3d b;
    Vector3d delta_bg;
    A.setZero();
    b.setZero();
    map<double, ImageFrame>::iterator frame_i;
    map<double, ImageFrame>::iterator frame_j;
    

上式中,A和b对应的是Ax=b。注意,传入的参数是all_image_frame,不仅仅是滑窗内的帧。frame_i和frame_j分别读取all_image_frame中的相邻两帧。

(2)套本小节的最后一个公式,构造Ax=b等式

    for (frame_i = all_image_frame.begin(); next(frame_i) != all_image_frame.end(); frame_i++)
    {
        frame_j = next(frame_i);
        MatrixXd tmp_A(3, 3);
        tmp_A.setZero();
        VectorXd tmp_b(3);
        tmp_b.setZero();
        Eigen::Quaterniond q_ij(frame_i->second.R.transpose() * frame_j->second.R);
        tmp_A = frame_j->second.pre_integration->jacobian.template block<3, 3>(O_R, O_BG);
        tmp_b = 2 * (frame_j->second.pre_integration->delta_q.inverse() * q_ij).vec();
        A += tmp_A.transpose() * tmp_A;
        b += tmp_A.transpose() * tmp_b;
    }


注意到本小节的第一个公式了吗,那里有求和,所以需要遍历all_image_frame,然后叠加A和b。

(3)ldlt分解

    delta_bg = A.ldlt().solve(b);

(4)给滑窗内的IMU预积分加入角速度bias

    for (int i = 0; i <= WINDOW_SIZE; i++)
        Bgs[i] += delta_bg;

(5)重新计算所有帧的IMU积分(重要!)

    for (frame_i = all_image_frame.begin(); next(frame_i) != all_image_frame.end( ); frame_i++)
    {
        frame_j = next(frame_i);
        frame_j->second.pre_integration->repropagate(Vector3d::Zero(), Bgs[0]);
    }
}

repropagate()部分内容见4.3.2.。

6.1.4 利用IMU的平移估计重力/各bk帧速度/尺度scaler
首先要明确需要优化的状态量是什么,是各帧在bk坐标系下的速度,c0帧下的g和SfM的尺度scaler:
在这里插入图片描述
这块有个遗留问题,就是为什么要优化速度呢?
在IMU预积分部分,已经有如下的公式:
在这里插入图片描述
但是w坐标系我们不知道,只知道c0坐标系,所以需要把上面的公式转到c0坐标系上:
在这里插入图片描述
上式中,等号左边减去等号右边就是残差,理想状态下,这个残差是0,那么带入上式得:
在这里插入图片描述
把这个 XX = 0的等式也转为 A x = b这种线性方程组的形式,如下式:
在这里插入图片描述
或者矩阵的形式:
在这里插入图片描述
对于beta而言,也是类似的,

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
那么,把这两个矩阵合体,就能得到论文中的等式:
在这里插入图片描述
同样采用LDLT分解,就能求出状态量:
在这里插入图片描述
接下来是代码解析,

(1)参数的传入和容器的定义

bool LinearAlignment(map<double, ImageFrame> &all_image_frame, Vector3d &g, VectorXd &x)
{
    int all_frame_count = all_image_frame.size();
    int n_state = all_frame_count * 3 + 3 + 1; //需要优化的状态量的个数

    MatrixXd A{n_state, n_state};
    A.setZero();
    VectorXd b{n_state};
b.setZero();

    map<double, ImageFrame>::iterator frame_i;
    map<double, ImageFrame>::iterator frame_j;


上式中,A和b对应的是Ax=b。注意,传入的参数是all_image_frame,不仅仅是滑窗内的帧。
frame_i和frame_j分别读取all_image_frame中的相邻两帧。

(2)套本小节的最后一个公式,构造Ax=b等式

    int i = 0;
    for (frame_i = all_image_frame.begin(); next(frame_i) != all_image_frame.end(); frame_i++, i++)
    {
        frame_j = next(frame_i);

        MatrixXd tmp_A(6, 10);
        tmp_A.setZero();
        VectorXd tmp_b(6);
        tmp_b.setZero();

        double dt = frame_j->second.pre_integration->sum_dt;

        tmp_A.block<3, 3>(0, 0) = -dt * Matrix3d::Identity();
        tmp_A.block<3, 3>(0, 6) = frame_i->second.R.transpose() * dt * dt / 2 * Matrix3d::Identity();
        tmp_A.block<3, 1>(0, 9) = frame_i->second.R.transpose() * (frame_j->second.T - frame_i->second.T) / 100.0;    //这里除以100,会导致x偏大100 
        tmp_b.block<3, 1>(0, 0) = frame_j->second.pre_integration->delta_p + frame_i->second.R.transpose() * frame_j->second.R * TIC[0] - TIC[0];
        tmp_A.block<3, 3>(3, 0) = -Matrix3d::Identity();
        tmp_A.block<3, 3>(3, 3) = frame_i->second.R.transpose() * frame_j->second.R;
        tmp_A.block<3, 3>(3, 6) = frame_i->second.R.transpose() * dt * Matrix3d::Identity();
        tmp_b.block<3, 1>(3, 0) = frame_j->second.pre_integration->delta_v;

        Matrix<double, 6, 6> cov_inv = Matrix<double, 6, 6>::Zero();
        cov_inv.setIdentity();

        MatrixXd r_A = tmp_A.transpose() * cov_inv * tmp_A;
        VectorXd r_b = tmp_A.transpose() * cov_inv * tmp_b;

        A.block<6, 6>(i * 3, i * 3) += r_A.topLeftCorner<6, 6>();
        b.segment<6>(i * 3) += r_b.head<6>();

        A.bottomRightCorner<4, 4>() += r_A.bottomRightCorner<4, 4>();
        b.tail<4>() += r_b.tail<4>();

        A.block<6, 4>(i * 3, n_state - 4) += r_A.topRightCorner<6, 4>();
        A.block<4, 6>(n_state - 4, i * 3) += r_A.bottomLeftCorner<4, 6>();
    }


另外需要注意的地方是,**虽然公式中只计算了相邻2帧,但是代码中,它把所有帧都放进去了,因此,A矩阵和b向量是远大于公式中的尺寸,而且在代码中有一个叠加的操作!非线性优化里构造H矩阵和J矩阵也是一样的。**这里是我看代码前比较疑惑的地方。

(3)ldlt分解,得到尺度和g的初始值,并用先验判断

x = A.ldlt().solve(b);

    double s = x(n_state - 1) / 100.0; //把x偏大的100矫正回来
    g = x.segment<3>(n_state - 4);
    
    if(fabs(g.norm() - G.norm()) > 1.0 || s < 0)
    {//如果重力加速度与参考值差太大或者尺度为负则说明计算错误
        return false;
    }


(4) 利用gw的模长已知这个先验条件进一步优化gc0

    RefineGravity(all_image_frame, g, x);
    s = (x.tail<1>())(0) / 100.0;
    (x.tail<1>())(0) = s;
    ROS_DEBUG_STREAM(" refine     " << g.norm() << " " << g.transpose());
    if(s < 0.0 )
        return false;   
    else
        return true;
}

见下一节。虽说是优化gc0,实际上都优化了。

6.1.5 利用gw的模长已知这个先验条件进一步优化gc0
但是,这里有一个bug,就是把g当成3自由度的向量优化,但是实际上g只有2自由度,因为它的模长是已知的。所以,在这里,需要想一个办法,就是怎么样用一个2自由度的表达式来表示3维的向量呢
在这里插入图片描述
在这里插入图片描述
在这里,采用球面坐标进行参数化,也就是用g的模长作为半径画一个半球,上图蓝色线对应的是gc0的测量值的方向(也就是优化前的方向),在这个交点上找到一个切平面,用gc0,b1,b2构造一个坐标系,那么在轴b1和b2上坐标值w1和w2就是我们需要求的量。求出来之后,把等号右边加在一起,就是优化后的gc0值。
注意,b1的方向是由gc0的测量值的方向与[1,0,0]作叉乘得到的,b2的方向是由gc0的测量值的方向与b1作叉乘得到的。

这样,6.1.4公式得到了更新,此时带优化量减少了1维:
在这里插入图片描述
即 ,同样使用LDLT分解:
在这里插入图片描述
其实,在这里,我们可以发现这一部分做的工作和6.1.4是相似的,但是却是在6.1.4的基础上进一步做的工作。

接下来是代码解析,
(1)参数的传入和容器的定义

void RefineGravity(map<double, ImageFrame> &all_image_frame, Vector3d &g, VectorXd &x)
{
    Vector3d g0 = g.normalized() * G.norm();
    Vector3d lx, ly;
    //VectorXd x;
    int all_frame_count = all_image_frame.size();
    int n_state = all_frame_count * 3 + 2 + 1;

    MatrixXd A{n_state, n_state};
    A.setZero();
    VectorXd b{n_state};
    b.setZero();

    map<double, ImageFrame>::iterator frame_i;
    map<double, ImageFrame>::iterator frame_j;


上式中,A和b对应的是Ax=b。注意,传入的参数是all_image_frame,不仅仅是滑窗内的帧。
frame_i和frame_j分别读取all_image_frame中的相邻两帧。

(2)一共迭代四次求解,并构建且向空间

    for(int k = 0; k < 4; k++)
    {
        MatrixXd lxly(3, 2);
        lxly = TangentBasis(g0);
        ....(3)
    }  

切向空间的构建如下代码所示:

MatrixXd TangentBasis(Vector3d &g0)
{
    Vector3d b, c;
    Vector3d a = g0.normalized();
    Vector3d tmp(0, 0, 1);
    if(a == tmp)
        tmp << 1, 0, 0;
    b = (tmp - a * (a.transpose() * tmp)).normalized();
    c = a.cross(b);
    MatrixXd bc(3, 2);
    bc.block<3, 1>(0, 0) = b;
    bc.block<3, 1>(0, 1) = c;
    return bc;
}


(3)套本小节的最后一个公式,构造Ax=b等式

int i = 0;
        for (frame_i = all_image_frame.begin(); next(frame_i) != all_image_frame.end(); frame_i++, i++)
        {
            frame_j = next(frame_i);

            MatrixXd tmp_A(6, 9);
            tmp_A.setZero();
            VectorXd tmp_b(6);
            tmp_b.setZero();

            double dt = frame_j->second.pre_integration->sum_dt;

            tmp_A.block<3, 3>(0, 0) = -dt * Matrix3d::Identity();
            tmp_A.block<3, 2>(0, 6) = frame_i->second.R.transpose() * dt * dt / 2 * Matrix3d::Identity() * lxly;
            tmp_A.block<3, 1>(0, 8) = frame_i->second.R.transpose() * (frame_j->second.T - frame_i->second.T) / 100.0;     
            tmp_b.block<3, 1>(0, 0) = frame_j->second.pre_integration->delta_p + frame_i->second.R.transpose() * frame_j->second.R * TIC[0] - TIC[0] - frame_i->second.R.transpose() * dt * dt / 2 * g0;

            tmp_A.block<3, 3>(3, 0) = -Matrix3d::Identity();
            tmp_A.block<3, 3>(3, 3) = frame_i->second.R.transpose() * frame_j->second.R;
            tmp_A.block<3, 2>(3, 6) = frame_i->second.R.transpose() * dt * Matrix3d::Identity() * lxly;
            tmp_b.block<3, 1>(3, 0) = frame_j->second.pre_integration->delta_v - frame_i->second.R.transpose() * dt * Matrix3d::Identity() * g0;

            Matrix<double, 6, 6> cov_inv = Matrix<double, 6, 6>::Zero();
            //cov.block<6, 6>(0, 0) = IMU_cov[i + 1];
            //MatrixXd cov_inv = cov.inverse();
            cov_inv.setIdentity();

            MatrixXd r_A = tmp_A.transpose() * cov_inv * tmp_A;
            VectorXd r_b = tmp_A.transpose() * cov_inv * tmp_b;

            A.block<6, 6>(i * 3, i * 3) += r_A.topLeftCorner<6, 6>();
            b.segment<6>(i * 3) += r_b.head<6>();

            A.bottomRightCorner<3, 3>() += r_A.bottomRightCorner<3, 3>();
            b.tail<3>() += r_b.tail<3>();

            A.block<6, 3>(i * 3, n_state - 3) += r_A.topRightCorner<6, 3>();
            A.block<3, 6>(n_state - 3, i * 3) += r_A.bottomLeftCorner<3, 6>();
        }


(4)ldlt分解,得到优化后的状态量x

            A = A * 1000.0;
            b = b * 1000.0;
            x = A.ldlt().solve(b);
            VectorXd dg = x.segment<2>(n_state - 3);
            g0 = (g0 + lxly * dg).normalized() * G.norm();
            //double s = x(n_state - 1);
    }   
    g = g0;
}

6.1.6 利用gc0和gw确定世界坐标系
(1) 找到 c0 到 w 系的旋转矩阵 Rwc0 = exp([θu])
在这里插入图片描述
gc0已经求出来了,而gw一直就是一个已知的量,因此它们之间的夹角θ是能很快求出来的;
所以我们然后可以用gc0和gw作叉乘得到一个旋转轴u;
最后把c0坐标系,绕着转轴旋转一个θ,就能找到c0 到 w 系的对齐关系,也就是Rwc0 = exp([θu])。

(2) 把所有 c0 坐标系下的变量旋转到 w系下
所有量都乘上Rwc0就可以了。我们定义的c0 与 w 系的原点坐标是重合的。

(3) 把相机平移和特征点尺度恢复到米制单位
初始化大功告成!

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

【SLAM】VINS-MONO解析——初始化(理论部分) 的相关文章

  • Dockerfile使用教程

    第一 创建一个spring boot项目 第二 创建 xff1a Dockerfile文件 xff08 在项目根目录下 xff09 第三 复制粘贴 FROM java 8 设置基础镜像 FROM openjdk 8 jdk alpine 指
  • C++ 用socket封装成http

    HttpSocket h interface for the CHttpSocket class if defined AFX HTTPSOCKET H F49A8F82 A933 41A8 AF47 68FBCAC4ADA6 INCLUD
  • echarts更换主题

    前言 本篇文章基于上一篇文章 xff1a vue工程整合echarts xff0c 因此这里主要讲的是主题是如何配置的 xff0c 其他代码在这里不再赘述 官网中已经说明了echarts除了有默认的主题外 xff0c 并且内置了dark主题
  • Java final修饰符详解

    final 在 Java 中的意思是最终 xff0c 也可以称为完结器 xff0c 表示对象是最终形态的 xff0c 不可改变的意思 final 应用于类 方法和变量时意义是不同的 xff0c 但本质是一样的 xff0c 都表示不可改变 x
  • Python Requests库安装和使用

    Python 提供了多个用来编写爬虫程序的库 xff0c 除了前面已经介绍的 urllib 库之外 xff0c 还有一个很重的 Requests 库 xff0c 这个库的宗旨是 让 HTTP 服务于人类 Requests 是 Python
  • C语言 十进制转十六进制

    问题描述 十六进制数是在程序设计时经常要使用到的一种整数的表示方式 它有0 1 2 3 4 5 6 7 8 9 A B C D E F共16个符号 xff0c 分别表示十进制数的0至15 十六进制的计数方法是满16进1 xff0c 所以十进
  • Pandas知识点超全总结

    Pandas知识点超全总结 一 数据结构1 Series1 创建2 切片 修改3 其他属性 2 DataFrame1 创建2 切片3 增加 修改4 删除5 查看 二 读写数据1 读数据1 excel文件2 csv文件3 sql文件 2 写数
  • socket通信小结

    1 网络中的进程之间如何进行通信 区别于本地的进程间通信 xff0c 我们首要解决的问题是如何唯一标识一个进程 xff0c 否则通信无从谈起 xff01 在本地可以通过进程PID来唯一标识一个进程 xff0c 但是在网络中这是行不通的 其实
  • eclipse alt+/代码智能提示总是报错:problems during content assist

    解决办法如下图 xff1a 依次点击红框标记的地方即可解决问题
  • linux C 遍历目录及其子目录 opendir -> readdir -> closedir

    在 linux 下遍历某一目录下内容 LINUX 下历遍目录的方法一般是这样的 xff1a 打开目录 gt 读取 gt 关闭目录 相关函数是 opendir gt readdir gt closedir xff0c 其原型如下 xff1a
  • 最全面的 linux 信号量解析

    一 xff0e 什么是信号量 信号量的使用主要是用来保护共享资源 xff0c 使得资源在一个时刻只有一个进程 xff08 线程 xff09 所拥有 信号量的值为正的时候 xff0c 说明它空闲 所测试的线程可以锁定而使用它 若为 0 xff
  • vue3学习一:let和const

    在函数的内部 xff0c 定义name变量 xff0c 当i等于false时 xff0c 按照Java语言 xff0c else里是拿不到name的 xff0c 并且会显示报错 xff0c 但是却不会报错 xff0c 这是因为javascr
  • PHP 中最全的设计模式(23种)

    PhpDesignPatterns PHP 中的设计模式 一 Introduction 介绍 设计模式 xff1a 提供了一种广泛的可重用的方式来解决我们日常编程中常常遇见的问题 设计模式并不一定就是一个类库或者第三方框架 xff0c 它们
  • 异常详细信息: System.NullReferenceException: 未将对象引用设置到对象的实例。

    我遇到的出现这种错误的原因一般是以下几种情况 xff1a 1 在绑定数据控件的时候 xff0c 建立数据库连接 OleDbConnection conn 61 new OleDbConnection 34 provider 61 micro
  • 连接不上Github,网络超时的检查和解决办法

    先附上图片吧 连接不上github但是其它网站都是正常上网 解决办法 win 43 r打开运行输入cmd 再命令行里输入 ping github com 看看返回值 我的全是请求超时 xff0c 发送的数据包全丢 xff08 我先ping了
  • 2018校招笔试真题汇总

    2018校招笔试真题汇总 最近看好多牛油贡献了很多考试的真题 xff0c 我把他们汇总在一起给到大家 xff0c 也感谢这些牛油的贡献 xff0c 只要进这个汇总贴的 xff0c 你们都将每人获得一份牛客送出的礼物一份 科大讯飞 xff1a
  • 【2】Docker的启动与停止

    1 xff09 启动 docker systemctl start docker 2 xff09 查看 docker 状态 systemctl status docker 3 xff09 查看 docker 概要信息 docker info
  • 【8】Docker中部署Redis

    1 xff09 拉取镜像 docker pull redis 这是我在 VMware 的 CentOS 中装过的 redis 版本 xff0c 拉取该指定版本使用 docker pull redis 5 0 12 命令 xff0c 不过下面
  • 操作系统学习之系统调用

    目录 一 操作系统学习之系统调用 1 什么是系统调用 2 系统调用有什么用 3 为什么需要系统调用 4 系统调用的具体流程 1 xff09 执行过程 2 如何实现用户态与内态之间的切换 3 系统调用常见名词 4 系统调用如何返回 传递返回值
  • 22-Docker-常用命令详解-docker pull

    常用命令详解 docker pull 前言docker pull语法格式options说明 使用示例未指定tag a 拉取所有 tagged 镜像 前言 本篇来学习docker pull命令 docker pull 作用 xff1a 从镜像

随机推荐

  • 720p,1080p对应像素解释

    720P是1280 720 61 921600 xff0c 即 分辨率为921600 xff0c 即大约92万像素 xff0c 921600接近100万像素 xff08 1280是按照16 9算出来的 xff0c 4 3的另算 xff0c
  • vue3学习二:模板字符串

    模板字符串是为了解决字符串拼接问题 xff0c 在es5中 xff0c 字符串拼接是这样的 xff1a let name 61 34 wjdsg 34 console log 34 您好 34 43 name 而在es6中可以使用模板字符串
  • Canal 读取 mysql bin_log

    场景 xff1a 在微服务开发的过程中多个项目协同完成一个功能 xff0c 工程与工程之间存在数据上的解耦 xff0c 底层服务为上层服务提供数据 而底层服务有需要对数据进行管理 解决方案 xff1a 基本底层服务 通过 canal 获取
  • PuTTY连接Linux服务器被拒绝问题

    PuTTY连接Linux服务器被拒绝问题 1 使用命令 xff1a ssh localhost 查看是否安装ssh1 2需要手动安装ssh1 2 1 输入命令 xff1a 1 2 2 若是出现下图所示 xff1a 1 2 3 查看进程 xf
  • 实时数据同步工具<Maxwell 操作案例>

    文章目录 案例一 xff1a 监控MySQL中的数据并输出到控制台案例二 xff1a Maxwell监控mysql的数据输出到kafka案例三 xff1a 监控MySQL指定表的数据并输出到kafka 案例一 xff1a 监控MySQL中的
  • 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