ORB-SLAM3如何加入GPS和Wheel轮速约束

0. 简介

对于ORB-SLAM3而言。如何将代码融入Wheel和GPS是一个挺有意思的事情。通过GPS和Wheel可以非常有效的约束视觉里程计结果。Wheel这块主要就是将速度等信息融合到前端中,类似IMU和视觉帧间的关系。而GPS由于频率不是很高,所以基本是用于全局修正的作用。这部分我们经常使用松耦合的形式,当然也有工作去做了紧耦合相关的工作。

1. Wheel特征添加

这一部分主要的其实就是将wheel的速度特征传入到imu中,以约束两者之间的位移信息。从而提供针对IMU的约束,并可以作为边约束约束G2O的边

1.1 ImuType.h

这一步主要是得是将轮速信息融合到IMU内部去做联合优化,这里面主要用于处理传感器数据融合和运动状态估计。

Point(const cv::Point3f Acc, const cv::Point3f Gyro, const double &timestamp, const double& encoder_v):
            a(Acc.x,Acc.y,Acc.z), w(Gyro.x,Gyro.y,Gyro.z), t(timestamp), encoder_v(encoder_v){}
.........
void IntegrateNewMeasurement(const Eigen::Vector3f &acceleration, const Eigen::Vector3f &angVel, const float &dt,const double &encoder_v );
.........
    Eigen::DiagonalMatrix<float,6> Nga, NgaWalk;
    Eigen::DiagonalMatrix<float,9> Nga_en, NgaWalk_en;

    // Values for the original bias (when integration was computed)
    Bias b;
    Eigen::Matrix3f dR;
    Eigen::Vector3f dV, dP;
    Eigen::Matrix3f Rbo = Eigen::Matrix3f::Identity();   //encoder 和imu的旋转
    Eigen::Vector3d Tbo = {-0.9810000061988831,0,0};   //encoder 和imu的旋转
    Eigen::Matrix3f JRg, JVg, JVa, JPg, JPa;
    Eigen::Vector3f avgA, avgW;
    Eigen::Vector3f encoder_velocity ;
    Eigen::Matrix<float,18,18> jacobian_enc;
    Eigen::Matrix<float,21,21> covariance_enc;

1.2 ImuType.cc

下面IntegrateNewMeasurement 函数中,该系统整合了惯性测量(来自加速度计和陀螺仪)和可选的编码器读数。此函数的主要目的是根据这些测量数据更新内部状态,以跟踪位置、速度和旋转的变化。

/** 
 * @brief 初始化预积分
 * @param b_ 偏置
 */
void Preintegrated::Initialize(const Bias &b_)
{
    dR.setIdentity();
    dV.setZero();
    dP.setZero();
    JRg.setZero();
    JVg.setZero();
    JVa.setZero();
    JPg.setZero();
    JPa.setZero();
    C.setZero();
    Info.setZero();
    db.setZero();
    encoder_velocity.setZero();
    jacobian_enc.setZero();
    covariance_enc.setZero();
    b = b_;
    bu = b_;  // 更新后的偏置
    avgA.setZero();  // 平均加速度
    avgW.setZero();  // 平均角速度
    dT = 0.0f;
    mvMeasurements.clear();  // 存放imu数据及dt
}

/** 
 * @brief 根据新的偏置重新积分mvMeasurements里的数据 Optimizer::InertialOptimization调用
 */ 
void Preintegrated::Reintegrate()
{
    std::unique_lock<std::mutex> lock(mMutex);
    const std::vector<integrable> aux = mvMeasurements;
    //重新进行预积分
    Initialize(bu);
    bool buseencoder;
    buseencoder = true;
    if(buseencoder){
        for (size_t i = 0; i < aux.size(); i++)
            IntegrateNewMeasurement(aux[i].a, aux[i].w, aux[i].t,aux[i].enc);
    }
    else{
    for (size_t i = 0; i < aux.size(); i++)
        IntegrateNewMeasurement(aux[i].a, aux[i].w, aux[i].t);}
}

