自动驾驶SLAM技术第四章习题2

news2024/11/16 5:36:21

在g2o的基础上改成ceres优化,高博都写好了其他的部分, 后面改ceres就很简单了. 这块我用的是ceres的自动求导,很方便,就是转化为模板仿函数的时候有点麻烦, 代码部分如下

ceres_type.h : ceres优化核心库的头文件

这个文件写的内容ceres优化的残差块. 把i, j时刻的状态都写成15维的数组, 顺序是r,p,v,bg,ba. 每个元素都是3维的, 所以r 部分涉及到R->r转换, sophus都实现好了.

/**
 * @file ceres_types.cc
 * @author Frank Zhang (tanhaozhang@connect.polyu.hk)
 * @brief 
 * @version 0.1
 * @date 2023-08-15
 * 
 * @copyright Copyright (c) 2023
 * 
 */

#ifndef SLAM_IN_AUTO_DRIVING_CH4_CERES_TYPE_H_
#define SLAM_IN_AUTO_DRIVING_CH4_CERES_TYPE_H_

#include <glog/logging.h>

#include "common/eigen_types.h"
#include "ceres/ceres.h"
#include "thirdparty/sophus/sophus/so3.hpp"
#include "ch4/imu_preintegration.h"

namespace sad
{

namespace ceres_optimization
{
  class PreintegrationCostFunctionCore {
    public:
     PreintegrationCostFunctionCore(std::shared_ptr<sad::IMUPreintegration> imu_preinit, const Eigen::Vector3d gravaty)
         : preinit_(imu_preinit), dt_(imu_preinit->dt_), grav_(gravaty) {}
     template <typename T>
     bool operator()(const T* const i, const T* const j, T* residual) const {
        Eigen::Matrix<T, 3, 1> r_i(i[0], i[1], i[2]);
        Eigen::Matrix<T, 3, 1> r_j(j[0], j[1], j[2]);
        Eigen::Matrix<T, 3, 1> p_i(i[3], i[4], i[5]);
        Eigen::Matrix<T, 3, 1> p_j(j[3], j[4], j[5]);
        Eigen::Matrix<T, 3, 1> v_i(i[6], i[7], i[8]);
        Eigen::Matrix<T, 3, 1> v_j(j[6], j[7], j[8]);
        Eigen::Matrix<T, 3, 1> bg(i[9], i[10], i[11]);
        Eigen::Matrix<T, 3, 1> ba(i[12], i[13], i[14]);

        Sophus::SO3<double> dR = preinit_->GetDeltaRotation(preinit_->bg_);

        Eigen::Matrix<double, 3, 1> dvd = preinit_->GetDeltaVelocity(preinit_->bg_, preinit_->ba_);
        Eigen::Matrix<T, 3, 1> dv(T(dvd.x()), T(dvd.y()), T(dvd.z()));
        Eigen::Matrix<double, 3, 1> dpd = preinit_->GetDeltaPosition(preinit_->bg_, preinit_->ba_);
        Eigen::Matrix<T, 3, 1> dp(T(dpd.x()), T(dpd.y()), T(dpd.z()));
      
        Sophus::SO3<T, 0> R_i = Sophus::SO3<T, 0>::exp(r_i);
        Sophus::SO3<T, 0> R_j = Sophus::SO3<T, 0>::exp(r_j);

        Eigen::Matrix<T, 3, 1> grav(T(grav_.x()), T(grav_.y()), T(grav_.z()));

        Eigen::Matrix<T, 3, 1> er = (dR.inverse() * R_i.inverse() * R_j).log();
        Eigen::Matrix<T, 3, 3> RiT = R_i.matrix();
        Eigen::Matrix<T, 3, 1> ev = RiT * (v_j - v_i - grav * T(dt_)) - dv;
        Eigen::Matrix<T, 3, 1> ep = RiT * (p_j - p_i - v_i * T(dt_) - grav * T(dt_) * T(dt_) * T(0.5)) - dp;
        residual[0] = T(er[0]);
        residual[1] = T(er[1]);
        residual[2] = T(er[2]);
        residual[3] = T(ev[0]);
        residual[4] = T(ev[1]);
        residual[5] = T(ev[2]);
        residual[6] = T(ep[0]);
        residual[7] = T(ep[1]);
        residual[8] = T(ep[2]);
        return true;
    }

