学习记录-自动驾驶与机器人中的SLAM技术

以下所有内容均为高翔大神所注的《自动驾驶与机器人中的SLAM技术》中的内容

2D SLAM

  • 作者实现了一个2D 的ICP

3D SLAM

ICP

  • 实现了一个并发的ICP配准
  • 实现了点到面的ICP
  • 实现了点到线的ICP
  • 点到线的ICP的结果与点到点的ICP相当,略差于点到面的、在三中算法中,点到面的ICP在精度和效率上都具有一定优势,明显快于PCL的内置版本,单其单次迭代中计算量明显大于原始ICP

NDT

本书各配准算法与PCL的对比

增量式NDT

需要解决两个问题:

  1. 每个体素内的高斯参数如何改变
  2. 如何维护不断增加的体素

高斯分布的增量更新

体素的增量维护

融合导航

1. EKF和优化的关系

2. 组合导航eskf中的预测部分,主要是F矩阵的构建

template <typename S>
bool ESKF<S>::Predict(const IMU& imu) {assert(imu.timestamp_ >= current_time_);double dt = imu.timestamp_ - current_time_;if (dt > (5 * options_.imu_dt_) || dt < 0) {// 时间间隔不对,可能是第一个IMU数据,没有历史信息LOG(INFO) << "skip this imu because dt_ = " << dt;current_time_ = imu.timestamp_;return false;}// nominal state 递推VecT new_p = p_ + v_ * dt + 0.5 * (R_ * (imu.acce_ - ba_)) * dt * dt + 0.5 * g_ * dt * dt;VecT new_v = v_ + R_ * (imu.acce_ - ba_) * dt + g_ * dt;SO3 new_R = R_ * SO3::exp((imu.gyro_ - bg_) * dt);R_ = new_R;v_ = new_v;p_ = new_p;// 其余状态维度不变// error state 递推// 计算运动过程雅可比矩阵 F,见(3.47)// F实际上是稀疏矩阵,也可以不用矩阵形式进行相乘而是写成散装形式,这里为了教学方便,使用矩阵形式Mat18T F = Mat18T::Identity();                                                 // 主对角线F.template block<3, 3>(0, 3) = Mat3T::Identity() * dt;                         // p 对 vF.template block<3, 3>(3, 6) = -R_.matrix() * SO3::hat(imu.acce_ - ba_) * dt;  // v对thetaF.template block<3, 3>(3, 12) = -R_.matrix() * dt;                             // v 对 baF.template block<3, 3>(3, 15) = Mat3T::Identity() * dt;                        // v 对 gF.template block<3, 3>(6, 6) = SO3::exp(-(imu.gyro_ - bg_) * dt).matrix();     // theta 对 thetaF.template block<3, 3>(6, 9) = -Mat3T::Identity() * dt;                        // theta 对 bg// mean and cov predictiondx_ = F * dx_;  // 这行其实没必要算,dx_在重置之后应该为零,因此这步可以跳过,但F需要参与Cov部分计算,所以保留cov_ = F * cov_.eval() * F.transpose() + Q_;current_time_ = imu.timestamp_;return true;
}

3. 以下是速度量测,主要是H矩阵的构建

template <typename S>
bool ESKF<S>::ObserveWheelSpeed(const Odom& odom) {assert(odom.timestamp_ >= current_time_);// odom 修正以及雅可比// 使用三维的轮速观测,H为3x18,大部分为零Eigen::Matrix<S, 3, 18> H = Eigen::Matrix<S, 3, 18>::Zero();H.template block<3, 3>(0, 3) = Mat3T::Identity();// 卡尔曼增益Eigen::Matrix<S, 18, 3> K = cov_ * H.transpose() * (H * cov_ * H.transpose() + odom_noise_).inverse();// velocity obsdouble velo_l = options_.wheel_radius_ * odom.left_pulse_ / options_.circle_pulse_ * 2 * M_PI / options_.odom_span_;double velo_r = options_.wheel_radius_ * odom.right_pulse_ / options_.circle_pulse_ * 2 * M_PI / options_.odom_span_;double average_vel = 0.5 * (velo_l + velo_r);VecT vel_odom(average_vel, 0.0, 0.0);VecT vel_world = R_ * vel_odom;dx_ = K * (vel_world - v_);//v_是状态递推后的速度// update covcov_ = (Mat18T::Identity() - K * H) * cov_;UpdateAndReset();return true;
}

4. 以下是GPS的量测,主要任然是H矩阵的构建

template <typename S>
bool ESKF<S>::ObserveGps(const GNSS& gnss) {/// GNSS 观测的修正assert(gnss.unix_time_ >= current_time_);if (first_gnss_) {R_ = gnss.utm_pose_.so3();p_ = gnss.utm_pose_.translation();first_gnss_ = false;current_time_ = gnss.unix_time_;return true;}assert(gnss.heading_valid_);ObserveSE3(gnss.utm_pose_, options_.gnss_pos_noise_, options_.gnss_ang_noise_);current_time_ = gnss.unix_time_;return true;
}template <typename S>
bool ESKF<S>::ObserveSE3(const SE3& pose, double trans_noise, double ang_noise) {/// 既有旋转,也有平移/// 观测状态变量中的p, R,H为6x18,其余为零Eigen::Matrix<S, 6, 18> H = Eigen::Matrix<S, 6, 18>::Zero();H.template block<3, 3>(0, 0) = Mat3T::Identity();  // P部分H.template block<3, 3>(3, 6) = Mat3T::Identity();  // R部分(3.66)// 卡尔曼增益和更新过程Vec6d noise_vec;noise_vec << trans_noise, trans_noise, trans_noise, ang_noise, ang_noise, ang_noise;Mat6d V = noise_vec.asDiagonal();Eigen::Matrix<S, 18, 6> K = cov_ * H.transpose() * (H * cov_ * H.transpose() + V).inverse();// 更新x和covVec6d innov = Vec6d::Zero();innov.template head<3>() = (pose.translation() - p_);          // 平移部分innov.template tail<3>() = (R_.inverse() * pose.so3()).log();  // 旋转部分(3.67)dx_ = K * innov;cov_ = (Mat18T::Identity() - K * H) * cov_;UpdateAndReset();return true;
}

IMU预积分

  • 书中有IMU预积分所有的公式推导,包括了预积分计算公式,预积分相较于状态量的雅克比矩阵公式,误差传播公式等等

/*** IMU 预积分器** 调用Integrate来插入新的IMU读数,然后通过Get函数得到预积分的值* 雅可比也可以通过本类获得,可用于构建g2o的边类*/
class IMUPreintegration {public:EIGEN_MAKE_ALIGNED_OPERATOR_NEW/// 参数配置项/// 初始的零偏需要设置,其他可以不改struct Options {Options() {}Vec3d init_bg_ = Vec3d::Zero();  // 初始零偏Vec3d init_ba_ = Vec3d::Zero();  // 初始零偏double noise_gyro_ = 1e-2;       // 陀螺噪声,标准差double noise_acce_ = 1e-1;       // 加计噪声,标准差};IMUPreintegration(Options options = Options());/*** 插入新的IMU数据* @param imu   imu 读数* @param dt    时间差*/void Integrate(const IMU &imu, double dt);/*** 从某个起始点开始预测积分之后的状态* @param start 起始时时刻状态* @return  预测的状态*/NavStated Predict(const NavStated &start, const Vec3d &grav = Vec3d(0, 0, -9.81)) const;/// 获取修正之后的观测量,bias可以与预积分时期的不同,会有一阶修正SO3 GetDeltaRotation(const Vec3d &bg);Vec3d GetDeltaVelocity(const Vec3d &bg, const Vec3d &ba);Vec3d GetDeltaPosition(const Vec3d &bg, const Vec3d &ba);public:double dt_ = 0;                          // 整体预积分时间Mat9d cov_ = Mat9d::Zero();              // 累计噪声矩阵Mat6d noise_gyro_acce_ = Mat6d::Zero();  // 测量噪声矩阵// 零偏Vec3d bg_ = Vec3d::Zero();Vec3d ba_ = Vec3d::Zero();// 预积分观测量SO3 dR_;Vec3d dv_ = Vec3d::Zero();Vec3d dp_ = Vec3d::Zero();// 雅可比矩阵Mat3d dR_dbg_ = Mat3d::Zero();Mat3d dV_dbg_ = Mat3d::Zero();Mat3d dV_dba_ = Mat3d::Zero();Mat3d dP_dbg_ = Mat3d::Zero();Mat3d dP_dba_ = Mat3d::Zero();
};

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# winform应用

C# winform应用 需求&#xff1a;导入Excel文件时需要执行其他操作&#xff0c;实现如果取消导入就不执行其他操作 C#代码实现 private bool DLimport0(string tablename, string datebasename, string buttonname){string xxx "";string Tag "";stri…

美易官方:人工智能将推动科技股在未来十年走高

人工智能的发展和科技股的未来 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经成为当今世界最为炙手可热的话题之一。而科技股作为人工智能技术的重要载体&#xff0c;其未来的走势也备受全球投资者关注。本文将从多个角度分析人工智能对科技股的影响&…

SQL-窗口函数

什么是窗口函数 可以像聚合函数一样对一组数据进行分析并返回结果&#xff0c;二者的不同之处在于&#xff0c;窗口函数不是将一组数据汇总成单个结果&#xff0c;而是为每一行数据都返回一个结果。 窗口函数组成部分 1.创建数据分区 窗口函数OVER子句中的PARTITION BY选项用…

机器学习~从入门到精通(二)线性回归算法和多元线性回归

为什么要做数据归一化 一、数据归一化&#xff1a; 1.最值归一化 2.均值方差归一化import numpy as npX np.random.randint(1,100,size100) X X.reshape(-1,2) X.shape X np.array(X,dtypefloat) X[:,0] (X[:,0]-np.min(X[:,0]))/(np.max(X[:,0])-np.min(X[:,0])) X[:,1]…

HarmonyOS之sqlite数据库的使用

从API Version 9开始&#xff0c;鸿蒙开发中sqlite使用新接口ohos.data.relationalStore 但是 relationalStore在 getRdbStore操作时&#xff0c;在预览模式运行或者远程模拟器运行都会报错&#xff0c;导致无法使用。查了一圈说只有在真机上可以正常使用&#xff0c;因此这里…

ARM 1.12

norflash与nandflash的区别&#xff1a; 一、NAND flash和NOR flash的性能比较 1、NOR的读速度比NAND稍快一些。 2、NAND的写入速度比NOR快很多。 3、NAND的4ms擦除速度远比NOR的5s快。 4、大多数写入操作需要先进行擦除操作。 5、NAND的擦除单元更小&#xff0c;相应的擦除电…

前端下载文件流,设置返回值类型responseType:‘blob‘无效的问题

前言&#xff1a; 本是一个非常简单的请求&#xff0c;即是下载文件。通常的做法如下&#xff1a; 1.前端通过Vue Axios向后端请求&#xff0c;同时在请求中设置响应体为Blob格式。 2.后端相应前端的请求&#xff0c;同时返回Blob格式的文件给到前端&#xff08;如果没有步骤…

【安全策略】前端 JS 安全对抗浏览器调试方法

一、概念解析 1.1 什么是接口加密 如今这个时代&#xff0c;数据已经变得越来越重要&#xff0c;网页和APP是主流的数据载体。而如果获取数据的接口没有设置任何的保护措施&#xff0c;那么数据的安全性将面临极大的威胁。不仅可能造成数据的轻易窃取和篡改&#xff0c;还可能…

ArcGIS Pro 标注牵引线问题

ArcGIS Pro 标注 模仿CAD坐标牵引线问题 右键需要标注的要素&#xff0c;进入标注属性。 选择背景样式 在这里有可以选择的牵引线样式 选择这一个&#xff0c;可以根据调整间距来进行模仿CAD标注样式。 此图为cad样式 此为调整后gis样式 此处可以调整牵引线的样式符号 …

基于springboot+vue的校园管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

【Vue】路由学习中遇到的BUG

目录捏 一、TypeError: Cannot read properties of undefined(reading self)问题描述&#xff1a;原因分析&#xff1a;解决方案&#xff1a; 二、error XXX is not defined no-undef问题描述:原因分析&#xff1a;解决方案&#xff1a; 三、Error: Cannot find module babel-…

交换机配置及网络测试

实验环境 拓扑图 Ip规划表 部门 主机数量 网络地址 子网掩码 网关 可用ip Vlan 市场部 38 192.168.131.0 255.255.255.0 192.168.131.1 2-254 11 研发部 53 192.168.132.0 255.255.255.0 192.168.132.1 2-254 12 财务部 9 192.168.133.0 255.255.255…