SLAM本质剖析-Eigen

简介: SLAM本质剖析-Eigen

0. 前言


在了解SLAM的原理、流程后,个人经常实时困惑该如何去从零开始去设计编写一套能够符合我们需求的SLAM框架。作者认为Ceres、Eigen、Sophus、G2O这几个函数库无法避免,尤其是Ceres函数库在激光SLAM和V-SLAM的优化中均有着大量的应用。所以作者已从Ceres作为开端,这一篇文章主要对Eigen函数库进行详细的阐述,来方便各位后续的开发。


1. Eigen示例


相较于Ceres而言,Eigen函数库相对较为简单,我们上一篇文章详细描述了Ceres的使用以及注意事项,由于Ceres能够使用ceres::AutoDiffCostFunction这一类的自动求导函数,相对而言更加轻松,所以Eigen更多的是做矩阵运算。这里我们给出上一篇文章最后的Ceres求解的Eigen版本。我们可以看到本质上差别不大,只是Eigen需要自己求解雅克比矩阵J,并在用GN构建增量方程后,使用ldlt求解线性方程HX=g。


#include <iostream>
#include <opencv2/opencv.hpp>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <ctime>
using namespace std;
using namespace Eigen;
int main(int argc, char **argv) {
    double ar = 1.0, br = 2.0, cr = 1.0;         // 真实参数值
    double ae = 2.0, be = -1.0, ce = 5.0;        // 估计参数值
    int N = 100;                                 // 数据点
    double w_sigma = 1.0;                        // 噪声Sigma值
    cv::RNG rng;                                 // OpenCV随机数产生器
    vector<double> x_data, y_data;      // 数据
    for (int i = 0; i < N; i++) {
        double x = i / 100.0;
        x_data.push_back(x);
        y_data.push_back(exp(ar * x * x + br * x + cr) + rng.gaussian(w_sigma));
    }
    // 开始Gauss-Newton迭代
    int iterations = 100;    // 迭代次数
    double cost = 0, lastCost = 0;  // 本次迭代的cost和上一次迭代的cost
    for (int iter = 0; iter < iterations; iter++) {
        Matrix3d H = Matrix3d::Zero();             // Hessian = J^T J in Gauss-Newton
        Vector3d b = Vector3d::Zero();             // bias
        cost = 0;
//-----------------用GN构建增量方程,HX=g---------------------------------//
        for (int i = 0; i < N; i++) {
            double xi = x_data[i], yi = y_data[i];  // 第i个数据点
            // start your code here
            // double error = 0; // 填写计算error的表达式
            double error = yi-exp(ae * xi * xi + be * xi + ce);   // 第i个数据点的计算误差
            Vector3d J; // 雅可比矩阵,3x1
            J[0] = -xi*xi*exp(ae * xi * xi + be * xi + ce);  // de/da,函数求倒数,-df/da
            J[1] = -xi*exp(ae * xi * xi + be * xi + ce);;  // de/db
            J[2] = -exp(ae * xi * xi + be * xi + ce);;  // de/dc
            H += J * J.transpose(); // GN近似的H
            b += -error * J;
            // end your code here
            cost += error * error;
        }
        // 求解线性方程 Hx=b,建议用ldlt
  // start your code here
        Vector3d dx;
        //LDL^T Cholesky求解
        // clock_t time_stt2 = clock();
        dx = H.ldlt().solve(b);//Hx=b,,,H.ldlt().solve(b)
        // cout<<"LDL^T分解,耗时:\n"<<(clock()-time_stt2)/(double)
        //     CLOCKS_PER_SEC<<"ms"<<endl;
        cout<<"\n dx:"<<dx.transpose()<<endl;
        // return 0;//一写就死
  // end your code here
        if (isnan(dx[0])) {
            cout << "result is nan!" << endl;
            break;
        }
        if (iter > 0 && cost > lastCost) {
            // 误差增长了,说明近似的不够好
            cout << "cost: " << cost << ", last cost: " << lastCost << endl;
            break;
        }
        // 更新abc估计值
        ae += dx[0];
        be += dx[1];
        ce += dx[2];
        lastCost = cost;
        cout << "total cost: " << cost << endl;
    }
    cout << "estimated abc = " << ae << ", " << be << ", " << ce << endl;
    return 0;
}


