惯导系统静止初始化方法与代码实现并在gazebo中测试

惯导系统静止初始化方法与代码实现并在gazebo中测试

  • 前言
  • 静止初始化方法
  • 惯导静止初始化实现代码
  • 在gazebo中进行测试

在这里插入图片描述

前言

在进行GPS加IMU的组合导航或者Lidar加IMU的组合导航时,用EKF或者ESKF的滤波方法时,需要提前知道惯导的测量噪声、初始零偏、重力方向等信息。

此时就需要对惯导进行一个初始化,来获取以上信息,常见的初始化方法为静止初始化法。例如无人机在上电后要进行自检,此时需要无人机静止一段时间,通过指示灯来提示自检是否完毕,在静止的过程中,则对惯导进行了初始化的方法。

静止初始化方法

在传统组合导航系统中,最常见的是使用静止初始化方法。

静止初始化就是把IMU放在某个地方静止一段时间。在静止时间内,由于物体本身没有任何运动,可以简单地认为IMU的陀螺仪只测到零偏,而加速度计则测到零偏与重力之和。

可以设置一个静止初始化流程来获取这些变量:
1、将IMU静止一段时间,比如10s。静止状态检测可以由轮速计进行判断,当两轮的轮速均小于阈值时,认为机器人静止。在没有轮速计的机器人上,也可以直接认为机器人静止,来测定相关变量。
2、统计静止时间内的陀螺仪与加速度计读数均值,记为 d ˉ g y r , d ˉ a c c \bar{d} _{gyr},\bar{d} _{acc} dˉgyr,dˉacc
3、由于机器人并未发生转动,这段时间的陀螺仪均值可以取 b g = d ˉ g y r b_{g}=\bar{d} _{gyr} bg=dˉgyr
4、加速度的测量方程为
在这里插入图片描述
当机器人的实际加速度为零,旋转视为R=I时,加速度实际测到 b a − g b_{a}-g bag,其中 b a b_{a} ba为小量,g的长度可视为固定值。
在这些前提下,取方向为 − d ˉ a c c -\bar{d} _{acc} dˉacc,大小为9.8的矢量作为重力矢量,这一步确定了重力的朝向。
5、将这段时间的加速度计读数去掉重力,重新计算 d ˉ a c c \bar{d} _{acc} dˉacc
6、取 b a = d ˉ a c c b_{a}=\bar{d} _{acc} ba=dˉacc
7、认为零偏不动,估计陀螺仪和加速度计的测量方差。该方差可用于ESKF的噪声参数

惯导静止初始化实现代码

声明静态惯导初始化的类

IMU水平静止状态下初始化器
使用方法:调用AddIMU, AddOdom添加数据,使用InitSuccess获取初始化是否成功
成功后,使用各Get函数获取内部参数

class StaticIMUInit {

下面为类的具体内容
++++++++++++++++++++++++++++++++++++++++++++++++++++

    //  可配置参数结构struct Options {Options() {}double init_time_seconds_ = 10.0;     // 静止时间int init_imu_queue_max_size_ = 2000;  // 初始化IMU队列最大长度int static_odom_pulse_ = 5;           // 静止时轮速计输出噪声double max_static_gyro_var = 0.5;     // 静态下陀螺测量方差double max_static_acce_var = 0.05;    // 静态下加计测量方差double gravity_norm_ = 9.81;          // 重力大小bool use_speed_for_static_checking_ = true;  // 是否使用odom来判断车辆静止(部分数据集没有odom选项)};

公共变量区,设置可配置参数结构体

具体参数:

  • 静止时间(采集这么长时间数据后进行初始化)
  • 初始化IMU队列最大长度(如在设置的静止时间内,队列满,再来数据则逐步省略掉最早的数据)
  • 静止时轮速计输出噪声(轮速计输出小于此值认为静止)
  • 静止下陀螺和加计测量方差最大值(计算结果大于此值则认为计算失败)
  • 重力大小
  • 是否使用odom来判断车辆静止

++++++++++++++++++++++++++++++++++++++++++++++++++++

