MPU6050的四元数解算姿态方法

发布者:平静宁静最新更新时间:2024-07-01 来源: elecfans关键字:MPU6050  STM32 手机看文章 扫描二维码
随时随地手机看文章

 最近在研究小四轴的飞行,姿态检测主要用到的传感器是MPU6050。从MPU6050读出来的加速度和角速度数据最后要转成姿态,可以转换成欧拉角(偏航角、俯仰角和滚转角)或四元数表示,为了减少计算量(欧拉角涉及正弦运算,运算量相对较大),方便在STM32主控上实现,可以转换成四元数表示。


  使用MPU6050硬件DMP解算姿态是非常简单的,下面介绍由三轴陀螺仪和加速度计的值来使用四元数软件解算姿态的方法。


  我们先来看看如何用欧拉角描述一次平面旋转(坐标变换):

  MPU6050的四元数解算姿态方法

  设坐标系绕旋转α角后得到坐标系,在空间中有一个矢量在坐标系中的投影为,在内的投影为由于旋转绕进行,所以Z坐标未变,即有。

  MPU6050的四元数解算姿态方法

  转换成矩阵形式表示为:

  MPU6050的四元数解算姿态方法

  整理一下:

  MPU6050的四元数解算姿态方法

  所以从旋转到可以写成

  上面仅仅是绕一根轴的旋转,如果三维空间中的欧拉角旋转要转三次:

  MPU6050的四元数解算姿态方法

  上面得到了一个表示旋转的方向余弦矩阵。

  不过要想用欧拉角解算姿态,其实我们套用欧拉角微分方程就行了:

  MPU6050的四元数解算姿态方法

  上式中左侧,,是本次更新后的欧拉角,对应row,pit,yaw。右侧,是上个周期测算出来的角度,,,三个角速度由直接安装在四轴飞行器的三轴陀螺仪在这个周期转动的角度,单位为弧度,计算间隔时T陀螺角速度,比如0.02秒0.01弧度/秒=0.0002弧度。间因此求解这个微分方程就能解算出当前的欧拉角。

  前面介绍了什么是欧拉角,而且欧拉角微分方程解算姿态关系简单明了,概念直观容易理解,那么我们为什么不用欧拉角来表示旋转而要引入四元数呢?

  一方面是因为欧拉角微分方程中包含了大量的三角运算,这给实时解算带来了一定的困难。而且当俯仰角为90度时方程式会出现神奇的“GimbalLock”。所以欧拉角方法只适用于水平姿态变化不大的情况,而不适用于全姿态飞行器的姿态确定。

  四元数法只求解四个未知量的线性微分方程组,计算量小,易于操作,是比较实用的工程方法。

  我们知道在平面(x,y)中的旋转可以用复数来表示,同样的三维中的旋转可以用单位四元数来描述。我们来定义一个四元数:

  MPU6050的四元数解算姿态方法

  我们可以把它写成,其中,。那么是矢量,表示三维空间中的旋转轴。w是标量,表示旋转角度。那么就是绕轴旋转w度,所以一个四元数可以表示一个完整的旋转。只有单位四元数才可以表示旋转,至于为什么,因为这就是四元数表示旋转的约束条件。

  而刚才用欧拉角描述的方向余弦矩阵用四元数描述则为:

  MPU6050的四元数解算姿态方法

  所以在软件解算中,我们要首先把加速度计采集到的值(三维向量)转化为单位向量,即向量除以模,传入参数是陀螺仪x,y,z值和加速度计x,y,z值:

  《code》void IMUupdate(float gx, float gy, float gz, float ax, float ay, float az) { float norm; float vx, vy, vz; float ex, ey, ez; norm = sqrt(ax*ax + ay*ay + az*az); ax = ax / norm; ay = ay / norm; az = az / norm;

  下面把四元数换算成方向余弦中的第三行的三个元素。刚好vx,vy,vz 其实就是上一次的欧拉角(四元数)的机体坐标参考系换算出来的重力的单位向量。

  《code》// estimated direction of gravity vx = 2*(q1*q3 - q0*q2); vy = 2*(q0*q1 + q2*q3); vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;

  axyz是机体坐标参照系上,加速度计测出来的重力向量,也就是实际测出来的重力向量。

  axyz是测量得到的重力向量,vxyz是陀螺积分后的姿态来推算出的重力向量,它们都是机体坐标参照系上的重力向量。

  那它们之间的误差向量,就是陀螺积分后的姿态和加计测出来的姿态之间的误差。

  向量间的误差,可以用向量叉积(也叫向量外积、叉乘)来表示,exyz就是两个重力向量的叉积。

  这个叉积向量仍旧是位于机体坐标系上的,而陀螺积分误差也是在机体坐标系,而且叉积的大小与陀螺积分误差成正比,正好拿来纠正陀螺。(你可以自己拿东西想象一下)由于陀螺是对机体直接积分,所以对陀螺的纠正量会直接体现在对机体坐标系的纠正。

  《code》// integral error scaled integral gain exInt = exInt + ex*Ki; eyInt = eyInt + ey*Ki; ezInt = ezInt + ez*Ki;

  用叉积误差来做PI修正陀螺零偏

  《code》// integral error scaled integral gain exInt = exInt + ex*Ki; eyInt = eyInt + ey*Ki; ezInt = ezInt + ez*Ki; // adjusted gyroscope measurements gx = gx + Kp*ex + exInt; gy = gy + Kp*ey + eyInt; gz = gz + Kp*ez + ezInt;

  四元数微分方程,其中T为测量周期,为陀螺仪角速度,以下都是已知量,这里使用了一阶龙哥库塔求解四元数微分方程:

  MPU6050的四元数解算姿态方法

  《code》// integrate quaternion rate and normalise q0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT; q1 = q1 + (q0*gx + q2*gz - q3*gy)*halfT; q2 = q2 + (q0*gy - q1*gz + q3*gx)*halfT; q3 = q3 + (q0*gz + q1*gy - q2*gx)*halfT;

  最后根据四元数方向余弦阵和欧拉角的转换关系,把四元数转换成欧拉角:

  MPU6050的四元数解算姿态方法

  所以有:

  Q_ANGLE.Yaw = atan2(2 * q1 * q2 + 2 * q0 * q3, -2 * q2*q2 - 2 * q3* q3 + 1)* 57.3; // yaw

  Q_ANGLE.Y = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch

  Q_ANGLE.X = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll

  以下是代码实现,attitude是上一次姿态融合的四元数(内存地址),gyr[3]是MPU6050读出来的角速度,acc[3]是MPU6050读出来的加速度,interval为积分时间。

  void mix_gyrAcc_crossMethod(quaternion * attitude,const float gyr[3],const float acc[3],float interval)

  {

  const static float FACTOR = 0.001;//取接近0的数

  //

  float w_q = attitude-》w;

  float x_q = attitude-》x;

  float y_q = attitude-》y;

  float z_q = attitude-》z;

  float x_q_2 = x_q * 2;

  float y_q_2 = y_q * 2;

  float z_q_2 = z_q * 2;

  //

  // 加速度计的读数,单位化。

  float a_rsqrt = math_rsqrt(acc[0]*acc[0]+acc[1]*acc[1]+acc[2]*acc[2]);

  float x_aa = acc[0] * a_rsqrt;

  float y_aa = acc[1] * a_rsqrt;

  float z_aa = acc[2] * a_rsqrt; //加速度计测量出的加速度向量(载体坐标系下)

  //

  // 载体坐标下的重力加速度向量,单位化。

  float x_ac = x_q*z_q_2 - w_q*y_q_2;

  float y_ac = y_q*z_q_2 + w_q*x_q_2; //通过四元数旋转矩阵与地理坐标系下的重力加速度向量[0 0 0 1]叉乘得到载体坐标系下的重力加速度向量

  float z_ac = 1 - x_q*x_q_2 - y_q*y_q_2;//(主要)角速度计测出的四元数表示的载体坐标系下的重力加速度向量(这里已转换成载体坐标系下)

  //

  // 测量值与常量的叉积。

  float x_ca = y_aa * z_ac - z_aa * y_ac;

  float y_ca = z_aa * x_ac - x_aa * z_ac;

  float z_ca = x_aa * y_ac - y_aa * x_ac;//角速度计测出的角度误差,叠加的FACTOR大小可以实验试凑

  //

  // 构造增量旋转。

  float delta_x = gyr[0] * interval / 2 + x_ca * FACTOR;

  float delta_y = gyr[1] * interval / 2 + y_ca * FACTOR;

  float delta_z = gyr[2] * interval / 2 + z_ca * FACTOR;

  //

  // 融合,四元数乘法。

  attitude-》w = w_q - x_q*delta_x - y_q*delta_y - z_q*delta_z;

  attitude-》x = w_q*delta_x + x_q + y_q*delta_z - z_q*delta_y;

  attitude-》y = w_q*delta_y - x_q*delta_z + y_q + z_q*delta_x;

  attitude-》z = w_q*delta_z + x_q*delta_y - y_q*delta_x + z_q;

  quaternion_normalize(attitude);//归一化

  }


关键字:MPU6050  STM32 引用地址:MPU6050的四元数解算姿态方法

上一篇:TM32F4 RT-thread移植
下一篇:基于机智云物联网的智能花卉栽培系统

推荐阅读最新更新时间:2024-11-11 22:03

stm32移植ucos iii教程
µC/OS-III是一个实时操作系统,广泛应用于嵌入式系统开发中。在STM32系列微控制器上移植µC/OS-III可以充分发挥其实时性和多任务处理能力。本篇文章将为您提供一个详实、细致的STM32移植µC/OS-III的教程。 准备工作 在开始移植之前,您需要准备以下工具和环境: STM32系列微控制器开发板 STM32CubeMX工具(用于生成底层驱动代码) Keil MDK(用于编译和下载代码) 创建STM32项目 首先,使用STM32CubeMX工具创建一个新的STM32项目。选择您想要使用的STM32系列微控制器型号,并设置相应的时钟源、配置引脚等。 在添加外设配置时,选择一个可用的USART或UART作为µC
[单片机]
STM32菜鸟成长记录---系统滴答定时器(systick)应用
1.systick介绍 Systick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。滴答中断?这里来简单地解释一下。操作系统进行运转的时候,也会有“心跳”。它会根据“心跳”的节拍来工作,把整个时间段分成很多小小的时间片,每个任务每次只能运行一个“时间片”的时间长度就得退出给别的任务运行,这样可以确保任何一个任务都不会霸占整个系统不放。或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。只要不把它在S
[单片机]
<font color='red'>STM32</font>菜鸟成长记录---系统滴答定时器(systick)应用
关于单片机STM32裸机程序架构设计
本着授人以渔的原则,既提供我一直在用的程序架构,也讲程序架构的设计思路。 如果本文内容,你都能领悟并做到,不管项目多复杂,都将游刃有余。 我研发的那几年,接触大多数工程师,都没有程序架构的概念,基本一个while死循环干到底。 模块之间也没有封装好,导致代码写好以后,扩展性和维护性太差,类似的功能代码,也很难移植到新项目去复用。 早期我也是这样写的,反正实现功能就行了,代码好不好,功能上又看不出区别。 不过,等你接触到复杂的项目时,这招就行不通了,没设计好程序架构,根本做不稳定。 我意识到这个问题,是碰到两种需求的时候: 1.是做一个基于STM32的网关项目,项目做完以后,客户老是要改功能,客户不懂技术,在客户眼里,觉得改一个
[单片机]
关于单片机<font color='red'>STM32</font>裸机程序架构设计
STM32生成bin文件
方案一: 第一步:打开Options for Target ‘target 1’对话框,选择User标签页; 第二步:找到fromelf.exe的路径(keil5在ARMCC里) 第三步:重点(基路径是工程路径,bin文件是根据axf生成的) 接下来要做的要视情况而定:选完fromelf.exe后在输入框中加个空格然后加一串字 : --bin -o ./Obj/xx.bin ./Obj/xx.axf 解释: 这串字符得依情况而定,不能直接照搬。如下下图所示,博主把.hex和.axf等文件输出到Obj文件夹里了,故为: --bin -o ./Obj/xx.bin ./Obj/xx.axf 所以最终的是:D:\MDK5
[单片机]
STM32 死在 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
移植官方STM32虚拟串口程序,串口通信死在 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); 仿真发现USART1时钟味使能。。。 使能时钟后仿真,USART1寄存器有反应,发送数据是仍死在 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); 上网寻找答案无果。怀疑引脚未配置造成。 配置 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA
[单片机]
STM32 VCP PC端安装驱动失败的问题解决----试了解决了问题
STM32,使用USB VCP功能,即虚拟串口功能时,选择USB_OTG_FS Device_Only,如上图。cube自动生成工程,不作修改。将USB插入电脑,WIN10或WIN7系统设备管理器中端口项中都能成功出现STMicroelecronics Virtual COM Port(COM4),但驱动前显示黄色叹号,表示设备安装存在问题的警告。 问题: usbd_cdc.c文件中,USBD_CDC_Init函数中存在一个USBD_malloc,可在此打断点调试,pdev- pClassData为NULL。可知malloc并没有申请到空间。 解决方法: malloc没有申请到空间,并不是USBD_malloc函数有问题,而是系统
[单片机]
stm32下载的问题
原因是JTAG已经被占用,当然不能再用JTAG操作啦!此时要保证CPU不进入正常运行状态,才能使用JTAG。 解决方案:options for target ---- Debug---- 右上方---- use 后面的setting按钮------ 左上方Ort下面的JTAG变为SW即可 改成
[单片机]
<font color='red'>stm32</font>下载的问题
STM32的PWM输入模式设置并用DMA接收数据
参考 :STM32输入捕获模式设置并用DMA接收数据 PWM input mode This mode is a particular case of input capture mode. The procedure is the same except:  Two ICx signals are mapped on the same TIx input.  These 2 ICx signals are active on edges with opposite polarity.  One of the two TIxFP signals is selected as trigger input and the
[单片机]
<font color='red'>STM32</font>的PWM输入模式设置并用DMA接收数据
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved