SLAM十四讲报错解决(2)

问题:运行ch6的gaussNewton.cpp出现错误,后来是g2oCurveFitting.cpp出现错误。版本为20.04

在ch6目录下新建build文件夹,运行cmake ..出现警告,提示G2O_INCLUDE_DIRS找不到,原因是我3rdparty目录下的g2o没有编译、安装。

由此引发一系列问题,进行的工作包括g2o安装、metis安装、g2o卸载重安装、ceres卸载重安装、修改g2oCurveFitting.cpp代码和两个Cmake文件使C++版本匹配。

目录

(1)g2o安装

(2)gaussNewton编译还是错误

(3)metis安装

(4)gaussNewton编译又错误

(5)重新安装g2o

(6)删除Ceres库

(7)安装ceres

(8)编译ch6还是报错

(9)修改代码和cmake

(10)成功!!!


(1)g2o安装

首先打开终端安装依赖项:

sudo apt-get install qt5-qmake qt5-default libqglviewer-dev-qt5 libsuitesparse-dev libcxsparse3 libcholmod3

进入g2o目录:

mkdir build 
cd build

编译、安装:

cmake ..
make -j4
sudo make install

(2)gaussNewton编译还是错误

安装成功后,首先修改gaussNewton的CMakeLists.txt的版本为cmake_minimum_required(VERSION 3.10),然后进入ch6目录下的build,重新编译cmake ..,显示无法找到METIS。

(3)metis安装

参考博客metis安装,直接安装,终端输入:

sudo apt-get install libmetis-dev

查询并修改代码:

whereis metis # 查找命令
metis: /usr/include/metis.h
sudo gedit /usr/include/metis.h

根据电脑修改为64位或32位:

完成。

(4)gaussNewton编译又错误

 在build目录下编译cmake ..,不再报错。

额……make还是出现相同错误,截取部分

(5)重新安装g2o

估计是slambook2的g2o太老了?重新安装g2o试试,把原来3rdparty目录下的g2o改成g2o1(不用但是不敢删),终端输入

git clone https://github.com/RainerKuemmerle/g2o.git

把home目录下刚下载的g2o文件夹移到3rdparty下,进入g2o目录:

mkdir build
cd build
cmake ..
make
sudo make install

一切弄好,make之后还是报错……

试了很久,决定重新安装Ceres库。首先把原来的删除干净

(6)删除Ceres库

要删的有Ceres和absl(我另外装的)

# 看准目录,根据自己的目录来
cd /usr/local/lib
sudo rm -rf libabsl_* libceres.a
sudo rm -r /cmake/Ceres
sudo rm -r /cmake/absl
cd /usr/local/include
sudo rm -r absl
sudo rm -rf ceres

(7)安装ceres

参考博客cuda导致ceres编译报错_ceres cuda-优快云博客,直接用官网下。

一切都很顺利。

#1. 下载ceres2.0版本
# 地址为 http://ceres-solver.org/ceres-solver-2.0.0.tar.gz
#2. 解压,放到slambook2/3rdparty目录下
#3. 进入目录,然后编译
cd ceres-solver
mkdir build && cd build 
cmake ..
make -j3
sudo make install

(8)编译ch6还是报错

【首先前面已经修改了gaussNewton的CMakeLists.txt的版本为cmake_minimum_required(VERSION 3.10)】进入ch6目录下的build,编译不报错

cd build
cmake ..

显示

呵呵,make之后还是报错,截取部分如下,并且跟之前报错一模一样!!!!

实不相瞒,鼠鼠我呀好想鼠。

(9)修改代码和cmake

问豆包,总结了三个问题。

(1)g2o库没有是c++17标准,以及链接可能发生错误,需要同时检查和修改两处CMakeLists.txt的标准问题。在g2o的CMakeLists.txt添加

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

ch6的CMakeLists.txt修改

set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS "-std=c++17 -O3") #原来是c++14

(2)CurveFittingVertex类和CurveFittingEdge类的read和write函数中,函数声明为bool类型,但函数体中没有return语句。

(3)修正make_unique的使用:将g2o::make_unique替换为std::make_unique。修改后的g2oCurveFitting.cpp如下

