卡尔曼滤波器融合六轴IMU数据

news2024/11/19 3:37:50

卡尔曼滤波

卡尔曼滤波是一种常用的状态估计方法,其基本原理是对系统状态进行最优估计。其主要思想是将系统的状态分为先验状态和后验状态,通过将先验状态和观测值进行加权平均,得到最优估计状态

卡尔曼滤波增益的计算是使后验误差协方差矩阵对角线上元素和(迹)最小(协方差最小)

卡尔曼滤波假设系统状态和测量噪声都服从零均值的高斯分布,也就是正态分布的期望值为0。这是因为卡尔曼滤波是一种线性高斯滤波器,它假设噪声是零均值的高斯白噪声,并且系统状态的转移和测量模型都是线性的。在实际应用中,通常可以通过对干扰的均值进行估计,然后进行补偿处理,从而使得干扰的期望值为零。

系统建模

由现代控制理论知识可知:

其中A是状态转移矩阵,B是输入矩阵,H是观测矩阵。

W_{k}过程噪声,符合正态分布,期望为0,协方差矩阵为Q

V_{k}测量噪声,符合正态分布,期望为0,协方差矩阵为R


将模型考虑到卡尔曼滤波方程中:

\hat{X{_{k}^{-}}}为系统状态的先验估计,根据上一时刻的估计值计算。

注意:

  • 系统建模的噪声W_{k}V_{k}不会直接出现,而是QR分别代表系统噪声协方差矩阵和观测噪声协方差矩阵。
  • 这里的Z_{k}成为了观测值(就是实际计算中的一个输入,会与预测系统状态做比较)。

五大公式:

预测方程2个

\hat{X{_{k}^{-}}} 是先验状态估计,A是状态转移矩阵,B是输入矩阵,\hat{X_{k-1}}是上一时刻状态估计,P_{k}^{-}是先验误差协方差矩阵,Q是系统噪声协方差矩阵。

更新方程3个

  1. 卡尔曼增益方程:
  2. 误差协方差矩阵更新方程:

或者等价简化为如下公式:

  1. 状态量更新方程:

实例:六轴加速度陀螺仪姿态解算

 融合三轴加速度和三轴角速度

  • 对3轴角速度建模,构建2个预测方程。
  • 对3轴加速度进行观测

系统建模

状态量\begin{bmatrix} rool_-gyro \\ pitch_-gyro \\yaw_-gyro \end{bmatrix}是由角速度计算出的姿态角 。

状态转移矩阵\begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0\\ 0 & 0 & 1 \end{bmatrix},输入是角速度\begin{bmatrix} gyro_-x \\ gyro_-y \\gyro_-z \end{bmatrix}

\begin{bmatrix} roll_-acc \\ pitch_-acc \\ yaw_-acc \end{bmatrix} 加速度计算的姿态角,对应Z_{k}观测值

\begin{bmatrix} roll_-esti_k \\ pitch_-esti_k \\ yaw_-esti_k \end{bmatrix}为先验估计状态量和观测量计算得到,对应\hat{X_{k}}估计值

五个方程的计算

 根据建模内容,可以知道:

A = \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0\\ 0 & 0 & 1 \end{bmatrix}B = \begin{bmatrix} \Delta t & 0 & 0 \\ 0 & \Delta t & 0\\ 0 & 0 & \Delta t \end{bmatrix},其中\Delta t为两次循环时间计算间隔。

u_k = \begin{bmatrix} gyro_-x \\ gyro_-y \\gyro_-z \end{bmatrix} 为3轴角速度,\hat{x_k^-} = \begin{bmatrix} rool_-gyro_k^- \\ pitch_-gyro_k^- \\yaw_-gyro_k^- \end{bmatrix}为先验状态估计






初始化值

 

 


代码:源代码

#pragma once

#include <Eigen/Core>
#include <Eigen/Dense>
#include <cmath>

