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

news2025/1/12 13:36:24

惯导系统静止初始化方法与代码实现并在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, gravity
    Vec3d 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.coloradmin.cn/o/1524142.html

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

相关文章

Mysql 索引、锁与MVCC等相关知识点

文章目录 Mysql锁的类型锁使用MVCC快照读和当前读读视图【Read View】串行化的解决 索引类型存储方式区分逻辑区分实际使用区分索引失效情况 索引建立规范SQL编写规范exlpain字段解析ACID的原理日志引擎慢SQL整合SpringBoot博客记录 Mysql锁的类型 MySQL中有哪些锁&#xff1a…

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

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

如何写好Stable Diffusion的prompt

Stable Diffusion是一种强大的文本到图像生成模型&#xff0c;其效果在很大程度上取决于输入的提示词&#xff08;Prompt&#xff09;。以下是一些关于如何编写有效的Stable Diffusion Prompt的秘诀&#xff1a; 明确描述&#xff1a;尽量清晰地描述你想要的图像内容。使用具体…

3.4 bp,si,di寄存器,寻址方式,寄存器总结

汇编语言 1. [bxidata] 我们可以用[bx]来指明一个内存单元我们也可以用[bxidata]来表示一个内存单元&#xff0c;它的偏移地址为bx中的数值加上idata mount c d:masm c: debug r d 2000:1000 e 2000:1000 12 34 56 78 a mov ax,2000 mov ds,ax mov bx,1000 mov ax,[bx] mov c…

训练YOLOv8m时AMP显示v8n

在训练Yolov8模型时&#xff0c;使用AMP&#xff08;Automatic Mixed Precision&#xff09;可以加速训练过程并减少显存的使用。AMP是一种混合精度训练技术&#xff0c;它通过将模型参数的计算转换为低精度&#xff08;如半精度&#xff09;来提高训练速度&#xff0c;同时保持…

llama笔记:官方示例解析 example_chat_completion.py

1 导入库 from typing import List, Optional从typing模块中导入List和Optional。typing模块用于提供类型注解的支持&#xff0c;以帮助明确函数预期接收和返回的数据类型。List用于指定列表类型Optional用于指定一个变量可能是某个类型&#xff0c;也可能是None。 import fir…

Visual Studio 2022下配置 OpenMP 多线程编程环境与运行

目录 一创建项目时选择“创建新项目 -> 空项目 -> 下一步 -> 创建” 二右键“源文件 -> 添加 -> 新建项 -> 添加” 三配置 1. 测试程序&#xff1a; 最开始的时候错误很多&#xff1a; 2.将 “ include "stdafx.h" ” 删掉&#xff0c;添加 “…

4.1_6 文件的基本操作

文章目录 4.1_6 文件的基本操作&#xff08;一&#xff09;创建文件&#xff08;二&#xff09;删除文件&#xff08;三&#xff09;打开文件&#xff08;四&#xff09;关闭文件&#xff08;五&#xff09;读文件&#xff08;六&#xff09;写文件 总结 4.1_6 文件的基本操作 …

uni-app开发特点和开发流程

uni-app是一个基于Vue.js框架的跨平台应用开发框架&#xff0c;通过一套代码可以同时运行在多个平台上&#xff0c;包括iOS、Android、H5等。它采用了基于流布局的页面渲染机制&#xff0c;可以自动适配不同平台的屏幕尺寸和分辨率。uniapp官网&#xff1a;https://uniapp.dclo…

2024-03-17悠然-思源茶社申时茶会有感

悠悠白云里&#xff0c;独住青山客&#xff1b; 然灯松林静&#xff0c;煮茗柴门香&#xff1b; 思归若汾水&#xff0c;无日不悠悠&#xff1b; 源上花初发&#xff0c;公应日日来&#xff1b; 申章写深谊&#xff0c;唯愿长相聚&#xff1b; 时时思己过&#xff0c;刻刻…

图鸟UI发布免费开源、高颜值小程序UI框架