    private:
    const double dt_;
    std::shared_ptr<sad::IMUPreintegration> preinit_ = nullptr;
    const Eigen::Vector3d grav_;
  };

  ceres::CostFunction* CreatePreintegrationCostFunction(std::shared_ptr<sad::IMUPreintegration> imu_preinit, const Eigen::Vector3d gravaty) {
    return new ceres::AutoDiffCostFunction<PreintegrationCostFunctionCore, 9, 15, 15>(new PreintegrationCostFunctionCore(imu_preinit, gravaty));
  }

  class BiasCostFunctionCore {
   public:
    BiasCostFunctionCore(){}
    template <typename T>
    bool operator() (const T* const i, const T* const j, T* residual) const
    {
      Eigen::Matrix<T, 3, 1> bg_i(i[9], i[10], i[11]);
      Eigen::Matrix<T, 3, 1> bg_j(j[9], j[10], j[11]);
      Eigen::Matrix<T, 3, 1> ba_i(i[12], i[13], i[14]);
      Eigen::Matrix<T, 3, 1> ba_j(j[12], j[13], j[14]);
      Eigen::Matrix<T, 3, 1> d_ba = ba_j - ba_i;
      Eigen::Matrix<T, 3, 1> d_bg = bg_j - bg_i;
      residual[0] = T(d_ba[0]);
      residual[1] = T(d_ba[1]);
      residual[2] = T(d_ba[2]);
      residual[3] = T(d_bg[0]);
      residual[4] = T(d_bg[1]);
      residual[5] = T(d_bg[2]);

      return true;
    }
  };
  ceres::CostFunction* CreateBiasCostFunction() {
    return new ceres::AutoDiffCostFunction<BiasCostFunctionCore, 6, 15, 15>(
      new BiasCostFunctionCore()
    );
  }

  class PriorCostFunctionCore {
    public:
     PriorCostFunctionCore(const std::shared_ptr<sad::NavStated> prior) : prior_(prior) {}
     template <typename T>
     bool operator()(const T* const i, T* residual) const {
      Eigen::Vector3d prior_r_d = prior_->R_.log();
      Eigen::Vector3d prior_p_d = prior_->p_;
      Eigen::Vector3d prior_v_d = prior_->v_;
      Eigen::Vector3d prior_bg_d = prior_->bg_;
      Eigen::Vector3d prior_ba_d = prior_->ba_;
      Eigen::Matrix<double, 15, 1> prior_M;
      prior_M << prior_r_d, prior_p_d, prior_v_d, prior_bg_d, prior_ba_d;
      for (int temp = 0; temp < prior_M.size(); temp++)
      {
        residual[temp] = T(prior_M[temp]) - i[temp];
      }
      return true;
    }
    private:
     const std::shared_ptr<sad::NavStated> prior_;
  };
  ceres::CostFunction* CreatePriorCostFunction(const std::shared_ptr<sad::NavStated> prior) {
     return new ceres::AutoDiffCostFunction<PriorCostFunctionCore, 15, 15>(new PriorCostFunctionCore(prior));
  }

