一种简单高效的IMU姿态解算方法

news2024/11/23 3:56:27

这里给出一种简单高效的IMU姿态解算方法,本方法的特点就是思路非常的简单,并且效果也还可以,地面机器人这类运动想对不那么剧烈的应用应该是能应付的,但是震动较大的无人机、足式机器人等应用是否能应用还有待试验。

代码如下:

/**
 * @brief 姿态估计
 * 
 */
void simpleAttitudeEstimation(const msa2d::sensor::ImuData& curr_data) {
    // 第一个IMU数据不计算,只记录时间信息
    if (last_attitude_predict_time_ == 0) {
        last_attitude_predict_time_ = curr_data.time_stamp_;
        last_attitude_update_time_ = last_attitude_predict_time_;  
        return;  
    }

    const Eigen::Vector3d unbiased_gyro = curr_data.gyro_ - sensor_param_.imu_.gyro_bias_;   // 去偏置 
    const Eigen::Vector3d angle_vec = unbiased_gyro * (curr_data.time_stamp_ - last_attitude_predict_time_);
    const double angle = angle_vec.norm();
    const Eigen::Vector3d axis = angle_vec / angle;
    Eigen::Matrix3d delta_rot = Eigen::AngleAxisd(angle, axis).toRotationMatrix();
    sensor_param_.imu_.G_R_I_ = sensor_param_.imu_.G_R_I_ * delta_rot;    // 旋转矩阵姿态更新  
    last_attitude_predict_time_ = curr_data.time_stamp_;  

    /**
     * @brief 在线标定陀螺仪bias
     * 测试:使用在线标定,15min 角度最大漂移0.1rad
     * 不使用在线标定,15min角度最大漂移 0.3rad
     * @todo 为了节省计算量,采用了一种迭代的静止标定方法,局限是需要载体在静止时才会自动校准参数,
     *  改进点是如何实现高效的动态标定
     */
    imu_tool_.OnlineCalibGyroBias(unbiased_gyro, sensor_param_.imu_.gyro_bias_); 
    // 重力校正
    float acc_v = curr_data.acc_.norm();
    // 加速度不能和重力相差太大  
    if (std::fabs(acc_v - 9.8) < 0.3 * 9.8) {
        double correct_delta_t = curr_data.time_stamp_ - last_attitude_update_time_;
        // 至少间隔0.1s
        if (correct_delta_t > 0.1) {
            // 计算权重因子
            float time_ratio = 1 - std::exp(-correct_delta_t / 0.5);     // 距离上一次校正的时间间隔越大   越接近1
            // 由重力观测出姿态角
            float gravity_pitch = -std::asin(curr_data.acc_[0] / 9.81); 
            float gravity_roll = std::atan2(curr_data.acc_[1], curr_data.acc_[2]); 
            // 由陀螺仪观测出来的姿态角
            float gyro_roll_ = atan2(sensor_param_.imu_.G_R_I_(2, 1), sensor_param_.imu_.G_R_I_(2, 2));
            float gyro_pitch_ = asin(-sensor_param_.imu_.G_R_I_(2, 0));
            // 重力解算出来的结果与陀螺仪解算出来的结果相差不能太大(5度)
            // 否则由与短时间更加信任陀螺仪,所以认为重力观测不准
            if (std::fabs(gyro_roll_ - gravity_roll) < 0.08 && std::fabs(gyro_pitch_ - gravity_pitch) < 0.08) {
                //  加权融合
                float correct_pitch = time_ratio * gravity_pitch + (1 - time_ratio) * gyro_pitch_;
                float correct_roll = time_ratio * gravity_roll + (1 - time_ratio) * gyro_roll_;
                // 重新更新旋转矩阵
                sensor_param_.imu_.G_R_I_ = Eigen::AngleAxisd(0, Eigen::Vector3d::UnitZ())
                                                        * Eigen::AngleAxisd(correct_pitch, Eigen::Vector3d::UnitY())
                                                        * Eigen::AngleAxisd(correct_roll, Eigen::Vector3d::UnitX());
                last_attitude_update_time_ = curr_data.time_stamp_; 
            } 
        }
    } 
}