// @input:
//   time: time stamp (s)
//   acc_*: accelerate (m/s^2) actually the unit is not important
//   gyro_*: gyroscope (rad/s)
// @Output:
//   Eigen::Vector3<T> : roll pitch yaw (rad/s)
template <typename Time, typename T>
inline Eigen::Vector3<T> KF_6_Axis(Time time, T acc_x, T acc_y, T acc_z,
                                   T gyro_x, T gyro_y, T gyro_z) {
  static Eigen::Matrix<T, 3, 3> Q = decltype(Q)::Identity();
  Q << 0.002, 0, 0, 0, 0.002, 0, 0, 0, 0.002;
  static Eigen::Matrix<T, 3, 3> R = decltype(R)::Identity();
  R << 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2;

  static Eigen::Matrix<T, 3, 3> A = decltype(A)::Identity();
  static Eigen::Matrix<T, 3, 3> B = decltype(B)::Identity();
  static Eigen::Matrix<T, 3, 3> H = decltype(H)::Identity();
  H << 1, 0, 0, 0, 1, 0, 0, 0, 0;

  static Eigen::Vector3<T> X_bar_k_1 = decltype(X_bar_k_1)::Zero();
  static Eigen::Vector3<T> u_k = decltype(u_k)::Zero();
  static Eigen::Vector3<T> X_bar_k__ = decltype(X_bar_k__)::Zero();
  static Eigen::Vector3<T> X_bar_k = decltype(X_bar_k)::Zero();
  static Eigen::Vector3<T> Z_k = decltype(Z_k)::Zero();
  static Eigen::Matrix<T, 3, 3> P_k_1 = decltype(P_k_1)::Zero();
  static Eigen::Matrix<T, 3, 3> P_k__ = decltype(P_k__)::Zero();
  static Eigen::Matrix<T, 3, 3> P_k = decltype(P_k)::Identity();
  static Eigen::Matrix<T, 3, 3> K_k = decltype(K_k)::Zero();
  static Eigen::Matrix<T, 3, 3> I = decltype(I)::Identity();

  /*计算微分时间*/
  static Time last_time;           // 上一次采样时间(s)
  double dt = (time - last_time);  // 微分时间(s)
  last_time = time;

  B = decltype(B)::Identity() * dt;
  /*计算x,y轴上的角速度*/
  T droll_dt =
      gyro_x +
      ((sin(X_bar_k(1)) * sin(X_bar_k(0))) / cos(X_bar_k(1))) * gyro_y +
      ((sin(X_bar_k(1)) * cos(X_bar_k(0))) / cos(X_bar_k(1))) *
          gyro_z;  // roll轴的角速度
  T dpitch_dt =
      cos(X_bar_k(0)) * gyro_y - sin(X_bar_k(0)) * gyro_z;  // pitch轴的角速度
  T dyaw_dt = sin(X_bar_k(0)) / cos(X_bar_k(1)) * gyro_y +
              cos(X_bar_k(0)) / cos(X_bar_k(1)) * gyro_z;

  u_k(0) = droll_dt;
  u_k(1) = dpitch_dt;
  u_k(2) = dyaw_dt;

  // 第一步计算 状态外推方程
  X_bar_k__ = A * X_bar_k_1 + B * u_k;
  // 第二步计算 协方差外推方程
  P_k__ = A * P_k_1 * A.transpose() + Q;
  // 第三步计算 卡尔曼增益
  K_k = P_k__ * H.transpose() * (H * P_k__ * H.transpose() + R).inverse();
  // 第四步计算 更新协方差矩阵
  P_k = (I - K_k * H) * P_k__;

  // 下面计算观测量
  // roll角度
  T acc_roll = atan(acc_y / acc_z);
  // pitch角度
  T acc_pitch = -1 * atan(acc_x / sqrt(pow(acc_y, 2) + pow(acc_z, 2)));
  // 对观测矩阵赋值
  Z_k(0) = acc_roll;
  Z_k(1) = acc_pitch;
  Z_k(2) = 0;

  // 第五步计算 更新状态量
  X_bar_k = X_bar_k__ + K_k * (Z_k - H * X_bar_k__);

  // 更改历史值为下次循环做准备
  P_k_1 = P_k;
  X_bar_k_1 = X_bar_k;

  return {X_bar_k(0), X_bar_k(1), X_bar_k(2)};
}

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

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

相关文章

程序员工作5年,还是个中级程序员,如何再快速晋升?

我曾经就是这个状态&#xff0c;5年工作经验就像是一年工作经验用了5年。职业生涯遇到了瓶颈&#xff0c;无法突破。分析原因有很多&#xff0c;一方面是基本功没练好&#xff0c;像操作系统底层、数据结构、算法、计算机网络这些计算机基础知识掌握的不扎实&#xff0c;不能灵…

vue项目的创建——总结版

目录 前提&#xff1a; 一、vue项目的创建 二、浏览项目页面 三、vue项目目录文件含义和作用 ​四、修改端口号 前提&#xff1a; 首先要有Node.js环境。 1.安装vue npm install vue 2.命令行工具&#xff08;CLI&#xff09;为单页面应用快速搭建繁杂的脚手架 npm in…

vulnhub之MATRIX-BREAKOUT 2 MORPHEUS

信息收集 输入命令&#xff1a;arp-scan 192.168.239.0/24&#xff0c;探测存活主机&#xff0c;发现192.168.239.185 对存活主机进行端口扫描&#xff0c;发现&#xff1a;22、80、81端口 浏览器访问http://192.168.239.185:81是一个登录界面 浏览器访问http://192.168.239.…

大模型携手AI原生应用融入产业场景

前言 10月17日&#xff0c;百度世界2023在北京首钢园召开。百度集团执行副总裁、百度智能云事业群总裁沈抖宣布&#xff0c;对“云智一体”的战略内涵全面升级&#xff0c;即云智一体&#xff0c;深入产业&#xff0c;生态繁荣&#xff0c;AI普惠。重磅发布“千帆AI原生应用开…

ASO优化之增加APP应用下载安装量的技巧1

想要增加APP应用的下载安装量&#xff0c;首先要在发布之前&#xff0c;分析我们的应用推广策略该如何运作并进行调整。提高知名度的基础是关键词&#xff0c;其次使用社交网络来推广我们的应用程序。 1、基础与规划。 在启动应用程序或者是实行ASO计划之前&#xff0c;需要了…