  class GnssCostFunctionCore {
    public:
    GnssCostFunctionCore(const Sophus::SE3d gnss_states) : gnss_states_(gnss_states){}
    template <typename T>
    bool operator() (const T* const i, T* residual) const
    {
      Eigen::Matrix<T, 3, 1> r_i(i[0], i[1], i[2]);
      Sophus::SO3<T, 0> R_i = Sophus::SO3<T, 0>::exp(r_i);
      Eigen::Matrix<T, 3, 1> t_i(i[3], i[4], i[5]);
      Eigen::Matrix<T, 3, 1> e_r = (gnss_states_.so3().inverse() * R_i).log();
      Eigen::Matrix<T, 3, 1> e_t = t_i - gnss_states_.translation();
      residual[0] = T(e_r[0]);
      residual[1] = T(e_r[1]);
      residual[2] = T(e_r[2]);
      residual[3] = T(e_t[0]);
      residual[4] = T(e_t[1]);
      residual[5] = T(e_t[2]);
      return true;
    }
    private:
    const Sophus::SE3d gnss_states_;
  };
  static ceres::CostFunction* CreateGnssCostFunction(const Sophus::SE3d gnss_states){
    return new ceres::AutoDiffCostFunction<GnssCostFunctionCore, 6, 15> (
      new GnssCostFunctionCore(gnss_states)
    );
  }

  class OdomCostFunctionCore {
    public:
    OdomCostFunctionCore(const Eigen::Vector3d odom_speed_states) : odom_speed_states_(odom_speed_states) {}
    template <typename T>
    bool operator() (const T* const j, T* residual ) const {
      Eigen::Matrix<T, 3, 1> vj(j[6], j[7], j[8]);
      residual[0] = T(vj[0] - odom_speed_states_[0]);
      residual[1] = T(vj[1] - odom_speed_states_[1]);
      residual[2] = T(vj[2] - odom_speed_states_[2]);
      return true;
    }
    private:
    const Eigen::Vector3d odom_speed_states_;
  };
  static ceres::CostFunction* CreatOdomCostFunction(const Eigen::Vector3d odom_speed_states) {
    return new ceres::AutoDiffCostFunction<OdomCostFunctionCore, 3, 15> (
      new OdomCostFunctionCore(odom_speed_states)
    );
  }

} // namespace ceres_optimization


} //namespace sad

#endif

上面代码分别实现了预积分, bias, 先验, GNSS, odom的残差以及其工厂函数. 不得不说啊, ceres自动求导用起来真简单.

gins_pre_integ.cc: 实现ceres预积分优化

这一部分调用上面头文件构造的工厂函数实现残差计算, ceres优化与更新. 这里只粘贴一下不同的地方

    else {
        LOG_FIRST_N(INFO, 1) << "Using Ceres to Solve!";
        ceres::Problem problem;
        Eigen::Vector3d last_r_vec = last_frame_->R_.log();
        Eigen::Vector3d current_r_vec = this_frame_->R_.log();
        double last_state[15] = {last_r_vec.x(), last_r_vec.y(), last_r_vec.z(),       
                                last_frame_->p_.x(),last_frame_->p_.y(),  last_frame_->p_.z(), 
                                last_frame_->v_.x(),  last_frame_->v_.y(), last_frame_->v_.z(),  
                                last_frame_->bg_.x(), last_frame_->bg_.y(), last_frame_->bg_.z(), 
                                last_frame_->ba_.x(), last_frame_->ba_.y(), last_frame_->ba_.z()};
        double current_state[15] = {current_r_vec.x(),    current_r_vec.y(),    current_r_vec.z(),
                                    this_frame_->p_.x(),  this_frame_->p_.y(),  this_frame_->p_.z(),
                                    this_frame_->v_.x(),  this_frame_->v_.y(),  this_frame_->v_.z(),
                                    this_frame_->bg_.x(), this_frame_->bg_.y(), this_frame_->bg_.z(),
                                    this_frame_->ba_.x(), this_frame_->ba_.y(), this_frame_->ba_.z()};
        //预积分
        problem
            .AddResidualBlock(ceres_optimization::CreatePreintegrationCostFunction(pre_integ_, options_.gravity_), nullptr, last_state, current_state);
        // 两个零偏
        problem.AddResidualBlock(ceres_optimization::CreateBiasCostFunction(), nullptr, last_state, current_state);

        //GNSS
        problem.AddResidualBlock(ceres_optimization::CreateGnssCostFunction(last_gnss_.utm_pose_), nullptr, last_state);
        problem.AddResidualBlock(ceres_optimization::CreateGnssCostFunction(this_gnss_.utm_pose_), nullptr,
                                 current_state);
        //先验
        problem.AddResidualBlock(ceres_optimization::CreatePriorCostFunction(last_frame_), nullptr, last_state);
        //ODOM
        Vec3d vel_world = Vec3d::Zero();
        Vec3d vel_odom = Vec3d::Zero();
        if (last_odom_set_) {
            // velocity obs
            double velo_l = options_.wheel_radius_ * last_odom_.left_pulse_ /
                            options_.circle_pulse_ * 2 * M_PI /
                            options_.odom_span_;
            double velo_r = options_.wheel_radius_ * last_odom_.right_pulse_ /
                            options_.circle_pulse_ * 2 * M_PI /
                            options_.odom_span_;
            double average_vel = 0.5 * (velo_l + velo_r);
            vel_odom = Vec3d(average_vel, 0.0, 0.0);
            vel_world = this_frame_->R_ * vel_odom;

            problem.AddResidualBlock(ceres_optimization::CreatOdomCostFunction(vel_world), nullptr, current_state);

            // 重置odom数据到达标志位,等待最新的odom数据
            last_odom_set_ = false;
        }


        ceres::Solver::Options options;
        options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;
        options.max_num_iterations = 20;
        options.num_threads = 4;
        options.minimizer_progress_to_stdout = false;

        ceres::Solver::Summary summary;
        ceres::Solve(options, &problem, &summary);

        Eigen::Vector3d last_r(last_state[0], last_state[1], last_state[2]);
        last_frame_->R_ = Sophus::SO3d::exp(last_r);
        Eigen::Vector3d last_t(last_state[3], last_state[4], last_state[5]);
        last_frame_->p_ = last_t;
        Eigen::Vector3d last_v(last_state[6], last_state[7], last_state[8]);
        last_frame_->v_ = last_v;
        Eigen::Vector3d last_bg(last_state[9], last_state[10], last_state[11]);
        last_frame_->bg_ = last_bg;
        Eigen::Vector3d last_ba(last_state[12], last_state[13], last_state[14]);
        last_frame_->ba_ = last_ba;

        Eigen::Vector3d current_r(current_state[0], current_state[1], current_state[2]);
        this_frame_->R_ = Sophus::SO3d::exp(current_r);
        Eigen::Vector3d current_t(current_state[3], current_state[4], current_state[5]);
        this_frame_->p_ = current_t;
        Eigen::Vector3d current_v(current_state[6], current_state[7], current_state[8]);
        this_frame_->v_ = current_v;
        Eigen::Vector3d current_bg(current_state[9], current_state[10], current_state[11]);
        this_frame_->bg_ = current_bg;
        Eigen::Vector3d current_ba(current_state[12], current_state[13], current_state[14]);
        this_frame_->ba_ = current_ba;
    }
    // 重置integ
    options_.preinteg_options_.init_bg_ = this_frame_->bg_;
    options_.preinteg_options_.init_ba_ = this_frame_->ba_;
    pre_integ_ = std::make_shared<IMUPreintegration>(options_.preinteg_options_);
}

上面部分代码为了使用autodiff做了好多不必要的数据处理, 如果有更好的解题思路欢迎留言.
上面代码分为以下几步: 1. 初始处理 2. 添加残差 3. ceres优化 4. 更新
效果如下

感觉还行, 没有评价精度

问题

没有评价精度是不是比g2o好一些
没有评价算力是不是比g2o小一些
没有实现解析求导, 正在搞

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【考研数学】矩阵、向量与线性方程组解的关系梳理与讨论