#include <iostream>
#include <g2o/core/g2o_core_api.h>
#include <g2o/core/base_vertex.h>
#include <g2o/core/base_unary_edge.h>
#include <g2o/core/block_solver.h>
#include <g2o/core/optimization_algorithm_levenberg.h>
#include <g2o/core/optimization_algorithm_gauss_newton.h>
#include <g2o/core/optimization_algorithm_dogleg.h>
#include <g2o/solvers/dense/linear_solver_dense.h>
#include <Eigen/Core>
#include <opencv2/core/core.hpp>
#include <cmath>
#include <chrono>


using namespace std;


// 曲线模型的顶点,模板参数:优化变量维度和数据类型
class CurveFittingVertex : public g2o::BaseVertex<3, Eigen::Vector3d> {
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW


    // 重置
    virtual void setToOriginImpl() override {
        _estimate << 0, 0, 0;
    }


    // 更新
    virtual void oplusImpl(const double *update) override {
        _estimate += Eigen::Vector3d(update);
    }


    // 存盘和读盘:留空
    virtual bool read(istream &in) override {
        return false;
    }


    virtual bool write(ostream &out) const override {
        return false;
    }
};


// 误差模型 模板参数:观测值维度,类型,连接顶点类型
class CurveFittingEdge : public g2o::BaseUnaryEdge<1, double, CurveFittingVertex> {
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW


    CurveFittingEdge(double x) : BaseUnaryEdge(), _x(x) {}


    // 计算曲线模型误差
    virtual void computeError() override {
        const CurveFittingVertex *v = static_cast<const CurveFittingVertex *>(_vertices[0]);
        const Eigen::Vector3d abc = v->estimate();
        _error(0, 0) = _measurement - std::exp(abc(0, 0) * _x * _x + abc(1, 0) * _x + abc(2, 0));
    }


    // 计算雅可比矩阵
    virtual void linearizeOplus() override {
        const CurveFittingVertex *v = static_cast<const CurveFittingVertex *>(_vertices[0]);
        const Eigen::Vector3d abc = v->estimate();
        double y = exp(abc[0] * _x * _x + abc[1] * _x + abc[2]);
        _jacobianOplusXi[0] = -_x * _x * y;
        _jacobianOplusXi[1] = -_x * y;
        _jacobianOplusXi[2] = -y;
    }


    virtual bool read(istream &in) override {
        return false;
    }


    virtual bool write(ostream &out) const override {
        return false;
    }


public:
    double _x;  // x 值, y 值为 _measurement
};


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值
    double inv_sigma = 1.0 / w_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 * w_sigma));
    }


    // 构建图优化,先设定g2o
    typedef g2o::BlockSolver<g2o::BlockSolverTraits<3, 1>> BlockSolverType;  // 每个误差项优化变量维度为3,误差值维度为1
    typedef g2o::LinearSolverDense<BlockSolverType::PoseMatrixType> LinearSolverType; // 线性求解器类型


    // 梯度下降方法,可以从GN, LM, DogLeg 中选
    auto solver = new g2o::OptimizationAlgorithmGaussNewton(
        std::make_unique<BlockSolverType>(std::make_unique<LinearSolverType>()));
    g2o::SparseOptimizer optimizer;     // 图模型
    optimizer.setAlgorithm(solver);   // 设置求解器
    optimizer.setVerbose(true);       // 打开调试输出


    // 往图中增加顶点
    CurveFittingVertex *v = new CurveFittingVertex();
    v->setEstimate(Eigen::Vector3d(ae, be, ce));
    v->setId(0);
    optimizer.addVertex(v);


    // 往图中增加边
    for (int i = 0; i < N; i++) {
        CurveFittingEdge *edge = new CurveFittingEdge(x_data[i]);
        edge->setId(i);
        edge->setVertex(0, v);                // 设置连接的顶点
        edge->setMeasurement(y_data[i]);      // 观测数值
        edge->setInformation(Eigen::Matrix<double, 1, 1>::Identity() * 1 / (w_sigma * w_sigma)); // 信息矩阵:协方差矩阵之逆
        optimizer.addEdge(edge);
    }


    // 执行优化
    cout << "start optimization" << endl;
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    optimizer.initializeOptimization();
    optimizer.optimize(10);
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
    cout << "solve time cost = " << time_used.count() << " seconds. " << endl;


    // 输出优化值
    Eigen::Vector3d abc_estimate = v->estimate();
    cout << "estimated model: " << abc_estimate.transpose() << endl;


    return 0;
}

(10)成功!!!

删除ch6的build,重新建build和进入build目录,cmake ..和make

贴一张结果图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值