void Preintegrated::IntegrateNewMeasurement(const Eigen::Vector3f &acceleration, const Eigen::Vector3f &angVel, const float &dt,const double &encoder_v)
    {
        // 保存imu数据,利用中值积分的结果构造一个预积分类保存在mvMeasurements中
        mvMeasurements.push_back(integrable(acceleration, angVel, dt,encoder_v));

        // Position is updated firstly, as it depends on previously computed velocity and rotation.
        // Velocity is updated secondly, as it depends on previously computed rotation.
        // Rotation is the last to be updated.

        // Matrices to compute covariance
        // Step 1.构造协方差矩阵
        // 噪声矩阵的传递矩阵,这部分用于计算i到j-1历史噪声或者协方差
        Eigen::Matrix<float, 9, 9> A;
        A.setIdentity();
        // 噪声矩阵的传递矩阵,这部分用于计算j-1新的噪声或协方差,这两个矩阵里面的数都是当前时刻的,计算主要是为了下一时刻使用
        Eigen::Matrix<float, 9, 6> B;
        B.setZero();

        // 考虑偏置后的加速度、角速度
        Eigen::Vector3f acc, accW;
        acc << acceleration(0) - b.bax, acceleration(1) - b.bay, acceleration(2) - b.baz;
        accW << angVel(0) - b.bwx, angVel(1) - b.bwy, angVel(2) - b.bwz;

        // 记录平均加速度和角速度
        avgA = (dT * avgA + dR * acc * dt) / (dT + dt);
        avgW = (dT * avgW + accW * dt) / (dT + dt);


        // Update delta position dP and velocity dV (rely on no-updated delta rotation)
        // 根据没有更新的dR来更新dP与dV  eq.(38)
        dP = dP + dV * dt + 0.5f * dR * acc * dt * dt;
        dV = dV + dR * acc * dt;
        Eigen::Vector3f encoder_cast = { static_cast<float>(encoder_v),0,0};
        encoder_velocity = encoder_velocity + dR*Rbo* encoder_cast*dt;
        //std::cerr<<"encoder_velocity "<<encoder_velocity;


        // Compute velocity and position parts of matrices A and B (rely on non-updated delta rotation)
        // 根据η_ij = A * η_i,j-1 + B_j-1 * η_j-1中的A矩阵和B矩阵对速度和位移进行更新
        Eigen::Matrix<float, 3, 3> Wacc = Sophus::SO3f::hat(acc);

        A.block<3, 3>(3, 0) = -dR * dt * Wacc;
        A.block<3, 3>(6, 0) = -0.5f * dR * dt * dt * Wacc;
        A.block<3, 3>(6, 3) = Eigen::DiagonalMatrix<float, 3>(dt, dt, dt);
        B.block<3, 3>(3, 3) = dR * dt;
        B.block<3, 3>(6, 3) = 0.5f * dR * dt * dt;

        // Update position and velocity jacobians wrt bias correction
        // 因为随着时间推移,不可能每次都重新计算雅克比矩阵,所以需要做J(k+1) = j(k) + (~)这类事,分解方式与AB矩阵相同
        // 论文作者对forster论文公式的基础上做了变形,然后递归更新,参见 https://github.com/UZ-SLAMLab/ORB_SLAM3/issues/212
        JPa = JPa + JVa * dt - 0.5f * dR * dt * dt;
        JPg = JPg + JVg * dt - 0.5f * dR * dt * dt * Wacc * JRg;
        JVa = JVa - dR * dt;
        JVg = JVg - dR * dt * Wacc * JRg;

        // Update delta rotation
        // Step 2. 构造函数,会根据更新后的bias进行角度积分
        IntegratedRotation dRi(angVel, b, dt);
        // 强行归一化使其符合旋转矩阵的格式
        auto dR_past = dR;
        dR = NormalizeRotation(dR * dRi.deltaR);

        //std::cerr<<"dR_past"<<dR_past<<std::endl;
        //std::cerr<<"dR"<<dR<<std::endl;
        // Compute rotation parts of matrices A and B
        // 补充AB矩阵
        A.block<3, 3>(0, 0) = dRi.deltaR.transpose();
        B.block<3, 3>(0, 0) = dRi.rightJ * dt;

        // 小量delta初始为0,更新后通常也为0,故省略了小量的更新
        // Update covariance
        // Step 3.更新协方差,frost经典预积分论文的第63个公式,推导了噪声(ηa, ηg)对dR dV dP 的影响
        C.block<9, 9>(0, 0) = A * C.block<9, 9>(0, 0) * A.transpose() + B * Nga * B.transpose();  // B矩阵为9*6矩阵 Nga 6*6对角矩阵,3个陀螺仪噪声的平方,3个加速度计噪声的平方
        // 这一部分最开始是0矩阵,随着积分次数增加,每次都加上随机游走,偏置的信息矩阵
        C.block<6, 6>(9, 9) += NgaWalk;

        // Update rotation jacobian wrt bias correction
        // 计算偏置的雅克比矩阵,r对bg的导数,∂ΔRij/∂bg = (ΔRjj-1) * ∂ΔRij-1/∂bg - Jr(j-1)*t
        // 论文作者对forster论文公式的基础上做了变形,然后递归更新,参见 https://github.com/UZ-SLAMLab/ORB_SLAM3/issues/212
        // ? 为什么先更新JPa、JPg、JVa、JVg最后更新JRg? 答:这里必须先更新dRi才能更新到这个值,但是为什么JPg和JVg依赖的上一个JRg值进行更新的?
        JRg = dRi.deltaR.transpose() * JRg - dRi.rightJ * dt;

        // Total integrated time
        // 更新总时间
        dT += dt;

        bool buseencoder;
        buseencoder = true;
// TODO
        if(buseencoder){
            Eigen::MatrixXf F = Eigen::MatrixXf ::Zero(12,12);
//            F.block<3,3>(0,0) = Eigen::Matrix3f::Identity();
//            F.block<3,3>(0,3) = A.block<3, 3>(6, 0);
//            F.block<3,3>(0,6) = Eigen::DiagonalMatrix<float, 3>(dt, dt, dt);
//
//            F.block<3,3>(3,3) = dRi.deltaR.transpose();
//
//            F.block<3,3>(6,3) = A.block<3, 3>(3, 0);
//            F.block<3,3>(6,6) = Eigen::Matrix3f::Identity();

            //轮速

            Eigen::Vector3f encoder_fi = Rbo*encoder_velocity;
            Eigen::Matrix3f R_encoder;
            R_encoder<< 0, -encoder_fi(2), encoder_fi(1),encoder_fi(2), 0, -encoder_fi(0),-encoder_fi(1), encoder_fi(0), 0;
//            F.block<3,3>(9,3) =-dR_past*dt*R_encoder;
//            F.block<3,3>(9,9) = Eigen::Matrix3f::Identity();


            Eigen::MatrixXf V = Eigen::MatrixXf ::Zero(12,9);
//            V.block<3,3>(0,0) = 0.5f * dR_past * dt * dt;
//            V.block<3,3>(3,3) = dRi.rightJ * dt;
//            V.block<3,3>(6,0) = dR_past * dt;
//            V.block<3,3>(9,6) = dR_past*Rbo*dt;

            F.block<9,9>(0,0) = A;
            F.block<3,3>(9,3) = -dR_past*dt*R_encoder;
            F.block<3,3>(9,9) = Eigen::Matrix3f::Identity();

            V.block<9,6>(0,0) = B;
            V.block<3,3>(9,6) = dR_past*Rbo*dt;


            covariance_enc.block<12,12>(0,0) = F*covariance_enc.block<12,12>(0,0)*F.transpose()+V*Nga_en*V.transpose();
            covariance_enc.block<9,9>(12,12) += NgaWalk_en;



        }
    }

1.3 Tracking.cc

…详情请参照古月居

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解锁AI新纪元:如何用好大语言模型?

在20世纪末和21世纪初&#xff0c;⼈类经历了两次信息⾰命的浪潮&#xff1a; 第⼀次是互联网时代的兴起&#xff0c;将世界各地连接在⼀起&#xff0c;改变了⼈们获取信息和交流的⽅式。 第⼆次则是移动互联网时代的到来&#xff0c;智能⼿机和移动应⽤程序的普及使⼈们可以…

Oracle 数据库全面升级为 23ai

从 11g 到 12c 再到 19c&#xff0c;今天&#xff0c;我们迎来了 23ai &#xff01; “ Oracle AI Vector Search allows documents, images, and relational data that are stored in mission-critical databases to be easily searched based on their conceptual content Ge…

平平科技工作室-Python-猜数字游戏

一.代码展示 import random print(__猜数字游戏__) print(由平平科技工作室制作) print(游戏规则:1至10随机数随便猜) print (三次没猜对游戏结束) numrandom.randint (1,10) for i in range(3):aint(input(输入你想要猜测的数字))if a>num:print (数字猜的有点大了)elif a…

MySQL-数据缓冲池(Buffer Pool)

InnoDB存储引擎以 页 为单位管理存储空间&#xff0c;增删改查的本质就是访问页面。为提高查询效率&#xff0c;DBMS会占用内存作为缓冲池&#xff0c;在执行SQL之前&#xff0c;会将磁盘上的页 缓存到内存中的 缓冲池&#xff08;Buffer Pool&#xff09;后执行相关SQL语句。 …