    /// 判定初始化是否成功bool InitSuccess() const { return init_success_; }/// 获取各Cov, bias, gravityVec3d GetCovGyro() const { return cov_gyro_; }Vec3d GetCovAcce() const { return cov_acce_; }Vec3d GetInitBg() const { return init_bg_; }Vec3d GetInitBa() const { return init_ba_; }Vec3d GetGravity() const { return gravity_; }

获得计算的 方差、零偏、重力等

++++++++++++++++++++++++++++++++++++++++++++++++++++
私有变量区声明,要用到的变量

    Options options_;                 // 选项信息bool init_success_ = false;       // 初始化是否成功Vec3d cov_gyro_ = Vec3d::Zero();  // 陀螺测量噪声协方差(初始化时评估)Vec3d cov_acce_ = Vec3d::Zero();  // 加计测量噪声协方差(初始化时评估)Vec3d init_bg_ = Vec3d::Zero();   // 陀螺初始零偏Vec3d init_ba_ = Vec3d::Zero();   // 加计初始零偏Vec3d gravity_ = Vec3d::Zero();   // 重力bool is_static_ = false;          // 标志车辆是否静止std::deque<IMU> init_imu_deque_;  // 初始化用的数据double current_time_ = 0.0;       // 当前时间double init_start_time_ = 0.0;    // 静止的初始时间

下面来看各实现函数
++++++++++++++++++++++++++++++++++++++++++++++++++++
当惯导数据来时,添加惯导数据

如果已经初始化成功则直接返回

bool StaticIMUInit::AddIMU(const IMU& imu) {if (init_success_) {return true;}

通过轮速计判断机器人 没有静止 ,则将用于初始化的惯导数据队列清空

    if (options_.use_speed_for_static_checking_ && !is_static_) {LOG(WARNING) << "等待静止";init_imu_deque_.clear();return false;}

如果惯导数据队列为空,那么则刚进入静止状态,记录初始静止时间

    if (init_imu_deque_.empty()) {// 记录初始静止时间init_start_time_ = imu.timestamp_;}

将数据加如用于初始化的imu队列数据

    // 记入初始化队列init_imu_deque_.push_back(imu);

计算静止时间数据有了多久

double init_time = imu.timestamp_ - init_start_time_;  // 初始化经过时间

如果时间大于了设定值,那么则用采集好的数据进入初始化函数

    if (init_time > options_.init_time_seconds_) {// 尝试初始化逻辑TryInit();}

时间没够,但是数据大于了设定队列长度,则删除掉队列最前数据

    // 维持初始化队列长度while (init_imu_deque_.size() > options_.init_imu_queue_max_size_) {init_imu_deque_.pop_front();}

运行到这则说明,静止的时间还没够,更新当前时间,整体函数返回false

   current_time_ = imu.timestamp_;return false;

++++++++++++++++++++++++++++++++++++++++++++++++++++
下面是轮速计数据来时的操作函数

bool StaticIMUInit::AddOdom(const Odom& odom) {// 判断车辆是否静止if (init_success_) {return true;}if (odom.left_pulse_ < options_.static_odom_pulse_ && odom.right_pulse_ < options_.static_odom_pulse_) {is_static_ = true;} else {is_static_ = false;}current_time_ = odom.timestamp_;return true;
}

主要就是根据数据,判断是否静止,将标志位进行设置

++++++++++++++++++++++++++++++++++++++++++++++++++++
然后就是当静止时间够后,进入的初始化函数

如果队列数据太短,则无法进行初始化

bool StaticIMUInit::TryInit() {if (init_imu_deque_.size() < 10) {return false;}

声明 陀螺和加计的均值

Vec3d mean_gyro, mean_acce;

下面则计算均值和协方差

math::ComputeMeanAndCovDiag(init_imu_deque_, mean_gyro, cov_gyro_, [](const IMU& imu) { return imu.gyro_; });
math::ComputeMeanAndCovDiag(init_imu_deque_, mean_acce, cov_acce_, [this](const IMU& imu) { return imu.acce_; });

这里主要调用了数学库中的均值与协方差计算函数

++++++++++++++++++++++++++++++++++++++++++++++++++++

    LOG(INFO) << "mean acce: " << mean_acce.transpose();gravity_ = -mean_acce / mean_acce.norm() * options_.gravity_norm_;

以acce均值为方向,取9.8长度为重力

将加计读数减去重力,重新计算协方差

    // 重新计算加计的协方差math::ComputeMeanAndCovDiag(init_imu_deque_, mean_acce, cov_acce_,[this](const IMU& imu) { return imu.acce_ + gravity_; });

检测 计算的 IMU 噪声是否过大,过大则 直接返回 false

    // 检查IMU噪声if (cov_gyro_.norm() > options_.max_static_gyro_var) {LOG(ERROR) << "陀螺仪测量噪声太大" << cov_gyro_.norm() << " > " << options_.max_static_gyro_var;return false;}if (cov_acce_.norm() > options_.max_static_acce_var) {LOG(ERROR) << "加计测量噪声太大" << cov_acce_.norm() << " > " << options_.max_static_acce_var;return false;}

赋值IMU零偏

    init_bg_ = mean_gyro;init_ba_ = mean_acce;

至此初始成功,函数返回true

    init_success_ = true;return true;
}

在gazebo中进行测试

为了在gazebo中测试上面的代码,在无人机的测试环境中进行,用无人机的IMU,进行测试,所以需要在类的定义中,加入对无人机IMU的订阅话题,然后在回调函数中调用上面的代码函数。

        // 将ros的imu格式的数据 转为 设置的imu格式的数据sad::IMU imu;imu.timestamp_ = Imu_msg->header.stamp.toSec();imu.gyro_ << Imu_msg->angular_velocity.x,Imu_msg->angular_velocity.y,Imu_msg->angular_velocity.z;imu.acce_ << Imu_msg->linear_acceleration.x,Imu_msg->linear_acceleration.y,Imu_msg->linear_acceleration.z;//添加IMU数据,时间够了则自动进行计算AddIMU(imu);

由于上面方法函数已经写好,所以测试函数就比较简单,上面就是将ros的imu格式的数据 转为 设置的imu格式的数据
下面就是添加IMU数据,时间够了则自动进行计算。

计算的结果在上面的实现函数中,直接打印在终端,可以查看

编译完代码,则可以进行测试。

启动无人机仿真环境:
在这里插入图片描述
无人机在地面静止

启动测试代码
终端输出

I0307 10:13:05.245363 49670 static_imu_init.cc:73] mean acce: -0.220884 -0.193247 009.92608
I0307 10:13:05.245481 49670 static_imu_init.cc:95] IMU 初始化成功,初始化时间= 10, bg = 0-0.00141685 000.00568429 -1.93852e-05, ba = -0.00267846 -0.00234334 0000.120365, gyro sq = 1.13541e-05 1.16579e-05 1.17825e-05, acce sq = 0.00150067 0.00157587 0.00172446, grav = 0.218205 0.190904 -9.80571, norm: 9.81
I0307 10:13:05.245513 49670 static_imu_init.cc:99] mean gyro: 0-0.00141685 000.00568429 -1.93852e-05 acce: -0.00267846 -0.00234334 0000.120365
在这里插入图片描述

通过打印信息可以看到得到的初始化测量结果:

  • 陀螺仪零偏:0.00141 0.00568 -1.93852e-05
  • 加速度计零偏:-0.00267846 -0.00234334 0.120365
  • 陀螺仪测量噪声:1.13541e-05 1.16579e-05 1.17825e-05
  • 加速度计测量噪声:0.00150067 0.00157587 0.00172446
  • 重力矢量:0.218205 0.190904 -9.80571
  • 重力模长:9.81

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

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

相关文章

POJO简介

文章目录 简介POJO与ELB的区别POJO真正的意思 常见的POJO类DTODAOPOVOEntity 简介 什么是POJO&#xff1f;POJO&#xff08;Plain Ordinary Java Object&#xff09;简单的Java对象&#xff0c;实际就是普通JavaBeans&#xff0c;是为了避免和EJB(EJB是Enterprise Java Beans技…

Ubuntu 22.04 Nvidia Audio2Face Error:Failed to build TensorRT engine

背景 1.在Ubuntu22.04上安装Audio2Face后启动&#xff0c;嘴形不会实时同步。控制台显示如【图一】&#xff1a; 【图一】 2.log日志如下: Error: Error during running command: [‘/home/admin/omniverse/libs/deps/321b626abba810c3f8d1dd4d247d2967/exts/omni.audio2fac…

【论文阅读】DiffSpeaker: Speech-Driven 3D Facial Animation with Diffusion Transformer

DiffSpeaker: 使用扩散Transformer进行语音驱动的3D面部动画 code&#xff1a;GitHub - theEricMa/DiffSpeaker: This is the official repository for DiffSpeaker: Speech-Driven 3D Facial Animation with Diffusion Transformer paper&#xff1a;https://arxiv.org/pdf/…

clickhouse学习笔记01(小滴课堂)

老王经历-数据库架构演变历史 你是否能分清OLTP和OLAP系统 急速掌握-数据库里面行存储和列式存储 新一代列式存储ClickHouse介绍和应用场景说明 Linux服务器容器化部署ClickHouse实战 记得要在安全组里配置开放端口号。 到这我们就安装完了。 简单使用&#xff1a; 创建你的第…

鲲鹏920集成100G网卡RDMA测试说明

1、背景介绍 目前鲲鹏920处理器内集成了两个100G网卡&#xff0c;支持RDMA&#xff08;Roce V2&#xff09;&#xff0c;说明如下 为了测试网卡性能&#xff0c;需要进行RDMA测试&#xff0c;两块鲲鹏920的板卡通过盛科的8180 100G交换芯片实现交换功能。 盛科8180芯片介绍如下…

2.亿级积分数据分库分表:增量数据同步之代码双写,为什么没用Canal?

1.亿级积分数据分库分表&#xff1a;总体方案设计 上一篇博客中写了一下积分数据分库分表的总体方案设计&#xff0c;里面说了采用应用程序代码双写的方式实现的增量数据同步&#xff0c;本篇就对这一块进行一些细化的介绍&#xff0c;包括&#xff1a; 为什么不用Canal监听数…

【S5PV210】 | GPIO编程

【S5PV210】 | GPIO编程 时间:2024年3月17日22:02:32 目录 [TOC] 1.参考 1.s5pv210开发与学习:1.5之裸机汇编流水点灯_s5pv210汇编指令集-CSDN博客 2.s5pv210开发与学习:1.8之裸机蜂鸣器实验_pv210 蜂鸣器-CSDN博客 3.s5pv210开发与学习:1.9之裸机按键控制LED_s5pv210 按键…

机器学习——压缩网络作业

文章目录 任务描述介绍知识蒸馏网络设计 Baseline实践 任务描述 网络压缩&#xff1a;使用小模型模拟大模型的预测/准确性。在这个任务中&#xff0c;需要训练一个非常小的模型来完成HW3&#xff0c;即在food-11数据集上进行分类。 介绍 有许多种网络/模型压缩的类型&#xff0…

代码随想录day23(2)二叉树:从中序与后序遍历序列构造二叉树(leetcode106)

题目要求&#xff1a;根据一棵树的中序遍历与后序遍历构造二叉树。 思路&#xff1a;408的经典题目&#xff0c;思路和手撕的思路差不多&#xff0c;先从后序中找到根节点&#xff0c;再从中序中找到此节点&#xff0c;然后分割成左右子树&#xff0c;记录一下左右子树的节点个…

PyQt5使用

安装Pyqt5信号与槽使用可视化界面编辑UI (Pyside2)ui生成之后的使用(两种方法)1 ui转化为py文件 进行import2 动态调用UI文件 安装Pyqt5 pip install pyqt5-tools这时候我们使用纯代码实现一个简单的界面 from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButto…

2024 年(第 12 届)“泰迪杯”数据挖掘挑战赛——B 题:基于多模态特征融合的图像文本检索完整思路与源代码分享

一、问题背景 随着近年来智能终端设备和多媒体社交网络平台的飞速发展&#xff0c;多媒体数据呈现海量增长 的趋势&#xff0c;使当今主流的社交网络平台充斥着海量的文本、图像等多模态媒体数据&#xff0c;也使得人 们对不同模态数据之间互相检索的需求不断增加。有效的信…

Rocket MQ 从入门到实践

为什么要使用消息队列&#xff0c;解决什么问题&#xff1f;&#xff08;消峰、解藕、异步&#xff09; 消峰填谷 客户端》 网关 〉 消息队列》秒杀服务 异步解耦 消息队列中的重要概念理解。&#xff08;主题、消费组、队列&#xff0c;游标&#xff1f;&#xff09; 主题&…

新手向-从VNCTF2024的一道题学习QEMU Escape

[F] 说在前面 本文的草稿是边打边学边写出来的&#xff0c;文章思路会与一个“刚打完用户态 pwn 题就去打 QEMU Escape ”的人的思路相似&#xff0c;在分析结束以后我又在部分比较模糊的地方加入了一些补充&#xff0c;因此阅读起来可能会相对轻松&#xff08;当然也不排除这是…

Transformer总结

1.Transform背景介绍 1.1Transform的优势 相比于之前占领市场的LSTM和GRU模型&#xff0c;Transformer有两个显著的优势&#xff1a; &#xff08;1&#xff09;Transform能够使用分布式GPU进行并行训练&#xff0c;提升模型训练效率 &#xff08;2&#xff09; 在分析预测…

zookeeper基础学习之六: zookeeper java客户端curator

简介 Curator是Netflix公司开源的一套zookeeper客户端框架&#xff0c;解决了很多Zookeeper客户端非常底层的细节开发工作&#xff0c;包括连接重连、反复注册Watcher和NodeExistsException异常等等。Patrixck Hunt&#xff08;Zookeeper&#xff09;以一句“Guava is to Java…

【算法刷题 | 数组】3.12(二分查找、移除元素、有序数组的平方、长度最小的子数组、螺旋矩阵2)

文章目录 1.二分查找1.1题目1.2思路&#xff08;核心&#xff1a;区间的定义&#xff09;1.3左闭右闭1.4左闭右开1.5总结 2.移除元素2.1题目2.1思路2.2.1暴力解法2.2.2双指针法 23总结 3.有序数组的平方3.1题目3.2思路3.2.1暴力解法3.2.2双指针法 4.长度最小的子数组4.1题目4.2…

Linux中文件和目录管理(创建删除移动复制)

目录 1——一次建立一个或多个目录&#xff1a;mkdir ​2——创建一个空文件&#xff1a;touch 3——移动和重命名&#xff1a;mv 4——复制文件和目录&#xff1a;cp 5—— 删除目录和文件&#xff1a;rmdir和rm 在学习文件与目录的管理的一些命令之前&#xff0c;我们先…

深度学习-面经(part2、CNN)

2 CNN 对图像&#xff08;不同的数据窗口数据&#xff09;和滤波矩阵做内积&#xff08;逐个元素相乘再求和&#xff09;的操作就是所谓的『卷积』操作。 卷积神经网络由输入层、卷积层、激励层、池化层、全连接层组成。 ① 最左边: 数据输入层&#xff0c;对数据做一些处理…

数字后端 EDA 软件分享

数字后端 EDA 软件分享 推荐这几家的EDA工具吧&#xff0c;虽说我也支持国产工具&#xff0c;但是我还是选择了这几家的工具 apache cadence mentor synopsys 下图我现在用的eda环境&#xff0c;利用网上的资源&#xff0c;自己独立在vmware上搭建好的EDA环境 除去pdk&#…

从政府工作报告探究计算机行业发展

从政府工作报告探计算机行业发展 政府工作报告作为政府工作的全面总结和未来规划&#xff0c;不仅反映了国家整体的发展态势&#xff0c;也为各行各业提供了发展的指引和参考。随着信息技术的快速发展&#xff0c;计算机行业已经成为推动经济社会发展的重要引擎之一。因此&…