大家好&#xff0c;今天分享的主题是图表统计。图表统计是使用图表和图形来可视化和呈现数据的方法。它通过将数据转化为柱状图、折线图、饼图等形式来展示各种统计指标和趋势。 图表统计可以帮助我们更好地理解和分析数据&#xff0c;发现数据之间的关联和规律&#xff0c;并…

四、自然语言中的生成式任务

目录 4.0 机器翻译 4.1 文本摘要 4.1.1 抽取式摘要 4.2.2 生成式摘要 NLP学习笔记系列&#xff0c;欢迎收藏交流&#xff1a; 零、自然语言处理开篇-CSDN博客 一、NLP中的文本分类-CSDN博客 二、NLP中的序列标注&#xff08;分词、主体识别&#xff09;-CSDN博客 三、NL…

基于单片机的IC 卡门禁系统设计

摘要:针对传统门锁钥匙易丢失、配置不便和忘记携带等问题,提出了一种基于STC89C52 的IC 卡门禁系统设计。该系统以STC89C52 单片机为核心来控制电子锁模块的开关。主要过程是由RFID 模块读取IC卡ID 并通过串口发送至STC89C52 单片机模块,STC89C52 单片机模块可以实现在线对I…

使用广度优先搜索算法找到最短路径,然后绘制路径图

使用广度优先搜索算法找到最短路径&#xff0c;然后绘制路径图 from collections import deque import matplotlib.pyplot as plt# 定义网格环境的参数 GRID_SIZE 5 GRID_WIDTH 4 AGENT_SPEED 2 START_STATE (0, 0) GOAL_STATE (GRID_SIZE - 1, GRID_SIZE - 1)# 定义动作…

Excel小技巧 (4) - Sumif用法

学期末&#xff0c;根据以下表格如果要汇总学生的三门主课分数&#xff0c;如何能快速的汇总呢&#xff1f; sumif就是一个很好用的函数 SUMIF&#xff08;指定汇总的key范围&#xff0c;汇总值&#xff0c;合计范围&#xff09;

记录windiwos系统安装homestead环境的一次报错

相关软件版本 VirtualBox 7.0.14Vagrant 2.3.8 报错信息如下 Bringing machine homestead up with virtualbox provider... > homestead: Box lc/homestead could not be found. Attempting to find and install...homestead: Box Provider: virtualboxhomestead: Box Ve…

从电影《沙丘》说起——对人工智能的思考

从《沙丘》开始说起 之前看《沙丘》电影&#xff0c;里面有一类角色叫门泰特&#xff0c;这类人大脑可以飞快地运算&#xff0c;在电影设定里是替换人工智能、机器运算的存在。男主保罗也是这类型的人&#xff0c;但他可能基因更强大&#xff0c;吸食了香料后&#xff0c;他的…

力扣题目训练(22)

2024年2月15日力扣题目训练 2024年2月15日力扣题目训练563. 二叉树的坡度637. 二叉树的层平均值643. 子数组最大平均数 I304. 二维区域和检索 - 矩阵不可变154. 寻找旋转排序数组中的最小值 II 2024年2月15日力扣题目训练 2024年2月15日第二十二天编程训练&#xff0c;今天主要…

Qt for Mac阻止MacOS系统休眠

Qt开发的应用程序如果电脑休眠了会影响软件的使用&#xff0c;因此在软件的使用过程中需要防止电脑休眠&#xff0c;在Win上有专门的API进行处理&#xff0c;在Mac上也必需使用Mac平台自身的API&#xff0c;本篇介绍在Mac平台下使用Qt阻止Mac系统休眠。 要调用Mac系统的API&am…

【开发】Spring整合MyBatis、MyBatisPlus

目录 前言 Spring整合MyBatis 1. 在项目中的pom.xml中导入MyBatis和Spring相关的依赖&#xff1a; 2. 配置数据源 3. 编写实体类 4. 编写API接口 5. 编写单元测试方法&#xff08;业务&#xff09; Spring整合MyBatis-Plus 1. 在项目中导入依赖&#xff1a; 2. 配置数…