文章目录 引言一、回顾二、梳理齐次线性方程组非齐次线性方程组 写在最后 引言 两个原因让我想写这篇文章&#xff0c;一是做矩阵题目的时候就发现这三货经常绑在一起&#xff0c;让人想去探寻其中奥秘&#xff1b;另一就是今天学了向量组的秩&#xff0c;让我想起来了之前遗留…

IIS之WEB服务器详解(上)

文章目录 一、WEB服务器介绍二、服务端口号三、WEB服务发布软件四、部署WEB服务器1. 配置静态IP地址2. 安装 IIS-WEB 插件 一、WEB服务器介绍 WEB服务器也称为网页服务器或HTTP服务器&#xff0c;网页服务器大家都能理解&#xff0c;为什么称为HTTP服务器呢&#xff1f; 因为…

Leetcode每日一题:1267. 统计参与通信的服务器

原题 这里有一幅服务器分布图&#xff0c;服务器的位置标识在 m * n 的整数矩阵网格 grid 中&#xff0c;1 表示单元格上有服务器&#xff0c;0 表示没有。 如果两台服务器位于同一行或者同一列&#xff0c;我们就认为它们之间可以进行通信。 请你统计并返回能够与至少一台其…

beego的安装及bee工具的使用

1、beego 的安装 beego 的安装是典型的 Go 安装包的形式&#xff1a; go get github.com/astaxie/beego 常见问题&#xff1a; git 没有安装&#xff0c;请自行安装不同平台的 git&#xff0c;如何安装请自行搜索。 git https 无法获取&#xff0c;请配置本地的 git&#x…

搭建个让你呼吸顺畅-ChatGPT

目录 ChatGPT使用时可能会遇到 1.请待命&#xff0c;我们正在检查您的浏览器... 2. 访问被拒绝。抱歉&#xff0c;您已被阻止 3. ChatGPT 目前已满负荷运转 4. 此内容可能违反我们的内容政策。 5.出了点问题。 6. 蹦字慢吞吞&#xff0c;卡顿不流畅&#xff0c;不知道的…

日志系统——日志器模块

一&#xff0c;日志器模块主体实现 该模块主要是对前边所以模块的整合&#xff08;日志等级模块&#xff0c;日志消息模块&#xff0c;日志格式化模块&#xff0c;日志落地模块&#xff09;&#xff0c;向外提供接口完成不同等级日志的输出。当我们需要使⽤⽇志系统打印log的时…

【JVM基础】JVM入门基础

目录 JVM的位置三种 JVMJVM体系结构类加载器双亲委派机制概念例子作用 沙箱安全机制组成沙箱的基本组件 NativeJNI&#xff1a;Java Native Interface&#xff08;本地方法接口&#xff09;Native Method Stack&#xff08;本地方法栈&#xff09; PC寄存器&#xff08;Program…

使用yarn build 打包vue项目时静态文件或图片未打包成功

解决Vue项目使用yarn build打包时静态文件或图片未打包成功的问题 1. 检查vue.config.js文件 首先&#xff0c;我们需要检查项目根目录下的vue.config.js文件&#xff0c;该文件用于配置Vue项目的打包和构建选项。在这个文件中&#xff0c;我们需要确认是否正确地配置了打包输…

个性定制还是纯粹简约:探寻界面选择背后的心理宇宙

在数码世界中&#xff0c;我们的界面选择成为了一张架起的桥梁&#xff0c;连接着个性的渴望与效率的追求。当我们面对个性化定制界面和极简版原装界面&#xff0c;我们仿佛站在了一座分岔路口&#xff0c;左右各有一片令人心驰神往的风景。究竟是走向五光十色的个性世界&#…

文件文档在线预览转换解决方案和应用

文章目录 Java Word转PDF文件方案评测一、kkFileView应用场景一&#xff1a;官网原始部署与应用二、kkFileView应用场景二&#xff1a;编译、自定义制作docker镜像部署三、kkfileview预览pdf文件以及关键词高亮和定位 Java Word转PDF文件方案评测 Word转PDF网上常见的方案5种&…