解析:
简单来说也是和互补滤波、KF一样的加权融合,步骤如下:
1、陀螺仪角速度测量对旋转矩阵进行更新。
2、迭代静态在线校准陀螺仪bias。
3、将重力向量观测恢复成姿态角的观测,同时将陀螺仪更新的旋转矩阵也恢复成姿态角,对这两个姿态角进行加权融合。这一步对整个系统的效果影响最为关键的,可以尝试增加各种的trick去进行优化,这里采用了两个最基本的策略,(1)、加速度向量的模长不能比重力大太多,否则这个加速度观测大概率包含了机体自身的运动加速度,这个测量值是不可用的。(2)、陀螺仪短时间准确,而长时间有累计误差,加速度计短期噪声大,而长期比较准确,因此,将校正的时间间隔作为权重的考量因素,时间过的越久,就越不相信陀螺仪的结果,而更相信重力观测的结果。(3)、除了模长外,还要考虑由重力和陀螺仪单独恢复出来的姿态角之间的差异,校正只在两个姿态角接近的时候执行,因为,在重力观测可靠时,重力恢复的姿态角和陀螺仪恢复的姿态角之间的误差很小,而当这个误差很大时,大概率是由与剧烈运动所产生的加速度噪声引起的,因此过滤掉。

试验结果:
下面是姿态角pitch的角度图,蓝色是融合后的结果,红色是加速度单独计算的结果,黄色是角速度单独计算的结果。
在这里插入图片描述静止时,可以看到加速度解算的结果有很大的噪声。

在这里插入图片描述上图是缓慢旋转抖动产生的。

在这里插入图片描述上图对应的是剧烈晃动,可以看到加速度计已经产生了巨大的噪声了,但融合后就将加速度计的噪声大部分过滤了,同时,最后静止时相比于陀螺仪的结果显著降低了稳态误差。

一些问题:

由与没有仔细调参,还是有不少问题的,如下图就没有很好的将加速度计的干扰给过滤掉。
在这里插入图片描述
剧烈运动时,给加速度的权重还是太大了,
在这里插入图片描述
总之有空还得将参数再好好调一调,不过只要不是太剧烈的运动用起来还是可以的。

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

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

相关文章

【Leetcode】(自食用)LRU算法(哈希链表法)

step by step. 题目&#xff1a; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键…

【深度学习注意力机制系列】—— CBAM注意力机制(附pytorch实现)

CBAM&#xff08;Convolutional Block Attention Module&#xff09;是一种用于增强卷积神经网络&#xff08;CNN&#xff09;性能的注意力机制模块。它由Sanghyun Woo等人在2018年的论文[1807.06521] CBAM: Convolutional Block Attention Module (arxiv.org)中提出。CBAM的主…

实现静态资源访问的几种方法

什么是静态资源&#xff1f; 静态资源是指在服务器端存储的不会变化的文件&#xff0c;如HTML、CSS、JavaScript、图片、音频、视频等文件。这些文件一般不包含动态内容&#xff0c;每次请求时返回的内容都是固定的。 为什么要使用静态资源&#xff1f; 提升网站性能&#xf…

gitblit-使用

1.登入GitBlit服务器 默认用户和密码: admin/admin 2.创建一个新的版本库 点击图中的“版本库”&#xff0c;然后点击图中“创建版本库” 填写名称和描述&#xff0c;注意名称最后一定要加 .git选择限制查看、克隆和推送勾选“加入README”和“加入.gitignore文件”在图中的1处…

kafka-2.12使用记录

kafka-2.12使用记录 安装kafka 2.12版本 下载安装包 根据你的系统下载rpm /deb /zip包等等, 这里我使用的是rpm包 安装命令 rpm -ivh kafka-2.12-1.nfs.x86_64.rpm启动内置Zookeeper 以下命令要写在同一行上 /opt/kafka-2.12/bin/zookeeper-server-start.sh /opt/kafka-2…

5.3.7.自动创建字符设备驱动的设备文件 class_create device_create

5.3.7.自动创建字符设备驱动的设备文件 5.3.7.1、问题描述&#xff1a; (1)整体流程回顾 (2)使用mknod创建设备文件的缺点 (3)能否自动生成和删除设备文件 5.3.7.2、解决方案&#xff1a;udev是PC机&#xff08;嵌入式中用的是mdev&#xff09; (1)什么是udev&#xff1f;应用层…

C语言笔记6

关于microsoft visual 的学习笔记 CtrlF5就是启动编译程序 先CtrlA进行全选&#xff0c;然后AitF8就自动的调节代码的格式 #include <stdio.h> #include <stdlib.h> int main() {//system启动程序(在一个程序中启动另外一个程序)//如果程序环境变量中找不到程序&am…

OpenCV实战(29)——视频对象追踪

OpenCV实战&#xff08;29&#xff09;——视频对象追踪 0. 前言1. 追踪视频中的对象2. 中值流追踪器算法原理3. 完整代码小结系列链接 0. 前言 我们已经学习了如何跟踪图像序列中点和像素的运动。但在多数应用中&#xff0c;通常要求追踪视频中的特定移动对象。首先确定感兴趣…

FFmpeg安装和使用