git学习指南

文章目录 一.版本控制1.认识版本控制2.版本控制功能3.集中式版本控制4.分布式版本控制 二.Git的环境安装搭建1.Git的安装2.Git配置分类3.Git配置选项 三.Git初始化本地仓库1. git init/git clone-获取Git仓库2. 本地仓库文件的划分3. git status-检测文件的状态4. git add-文件…

数据库基础--MySQL多表查询之外键约束

MySQL多表关系 一对一 顾名思义即一个对应一个的关系&#xff0c;例如身份证号对于每个人来说都是唯一的&#xff0c;即个人信息表与身份证号信息表是一对一的关系。车辆信息表与车牌信息表也是属于一对一的关系。 一对多 即一个表当中的一个字段信息&#xff0c;对应另一张…

黑马面试篇1

目录 一、面试准备 二、Redis篇 ​编辑1. 布隆过滤器&#xff1a; 2. 缓存击穿概念&解决方案 3. 双写一致 4. 持久化 1&#xff09;RDB的执行原理&#xff1f; 2&#xff09;AOF vs RDB 5. 数据过期策略 6. 数据淘汰策略 7. 分布式锁 8. Redis集群 1&#xff…

如何选择一个出色的APP内测分发平台 - 探讨小猪APP分发平台

在众多APP内测分发平台中如何选择一个出色的APP内测分发平台 - 探讨小猪APP分发平台&#xff0c;小猪APP分发平台&#xff08;zixun.ppzhu.net&#xff09;以其出色的服务和高效的推广机制成为行业佼佼者。 小猪APP分发平台的核心优势 小猪APP分发平台不仅以其用户友好的界面赢…

Coze扣子开发指南:搭建一个免费的微信公众号AI客服

运营微信公众号的自媒体&#xff0c;现在借助Coze扣子可以非常好用而且免费的7*24客服了&#xff0c;完全不需要任何编程基础&#xff0c;操作非常简单&#xff1a; 打开Coze扣子&#xff0c;新建一个bot&#xff0c;输入bot名称、功能介绍和图标&#xff1a; 选择大语言模型&…

论文笔记(四十五)Attention Is All You Need

Attention Is All You Need 文章概括摘要1. 介绍2. 背景3. 模型架构3.1 编码器和解码器堆栈3.2 Attention3.2.1 按比例点积Attention3.2.2 Multi-Head Attention3.2.3 注意力在模型中的应用 3.3 定位前馈网络3.4 嵌入与 Softmax3.5 位置编码 4 为什么 Self-Attention5. Trainin…

