草庐IT

陀螺仪与加速度计的姿态融合——互补滤波

xiaobaibai_2021 2023-08-15 原文

本篇文章我们来讲讲如何将陀螺仪和加速度计的数据结合起来,获取更准确的姿态数据,使用的是互补滤波的方法。

阅读本文需有一定的知识基础,可以参见作者以前MPU6050的两篇文章:《MPU6050陀螺仪和加速度计数据的获取和校准》、《MPU6050官方DMP的移植和使用》,以及了解四元数的一些基本概念。

1)为什么要进行姿态融合

在之前的文章里,我们讲过一些陀螺仪和加速度计的知识,我们知道,陀螺仪可以获取载体的角速度,由角速度积分,就能得到角度,也就得到了载体的姿态。但是,陀螺仪给出的角速度存在测量误差、噪声和漂移,经过积分运算之后,会形成累积误差,这个误差会随着时间延长越来越大,最终导致偏差太大而无法使用。

另一方面,加速度计可以测量到地球的重力,当载体静止或者匀速运动时,重力的方向就是竖直向下的,通过测量重力加速度的方向,可以获取当前载体的俯仰角、滚转角。但是加速度计容易受到高频噪声的干扰,动态响应慢,只在长时间内数据比较有效。

因此,一般我们使用加速度计的数据来修正陀螺仪,以加速度计获取的实时姿态角来修正陀螺仪的累积误差,就能在短时间和长时间内都能获取比较满意的姿态信息。

我们以下图为例,Z轴向上,约定绕X轴旋转的角度为滚转角;绕Y轴旋转的角度为俯仰角,绕Z轴旋转的角度为偏航角。

那么,滚转角(绕X轴转)和俯仰角(绕Y轴转)发生变化时,MPU6050测出来的重力加速度g的方向相对于载体也会发生变化。而加速度计测出来的重力加速度g的方向是实时的,不会受长时间计算累加的影响。所以,我们可以用加速度计测到的g的方向,来修正陀螺仪积分得到的滚转角和俯仰角

而偏航角(绕Z轴转)变化时,MPU6050测到的重力加速度g方向是不会变化的,所以g的方向不能用来修正偏航角。要想修正偏航角,需要测量地磁偏角的传感器信息。

这个用加速度计或磁力计来修正姿态角的过程,一般称为数据融合,有多种方法实现。在之前的文章中,我们使用MPU6050芯片官方提供的DMP库直接获取了融合后的数据;但是这只适用于特定厂家的芯片,而更通用的方法是使用互补滤波或者卡尔曼滤波来实现,本节要讲的就是使用互补滤波的方法,来进行数据融合。

(注意,由于没有引入磁力计的数据,本文使用互补滤波的方法只是修正了俯仰角和滚转角的信息,无法修正偏航角,后续有机会再讲解如何用磁力计修正偏航角)

2)互补滤波的原理

假如我们有两种途径测量某个信号,测得的结果一个带有高频噪声,一个带有低频噪声。我们为了获取更准确的信号,可以把它们的噪声分别滤掉,再合并,就得到了没有噪声的原始信号。具体操作如下图所示:

这就是互补滤波最基础的理论。

为了使得最后相加的重构信号与我们想要的信号尽量相等,一般要求F1(s)+F2(s) = 1。

具体到我们的实际问题,姿态信息可以通过陀螺仪角速度积分得到,也可以通过加速度计实时测量得到;而且,陀螺仪积分得到的姿态主要包含低频噪声(零偏、累积误差),加速度计得到的姿态主要包含高频噪声。使用互补滤波正好可以融合二者的姿态信息。

依据上面这个框图,我们可以想到以下的姿态融合方法:

图中ω是角速度,n1和n2为噪声,θ’为融合后的角度。

当我们把滤波器简化为最简单的一个比例系数时,有如下形式:

姿态角 = k*陀螺仪姿态角 + (1-k)*加速度计姿态角

(其中0<k<1,k的选择,取决于我们更相信陀螺仪的数据,还是更相信加速度计的数据)

你可能会很惊讶,这不就是个加权平均吗?就这也能滤波?

别急,它确实没有滤波,但我们先理解一下,再慢慢深入。