sudo apt install ffmpeg sudo apt-get install libavfilter-devcmakelist模板 CMakeLists.txt cmake_minimum_required(VERSION 3.16) project(ffmpeg_demo)# 设置ffmpeg依赖库及头文件所在目录&#xff0c;并存进指定变量 set(ffmpeg_libs_DIR /usr/lib/x86_64-linux-gnu) …

SpringBoot自动装配及run方法原理探究

自动装配 1、pom.xml spring-boot-dependencies&#xff1a;核心依赖在父工程中&#xff01;我们在写或者引入一些SpringBoot依赖的时候&#xff0c;不需要指定版本&#xff0c;就因为有这些版本仓库 1.1 其中它主要是依赖一个父工程&#xff0c;作用是管理项目的资源过滤及…

冠达管理:“高温超导”不是“室温超导”,5天4板百利电气再次澄清

短短半个月&#xff0c;“室温超导”在惊喜、质疑间回转&#xff0c;但资本市场对“超导概念股”的炒作还在进行&#xff0c;8月7日室温超导概念持续疯涨。同花顺显现&#xff0c;到8月7日收盘&#xff0c;18只超导概念股中&#xff0c;有16只股票飘红。 广东研山私募证券投资&…

如何将GPS坐标点如何网格化?

目录 题主问题&#xff1a; 解答&#xff1a; 高效判断点是否在正六边形蜂窝内的方法 代码实现&#xff1a;ArcGIS中实现指定面积蜂窝&#xff08;正六边形&#xff09;方法 碰巧自己前段时间处理过类似的数据&#xff0c;讲一下自己的解决思路。 题主问题&#xff1a; 解…

【小练习】交互式网格自定义增删改(进行中)

学习SQL和PLISQL数据类型的区别和应用场景 Oracle plsql 基础篇1 数据类型以及流程控制_bb_tarek的博客-CSDN博客https://blog.csdn.net/bb_tarek/article/details/17555713?ops_request_misc&request_id&biz_id102&utm_termplsql%E5%9F%BA%E6%9C%AC%E6%95%B0%E6…

9.异常

文章目录 9.1 Java 异常类层次结构图9.2 Throwable 类常用方法9.3 try-catch-finally9.4使用 try-with-resources 来代替try-catch-finally 9.1 Java 异常类层次结构图 在 Java 中&#xff0c;所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable 类有两个…

CentOS安装Postgresql

PG基本安装步骤 安装postgresql&#xff1a; sudo yum install postgresql-server初始化数据库&#xff1a;安装完毕后&#xff0c;需要初始化数据库并创建初始用户&#xff1a; sudo postgresql-setup initdb启动和停止服务&#xff1a; sudo systemctl start postgresql sudo…

06微服务间的通信方式

一句话导读 微服务设计的一个挑战就是服务间的通信问题&#xff0c;服务间通信理论上可以归结为进程间通信&#xff0c;进程可以是同一个机器上的&#xff0c;也可以是不同机器的。服务可以使用同步请求响应机制通信&#xff0c;也可以使用异步的基于消息中间件间的通信机制。同…

【TS第三讲】完善TS开发环境

文章目录 &#x1f31f; 写在前面&#x1f31f; ts-node&#x1f31f; nodemon&#x1f31f; nodemon文件类型&#x1f31f; nodemon文件范围&#x1f31f; 写在最后 &#x1f31f; 写在前面 &#x1f525;探索TypeScript世界&#xff0c;驭Vue3Ts潮流&#xff0c;开启前端之旅…

【Ubuntu】简化反向代理和个性化标签页体验

本文将介绍如何使用Docker部署Nginx Proxy Manager和OneNav&#xff0c;两个功能强大且易用的工具。Nginx Proxy Manager用于简化和管理Nginx反向代理服务器的配置&#xff0c;而OneNav则提供个性化的新标签页体验和导航功能。通过本文的指导&#xff0c;您将学习如何安装和配置…

【打印整数二进制的奇数位和偶数位】

打印整数二进制的奇数位和偶数位 1.题目 获取一个整数二进制序列中所有的偶数位和奇数位&#xff0c;分别打印出二进制序列 2.题目分析 打印一个整数的二进制位中的偶数位和奇数位&#xff0c;可以对整数进行移位操作&#xff0c;再将移位的二进制位与1进行&操作。 按位&a…

HarmonyOS/OpenHarmony应用开发-ArkTS语言渲染控制概述

ArkUI通过自定义组件的build()函数和builder装饰器中的声明式UI描述语句构建相应的UI。 在声明式描述语句中开发者除了使用系统组件外&#xff0c;还可以使用渲染控制语句来辅助UI的构建&#xff0c;这些渲染控制语句包括控制组件是否显示的条件渲染语句&#xff0c;基于数组数…