TIP:值得注意的是Eigen函数库是不存在动态链接库的,我们在CMakeList.txt编译时候只需要引入include即可。


include_directories(BEFORE /home/xxx/eigen3_3/complex_eigen/install/include/eigen3/)


a0c792a9c7c44a2f84e017d16dea35f3.png


2. Eigen模块和头文件归纳


…详情请参照古月居



相关文章
|
并行计算 算法 测试技术
[Eigen中文文档] 稠密分解方法目录
本文介绍了 Eigen 提供的处理稠密矩阵分解方法的目录。
148 0
|
存储 前端开发 数据可视化
3D激光SLAM:LeGO-LOAM---两步优化的帧间里程计及代码分析
**LeGO-LOAM**的全称是 Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain 其中LeGO就是轻量级和利用地面优化,轻量级的实现就是通过两步的优化方式,利用地面优化的部分也在两步优化的第一步中。 和原始LOAM一样,通过前后两帧点云来估计两帧之间的运动,从而累加得到前端里程计的输出,和上述方法使用线面约束同时优化六自由度帧间位姿不同,LeGO-LOAM的前端分成两个步骤,每个步骤估计三自由度的变量。 通过这种方式进行帧间里程计的运算,可以提供运算效率,使得可以在嵌入式平台
3D激光SLAM:LeGO-LOAM---两步优化的帧间里程计及代码分析
|
7月前
|
计算机视觉
opencv之形态变换
opencv之形态变换
|
7月前
|
计算机视觉
图像处理之二值腐蚀
图像处理之二值腐蚀
65 0
|
8月前
halcon基础系列之几何工具相关算子
halcon基础系列之几何工具相关算子
186 0
|
8月前
|
编解码 算法 计算机视觉
OpenCV(十七):拉普拉斯图像金字塔
OpenCV(十七):拉普拉斯图像金字塔
212 0
|
存储 算法 BI
04 OpenCV位平面分解
位平面分解的核心思想是将图像的每一个像素分解为多个二进制位,分别存储在不同的位平面上。例如,如果一个图像是8位深度的,则可以分解为8个位平面,每个位平面上存储一个二进制位。
|
计算机视觉
几何变换之仿射---OpenCV-Python开发指南(12)
几何变换之仿射---OpenCV-Python开发指南(12)
222 0
几何变换之仿射---OpenCV-Python开发指南(12)
|
前端开发 定位技术 C++
3D激光SLAM:A-LOAM :前端lidar点预处理部分代码解读
A-LOAM的cpp有四个,其中 kittiHelper.cpp 的作用是将kitti数据集转为rosbag 剩下的三个是作为 slam 的 部分,分别是: - laserMappin.cpp ++++ 当前帧到地图的优化 - laserOdometry.cpp ++++ 帧间里程计 - scanRegistration.cpp ++++ 前端lidar点预处理及特征提取 本片主要解读 前端lidar点预处理部分的代码
3D激光SLAM:A-LOAM :前端lidar点预处理部分代码解读
|
传感器 算法 前端开发
3D激光SLAM:LIO-SAM整体介绍与安装编译
**LIO-SAM**的全称是:**Tightly-coupled Lidar Inertial Odometry via Smoothing and Mapping** 从全称上可以看出,该算法是一个紧耦合的雷达惯导里程计(Tightly-coupled Lidar Inertial Odometry),借助的手段就是利用GT-SAM库中的方法。 **LIO-SAM** 提出了一个利用GT-SAM的紧耦合激光雷达惯导里程计的框架。 实现了高精度、实时的移动机器人的轨迹估计和建图。 **框架的构成**: 通过相对观测(两帧间的估计)及绝对观测(GPS),还包括回环检测,构成因子图。 这
3D激光SLAM:LIO-SAM整体介绍与安装编译

热门文章

最新文章