我们看看等式右边的两项,由于k小于1,所以陀螺仪姿态角的低频噪声被缩小了k倍;同样,1-k也小于1,所以加速度计姿态角的高频噪声被缩小了1-k倍;二者相加,姿态角的倍数仍为1,而高频和低频的噪声都被缩小了。虽然这个“滤波”效果有点弱,但是这样我们至少得到了一个高频、低频都比原始信号稍好一些的姿态信息,这就实现了高频和低频信号的互补。

实际上,当使用了有效的高通和低通滤波器时,噪声的影响会被进一步减弱。

前人的研究已经帮我们总结出了通用的公式,就是低通滤波器为LPF=C(s)/(C(s)+s),高通滤波器HPF=s/(C(s)+s)。选用不同的C(s)可以形成不同滤波效果。

把算法化成框图的形式,如下图所示:

上面这个框图对于理解互补滤波的原理比较直观,但是等效为下图这种形式时,更接近于编程实现的思想:(有兴趣的可以推导一下,两种框图是等效的)

当选择不同的C(s)时,可以获得不同的滤波效果,C(s)为常数时,就是一阶滤波器;C(s)为a+b/s时就是二阶滤波器。

3)互补滤波用于姿态融合的编程实现

当求解姿态角时,必须要有一些四元数的知识,可以认为四元数等价于滚转角、俯仰角、偏航角。之所以要使用四元数,是因为它可以简化姿态更新的计算过程。基本上现在网上的开源代码都是以四元数来表征姿态角的。本文不去深究四元数的理论,只是拿来使用。

我们来看一下最经典互补滤波算法是如何实现的,这段代码被广泛应用在开源四轴飞行器上,它的核心部分如下:

ax、ay、az是加速度计测得的三个方向的加速度,gx、gy、gz是陀螺仪测得的三个方向的角速度。

首先,将ax、ay、az进行单位化,因为我们只需要使用它们求角度,不关心它们的大小,单位化的操作就是第65~68行,其中sqrt函数是求平方根:

       norm = sqrt(ax*ax + ay*ay + az*az);

       ax = ax / norm;

       ay = ay / norm;

       az = az / norm;

然后,第72~74行,是依据当前的姿态来计算重力加速度;静止或匀速直线运动时,重力产生的加速度在地面东北天坐标系的xyz三个方向上分量是[0,0,g],再乘以姿态转换矩阵,就得到了机体坐标系下的加速度:

用四元数表示的姿态转移矩阵是:

所以,转换矩阵的最后一列,就是在载体坐标系下的加速度(忽略了倍数g):

       vx = 2*(q1q3 - q0q2);

       vy = 2*(q0q1 + q2q3);

       vz = q0q0 - q1q1 - q2q2 + q3q3 ;

由于这个计算过程是通过已有的姿态转移矩阵算出来的,所以,它是包含了陀螺仪的角度信息的,那么它与加速度计的测量原始量ax、ay、az之间会比较接近但会有偏差。我们知道了这个偏差后,就可以用加速度计的测量值来修正已有的姿态了。

计算偏差的过程就是第77~79行,这里是用向量的外积作为向量之间的偏差:

       ex = (ay*vz - az*vy) ;

       ey = (az*vx - ax*vz) ;

       ez = (ax*vy - ay*vx) ;

注意,上一节的框图中,是通过角度θ1(s)-θ’(s)来计算偏差的,而这里的代码实现,是将θ’(s)反算到了三个轴的加速度vx、vy、vz之后,再计算三个轴的加速度误差,效果也是一样的,这样也是为了简化计算。

现在我们已经得到了框图中的θ1(s)-θ’(s)等效量ex、ey、ez,接下来就要选择合适的C(s)来确定滤波函数了。这部分代码中实现的,是使用的二阶滤波,取的C(s)=Kp+Ki/s,也就是用“误差”和“误差的积分”共同去修正角速度,Kp和Ki是两个由用户确定的常数,代码如下:

       exInt = exInt + ex * Ki;  //对误差进行积分,也就是每周期累加

       eyInt = eyInt + ey * Ki;

       ezInt = ezInt + ez * Ki; 

       gx = gx + Kp*ex + exInt;  //将误差PI(比例和积分项)补偿到陀螺仪角速度

       gy = gy + Kp*ey + eyInt;

       gz = gz + Kp*ez + ezInt;  