6-3 用链栈实现将非负的十进制数转换为指定的进制数【有题解视频,可本地编译器调试】 分数 15

int DecimalConvert(LinkStack s, int dec, int scale) {while (dec){if (LinkStackPush(s, dec % scale))dec dec / scale;elsereturn 0;}return 1; }

微信小程序获取手机号和openid

小程序通过wx.login组件会返回一个code&#xff0c;这个code用来获得用户的openid。 小程序写法为&#xff1a; wx.login({success (res) {if (res.code) {//发起网络请求wx.request({url: https://example.com/onLogin,// 后台给的请求地址data: {code: res.code}})} else {…

流程图如何制作?好用的11款流程图软件盘点!

流程图是一种强大的可视化工具&#xff0c;用于清晰地展示各种过程和步骤&#xff0c;应用非常广泛&#xff0c;在各个行业中随处可见&#xff0c;凡是涉及流程步骤的场景&#xff0c;都可以用到流程图&#xff0c;那么问题来了&#xff1a;流程图如何制作&#xff1f; 这篇文…

性能优化-卡顿优化-tarce抓取及分析

性能优化&#xff08;卡顿分析&#xff09; 文章目录 一、抓取trace的方法1.使用systrace抓取trace2.使用atrace抓取3.使用Perfetto抓取trace 二、trace文件的分析1.快捷操作1.1 导航操作1.2 快捷操作 2.chrome trace工具分析trace文件3.Prefetto分析trace文件 一、抓取trace的…

C++初阶-类和对象(上)

类和对象&#xff08;上&#xff09; 一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装访问限定符封装 五、类的作用域六、类的实例化七、类的对象大小的计算如何计算类对象的大小类对象的存储方式猜测 八、类成员函数的this指针this指针的引出…

精神科常用评估量表汇总,建议收藏!

根据精神科医生的量表使用情况&#xff0c;笔者整理了10个精神科常用量表&#xff0c;可在线评测直接出结果&#xff0c;可转发使用&#xff0c;可生成二维码使用&#xff0c;可创建项目进行数据管理&#xff0c;有需要的小伙伴赶紧收藏&#xff01; 抑郁自评量表 抑郁自评量表…

22.项目开发之量化交易抓取数据QuantTradeData(一)

项目创建及后端业务&#xff1a;定时更新“股票列表基础信息”数据 项目创建 该量化交易数据平台用于数据库的数据抓取、分析等操作。 和QuantTrade使用同一个数据库&#xff0c;无需重新创建 pom.xml <properties><java.version>1.8</java.version><pro…

GPU 驱动下载记录

1. 我的GPU 是这个&#xff1a;GeForce RTX 2060 下载链接是&#xff1a;Official Drivers | NVIDIA

人脸识别技术是什么?如何进行人脸识别数据标注?

人脸识别解锁、人脸识别防盗系统、人脸识别登陆账户&#xff0c;相比于传统的指纹识别或者是虹膜识别等生物识别技术&#xff0c;人脸识别的应用更加广泛和多样。人脸识别技术是什么&#xff1f;人脸识别和数据标注有什么关系&#xff1f;阅读本文你会了解&#xff1a; 人脸识…

异形led显示屏调试步骤

调试异形LED显示屏需要一定的专业知识和技能。以下是一般的异形LED显示屏调试步骤&#xff1a; 安装和连接&#xff1a; 安装LED模块和框架&#xff0c;确保它们正确固定和对齐。连接电源和信号线。确保电源供电正常&#xff0c;信号线连接正确。什么是LED显示模块&#xff1f;…

android源码查阅连接

原文链接如下&#xff1a; AOSPXRef 在此做个笔记

Paypal提现到万里汇再提现到支付宝的全过程

因为外汇管制的缘故&#xff0c;paypal的钱无法直接提现到国内银行卡。即使提现也会接到电话通知表示非常抱歉无法入账。之前还被银行主管问到是否能提供合同&#xff0c;交易信息&#xff0c;是否完税等等。因为他们对网商都不是太懂&#xff0c;知道paypal已经算不错了。但是…

【数据结构】队列-Queue

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 队列 1.什么是队列2. 队列的使用3. …

报名倒计时 | 超硬核!第四届中国云计算基础架构开发者大会邀你参会

编者按&#xff1a;第四届 CID 大会将于 10 月 21 日在深圳南山科技园希尔顿花园酒店举办&#xff01;龙蜥社区作为本次 CID 大会支持的单位&#xff0c;诚邀您参与此次大会。 本大会将聚焦业界最前沿的云计算基础架构技术成果&#xff0c;围绕基础架构技术领域的技术交流&…

访问文件夹

访问文件夹并读取文件内容 将展示如何使用 JavaScript 中的 showDirectoryPicker() 方法来访问文件夹&#xff0c;并读取文件的内容。 HTML 结构 首先&#xff0c;需要一个按钮来触发打开文件夹的操作&#xff1a; <button>打开文件夹</button>还需要一个段落元…