OpenWRT部署Zerotier虚拟局域网实现内网穿透

前言 细心的小伙伴肯定已经发现了&#xff1a;电脑上部署了Zerotier&#xff0c;如果路由器也部署了OpenWRT&#xff0c;那是否能远程访问呢&#xff1f; 答案是肯定的。 OpenWRT部署Zerotier有啥好处&#xff1f; 那好处必须多&#xff0c;其中的一个便是在外远程控制家里…

Win11安装Postgresql(更新于24.5)

Postgresql是一个功能强大的开源对象关系数据库系统&#xff0c;拥有超过 35 年的积极开发经验&#xff0c;这为其在可靠性、功能稳健性和性能方面赢得了良好的声誉。 1.安装程序下载 根据系统版本型号选择对应安装程序完成下载 网址&#xff1a; https://www.enterprisedb…

自定驾驶A*算法的思路

1. 背景 2 算法理论 2. 1.A*算法公式 2.2. H是不确定的 2.4. H使用的启发函数 2.5. 曼哈顿距离

电机控制系列模块解析(14)—— 脉冲频率/幅值/密度调制

一、脉冲序列调制&#xff08;PSM&#xff09; 脉冲宽度调制&#xff08;PWM&#xff09;、脉冲幅值调制&#xff08;PAM&#xff09;和脉冲密度调制&#xff08;PDM&#xff09;都是脉冲序列调制技术&#xff0c;它们通过改变脉冲信号的某一特性&#xff08;宽度、幅值或密度…

机器学习每周挑战——二手车车辆信息交易售价数据

这是数据集的截图 目录 背景描述 数据说明 车型对照&#xff1a; 燃料类型对照&#xff1a; 老规矩&#xff0c;第一步先导入用到的库 第二步&#xff0c;读入数据&#xff1a; 第三步&#xff0c;数据预处理 第四步&#xff1a;对数据的分析 第五步&#xff1a;模型建…

深入了解 Arthas:Java 应用程序诊断利器

序言 在 Java 应用程序的开发和运维过程中&#xff0c;诊断和解决性能问题是一项非常重要的任务。而 Arthas 作为一款由阿里巴巴开发的 Java 应用程序诊断工具&#xff0c;提供了一系列强大的功能&#xff0c;帮助开发人员实时监控、诊断和调优Java 应用程序。本文将深入介绍 …

压缩机的实际制冷量

制冷压缩机是制冷系统的“心脏”&#xff0c;吸收来自蒸发器的制冷剂蒸气&#xff0c;提高压力后排气到冷凝器&#xff0c;使制冷剂在系统中循环流动。 按温度范围可以分为高温&#xff0c;中温&#xff0c;低温制冷压缩机。按密封结构形式分类为开启式&#xff1b;半封闭式&a…

深度学习每周学习总结P7(咖啡豆识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 –来自百度网盘超级会员V5的分享 数据链接 提取码&#xff1a;7zt2 –来自百度网盘超级会员V5的分享 目录 0. 总结1. 数据导入及处理部分…

【Linux】学习笔记

文章目录 [toc]第一章&#xff1a;基础篇01|课程介绍02|内容综述03|什么是Linux04|Linux的内核版本及常见发行版内核版本发行版本Red Hat Enterprise LinuxFedoraCentOSDebianUbuntu 05|安装VirtualBox虚拟机VirtualBox下载url 06|在虚拟机中安装Linux系统Linux安装镜像下载 07…

020、Python+fastapi,第一个Python项目走向第20步:ubuntu 24.04 docker 安装mysql8、redis(一)

系列文章 pythonvue3fastapiai 学习_浪淘沙jkp的博客-CSDN博客https://blog.csdn.net/jiangkp/category_12623996.html 前言 docker安装起来比较方便&#xff0c;不影响系统整体&#xff0c;和前面虚拟环境有异曲同工之妙&#xff0c;今天把老笔记本T400拿出来装了个ubuntu24…