细心的朋友可能发现了,这与PID控制中只使用了PI环节是一样的,有比例项和积分项。所以,代码里也用Kp和Ki两个参数来表示。

执行完这里,就已经完成了加速度计对陀螺仪的修正。上一节的框图就只剩下最后一步,积分一次就能得到新的姿态角了。

我们使用四元数更新姿态时,不是使用积分累加的方法,而有另一种方法:

具体为什么如上面计算,用角速度和周期可以更新四元数,这里不深入探讨了,有兴趣可以找资料深入了解。

最后,有需要的话,可以用更新后的四元数,通过反三角函数来求取当前的姿态角:

这段代码在使用时,只要周期性地获取陀螺仪和加速度计的数据、调用互补滤波函数、

更新四元数、计算姿态角即可。

测试一下互补滤波的效果,取Kp=10,Ki=0.008,初始时z轴向上保持5s进行MPU6050传感器自校正,然后每100ms获取一次MPU6050的测量数据,进行互补滤波,计算姿态角,送到上位机显示。

可以看到,经过较长时间后,俯仰和滚转角都可以保持正确,不会产生误差累积和漂移,说明陀螺仪的数据得到了加速计的修正;而偏航角是不能实时修正的,会慢慢越偏越大:

好了,关于互补滤波姿态融合的知识,就讲到这里了。由于篇幅所限,文中的代码只是截取了核心片段进行讲解,完整的工程代码可以免费提供下载交流。

如果觉得有用可以关注作者微信公众号“小白白学电子”,有更多内容分享,在公众号可以找到所有代码和资料下载地址。