【Unity】【Amplify Shader Editor】ASE入门系列教程第一课 遮罩

新建材质 &#xff08;不受光照材质&#xff09; 贴图&#xff1a;快捷键T 命名&#xff1a; UV采样节点&#xff1a;快捷键U 可以调节主纹理的密度与偏移 添加UV流动节点&#xff1a; 创建二维向量&#xff1a;快捷键 2 遮罩&#xff1a;同上 设置shader材质的模板设置 添加主…

当服务器中了勒索病毒以后该怎么办?勒索病毒解密,数据恢复

无论对于什么体量的企业而言&#xff0c;数据都是企业的命。没有了数据就连正常的生产经营都没有办法做到。也正是因为如此&#xff0c;才会有一些黑客专门攻击企业的服务器&#xff0c;并将数据进行加密&#xff0c;以此来达到勒索赎金的目的&#xff0c;这就是很多企业有可能…

大同趋势,龙头股的自我修养-神奇指标网

入市的投资者总能听到一句话&#xff0c;历史会重演但不会简单重演。 技术分析是相同的道理&#xff0c;当我们关注历史上发生过的行情&#xff0c;我们对于技术的理解自然越近的周期我们印象越深&#xff0c;感性认识越强烈&#xff0c;而市场趋势就是由投资者推动的&#xf…

Scratch 之 如何打包 Scratch 成为可执行文件?

各位好&#xff0c;这期文章教学中&#xff0c;我将教大家如何打包Scratch文件(.sb3)为可执行文件(.exe)或网页文件(*.htm; *.html)。 另附&#xff1a;本期文章中有个可以转换的好网站 首先&#xff0c;还是一如既往打开Turbowarp Packager&#xff1a; 网址&#xff1a;htt…

介绍下杭州聚会的小伙伴们

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 2023年8月17日至18日&#xff0c;卢松松在杭州举办了一次创业者小聚会。 这次杭州之行&#xff0c;卢松松不仅见到了阿里巴巴的朋友&#xff0c;也见到了支付宝的朋友&#xff0c;还参观了支付宝合…

Android沉浸式实现(记录)

沉浸式先看效果 直接上代码 Android manifest文件 android:theme="@style/Theme.AppCompat.NoActionBar"布局文件 <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android=&qu…

FinalShell报错:Swap file “.docker-compose.yml.swp“ already exists

FinalShell中编辑docker-compose.yml文件&#xff0c;保存时报错&#xff1a;Swap file ".docker-compose.yml.swp" already exists&#xff1b;报错信息截图如下&#xff1a; 问题原因&#xff1a;有人正在编辑docker-compose.yml文件或者上次编辑没有保存&#xff…

【Python爬虫】使用代理ip进行网站爬取

前言 使用代理IP进行网站爬取可以有效地隐藏你的真实IP地址&#xff0c;让网站难以追踪你的访问行为。本文将介绍Python如何使用代理IP进行网站爬取的实现&#xff0c;包括代理IP的获取、代理IP的验证、以及如何把代理IP应用到爬虫代码中。 1. 使用代理IP的好处 在进行网站爬…

使用 uniapp 适用于wx小程序 - 实现移动端头部的封装和调用

图例&#xff1a;红框区域&#xff0c;使其标题区与胶囊对齐 一、组件 navigation.vue <template><view class"nav_name"><view class"nav-title" :style"{color : props.color, padding-top : toprpx,background : props.bgColor,he…

嵌入式软件开发工具简化基于STM8的智能装置开发

嵌入式软件开发工具简化基于STM8的智慧装置开发 降低功耗一直是微控器(MCU)市场的主要关注焦点。超低功耗MCU现在可大幅降低主动和深度睡眠的功耗。此种变化的效果是显而易见的&#xff0c;因为它大幅提高了日常嵌入式应用的电池寿命&#xff0c;以及在未来使用能量采集的可能性…