有关陀螺仪与加速度计的姿态融合——互补滤波的更多相关文章

  1. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  2. ruby-on-rails - 加速 RSpec 请求规范的方法 - 2

    我有33个规范以大约5秒的速度运行,以这种速度运行会导致测试套件变慢。我追踪到请求规范(4秒以上),因为模型规范只用了一小部分时间。我已经检查过,我的请求规范没有任何过于复杂或不必要的东西,所以我不知道该去哪里让它们更快,而不是只在推送代码之前运行它们以确保一切正常.加快请求规范的最佳方法是什么? 最佳答案 我使用Spork来加速我的测试。它保持整个环境加载以赢得时间。看看这个博客:http://ykyuen.wordpress.com/2010/12/14/rails-running-rspec-with-spork-test-s

  3. 欧拉角表示的姿态矩阵(313和312转序) - 2

    一、习惯约定图片来自PSINS(高精度捷联惯导算法)PSINS工具箱入门与详解.pptx二、基本旋转矩阵绕x轴逆时钟旋转α\alphaα角度Rx(α)=[ 1000cos⁡αsin⁡α0−sin⁡αcos⁡α]R_x(\alpha)=\begin{bmatrix}\1&0&0\\0&\cos\alpha&\sin\alpha\\0&-\sin\alpha&\cos\alpha\end{bmatrix}Rx​(α)=​ 100​0cosα−sinα​0sinαcosα​​绕y轴逆时钟旋转α\alphaα角度Ry(α)=[ cos⁡α0−sin⁡α010sin⁡α0cos⁡α]R_y(\alpha

  4. ruby - 融合表 : Why do I keep getting a "400 Bad Request" error when trying to update a table style via Ruby's RestClient gem - 2

    我正在尝试使用RubygemRestClient为我的一个FusionTables更新样式。这是我的代码:require'rest_client'tableId=''styleId=''key=''table_url="https://www.googleapis.com/fusiontables/v1/tables/#{tableId}/styles/#{styleId}?key=#{key}"update='{"polygonOptions":{"strokeColor":"#ffffff"}}'token='STRINGCONTAININGAUTHORIZATIONTOKEN'R

  5. ruby-on-rails - 如何使用 ruby​​ 加速大型 CSV 的处理 - 2

    对于一个项目,我需要解析一些非常大的CSV文件。一些条目的内容存储在MySQL数据库中。我正在尝试使用多线程来加快速度,但到目前为止,这只会减慢速度。我解析了一个CSV文件(最大10GB),其中一些记录(20M+记录CSV中的大约5M)需要插入到MySQL数据库中。为了确定需要插入的记录,我们使用Redis服务器和包含正确ID/引用的集合。由于我们在任何给定时间处理大约30个这样的文件,并且存在一些依赖关系,我们将每个文件存储在一个Resque队列中,并让多个服务器处理这些(优先级)队列。简而言之:classWorkerdefself.perform(file)CsvParser.ea

  6. ruby - 如何加速sass编译? - 2

    在编译sass时,我的编译时间往往很长(在当前的中型项目中长达9秒),而我的笔记本电脑速度非常快,而且带有ssd。我通过grunt-contrib-sass使用sassass一个grunt任务,但是直接从命令行运行sass时编译时间差别不大。Libsass另一方面,同一个项目只需要大约100毫秒,但它不支持我需要的几个功能。所以我想知道我有什么可能加快编译过程?拆分文件当然有帮助,但是还有其他副作用更小的方法吗?编辑:此外,我也很乐意解释libsass为什么比ruby​​-sass快得多。不知何故,我非常怀疑这只是因为ruby​​比C/C++慢得多。还是我错了?编辑2:当我使用Ubun

  7. ruby - 如何加速 Jekyll/Octopress 的生成? - 2

    我使用Octopress作为我的博客引擎。这是完美的。但是如果帖子很多,比如400+,生成速度就很慢了。那么,有什么方法可以加快Jekyll/Octopress的生成速度吗?谢谢。 最佳答案 显然,如果您只处理一篇文章,则无需等待整个站点生成。您正在寻找的是rakeisolate[partial_post_name]任务。使用rakeisolate,您可以仅“隔离”您正在处理的帖子,并将所有其他帖子移至source/_stash文件夹。partial_post_name参数只是帖子文件名中的一些单词。例如,如果我想将帖子与前面的示例

  8. 视频融合技术解决方案,三维全景拼接赋能平台 - 2

    近年来,随着信息化时代的到来,三维全景拼接以视频监控领域为代表的智能硬件公司迅速崛起,随后全国各地在视频监控领域进行了大量的建设。但随着摄像头数量的增加,视频监控画面离散、庞杂、关联性差等诸多问题日渐凸显。如何优化现有视频技术,助力管理者或使用者有效、直观、准确地掌控现场实时动态,成为我国信息化前行路上面临的新课题。视频融合技术平台解决方案北京智汇云舟科技有限公司成立于2012年,专注于创新性的“视频孪生(实时实景数字孪生)”技术研发与应用。公司依托自研三维地理信息引擎(3DGIS),融合建筑信息模型(BIM)、视频监控(Video)、人工智能(AI)及物联网(IOT)等多种技术,并在此基础上

  9. ruby-on-rails - rspec 和 shoulda - 互补还是替代? - 2

    我已经使用了一段时间的shoulda,并且阅读并使用了rspec。我没有做过深入的比较和对比。但在我看来,两者之间有一些重叠,但它们不是1-1的替代品。我正在考虑使用rspec在我的rails系统中编写一些单元测试,而不替换所有使用shoulda编写的现有测试。只是作为一种获得感觉的方式。这是个好主意吗?我可以逐渐从一个转移到另一个还是自找麻烦?我应该考虑其中一个比另一个明显的优势吗?谢谢! 最佳答案 我不得不反对Chris的回答,即它们是替代方案。我在我的Rails应用程序中同时使用Shoulda和Rspec,它们相互补充得很好。

  10. “数实融合 元力觉醒”,苏州市元宇宙生态大会圆满召开! - 2

     为贯彻落实《苏州市培育元宇宙产业创新发展指导意见》,抢抓数字经济发展新机遇,加速培育与元宇宙发展相关的技术底座,“数实融合元力觉醒——苏州市软件行业协会元宇宙专委会成立大会暨元宇宙生态大会”于4月14日成功举办。 苏州和数智能软件有限公司作为苏州市软件行业协会元宇宙专委会轮值理事长单位,参加了“元宇宙专委会揭牌与轮值理事长单位授牌仪式”。 大会上,数字主持人“丹丹”向社会发布了由苏州市软件行业协会、苏州市软件行业协会元宇宙专委会、西交利物浦大学、苏州科技大学、苏州和数智能软件有限公司等单位编写的《元宇宙行业分析报告2023》。该报告立足苏州、辐射长三角,系统梳理了元宇宙行业现状、元宇宙核心技

随机推荐