目录

  • 源码
    • Mahony_6.c
    • Mahony_6.h
  • 使用方法
  • 测试程序
    • main.c
    • 效果

STC89C516 32MHz
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
上位机:Vofa+ 1.3.10


移植自MPU6050姿态解算——Mahony互补滤波 —— 大写的小写字母

加入了输入数据范围的自动处理,即使更改量程也能正确解算。

源码

为了避免所用RAM超标,部分变量设为idata类型,移植时需注意。
       所用MCU为STC89C516 晶振16MHz 6T模式

stdint.h见【51单片机快速入门指南】1:基础知识和工程创建
       软件I2C程序见【51单片机快速入门指南】4: 软件 I2C
       串口部分见【51单片机快速入门指南】3.3:USART 串口通信
       MPU6050.c、MPU6050.h见【51单片机快速入门指南】4.3: I2C读取MPU6050陀螺仪的原始数据

Kp和Ki要按需调整,我这里取1.5和0.005

Mahony_6.c

#include <math.h>
#include "MPU6050.h"#define G 9.80665f                    // m/s^2#define PI 3.141592653589793idata float halfT = 1;
idata float GYRO_K = 1, ACCEL_K = 1;void MPU6050_Mahony_Init(float loop_ms)
{halfT = loop_ms/1000./2;  //计算周期的一半,单位sswitch((MPU_Read_Byte(MPU_GYRO_CFG_REG) >> 3) & 3){case 0:GYRO_K = 1./131/57.3;break;case 1:GYRO_K = 1./65.5/57.3;break;case 2:GYRO_K = 1./32.8/57.3;break;case 3:GYRO_K = 1./16.4/57.3;break;}switch((MPU_Read_Byte(MPU_ACCEL_CFG_REG) >> 3) & 3){case 0:ACCEL_K = G/16384;break;case 1:ACCEL_K = G/8192;break;case 2:ACCEL_K = G/4096;break;case 3:ACCEL_K = G/2048;break;}
}static float invSqrt(float x)      //快速计算 1/Sqrt(x)
{float halfx = 0.5f * x;float y = x;long i = *(long*)&y;i = 0x5f3759df - (i >> 1);y = *(float*)&i;y = y * (1.5f - (halfx * y * y));return y;
}#define Kp 1.50f
#define Ki 0.005fidata float Pitch, Roll, Yaw;
idata float q0 = 1, q1 = 0, q2 = 0, q3 = 0;     //四元数
idata float exInt = 0, eyInt = 0, ezInt = 0;     //叉积计算误差的累计积分void Imu_Update(float gx, float gy, float gz, float ax, float ay, float az)
{unsigned char i;float vx, vy, vz;                          //实际重力加速度float ex, ey, ez;                          //叉积计算的误差float norm;float q0q0 = q0*q0;float q0q1 = q0*q1;float q0q2 = q0*q2;float q0q3 = q0*q3;float q1q1 = q1*q1;float q1q2 = q1*q2;float q1q3 = q1*q3;float q2q2 = q2*q2;float q2q3 = q2*q3;float q3q3 = q3*q3;//将加速度原始AD值转换为m/s^2ax = ax * ACCEL_K;ay = ay * ACCEL_K;az = az * ACCEL_K;//将陀螺仪AD值转换为 弧度/sgx = gx * GYRO_K;gy = gy * GYRO_K;gz = gz * GYRO_K;if (ax * ay * az == 0)return;//加速度计测量的重力方向(机体坐标系)norm = invSqrt(ax * ax + ay * ay + az * az);           //之前这里写成invSqrt(ax*ax + ay+ay + az*az)是错误的,现在修改过来了ax = ax * norm;ay = ay * norm;az = az * norm;//四元数推出的实际重力方向(机体坐标系)vx = 2 * (q1q3 - q0q2);vy = 2 * (q0q1 + q2q3);vz = q0q0 - q1q1 - q2q2 + q3q3;//叉积误差ex = (ay * vz - az * vy);ey = (az * vx - ax * vz);ez = (ax * vy - ay * vx);//叉积误差积分为角速度exInt = exInt + ex * Ki;eyInt = eyInt + ey * Ki;ezInt = ezInt + ez * Ki;//角速度补偿gx = gx + Kp * ex + exInt;gy = gy + Kp * ey + eyInt;gz = gz + Kp * ez + ezInt;//更新四元数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;//单位化四元数norm = invSqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);q0 = q0 * norm;q1 = q1 * norm;q2 = q2 * norm;q3 = q3 * norm;//四元数反解欧拉角Yaw = atan2(2.f * (q1q2 + q0q3), q0q0 + q1q1 - q2q2 - q3q3) * 57.3f;Pitch = -asin(2.f * (q1q3 - q0q2)) * 57.3f;Roll = atan2(2.f * q2q3 + 2.f * q0q1, q0q0 - q1q1 - q2q2 + q3q3) * 57.3f;
}

Mahony_6.h

#ifndef Mahony_6_H_
#define Mahony_6_H_extern idata float Pitch, Roll, Yaw;
extern idata float q0, q1, q2, q3;      //四元数void MPU6050_Mahony_Init(float loop_ms);
void Imu_Update(float gx, float gy, float gz, float ax, float ay, float az);#endif

使用方法

先调用MPU6050_Mahony_Init(dt),参数为一次循环的时间,单位为ms
再使用Imu_Update姿态融合函数。

测试程序

main.c

#include <STC89C5xRC.H>
#include "intrins.h"
#include "stdint.h"
#include "USART.h"
#include "./MPU6050/MPU6050.h"
#include "./MPU6050/Mahony_6.h"void Delay1ms()        //@32MHz
{unsigned char i, j;i = 6;j = 44;do{while (--j);} while (--i);
}void Delay_ms(int i)
{while(i--)Delay1ms();
}void main(void)
{int16_t aacx,aacy,aacz;        //加速度传感器原始数据int16_t gyrox,gyroy,gyroz;  //陀螺仪原始数据USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 32000000, 4800, DOUBLE_BAUD_DISABLE, USART_TIMER_2);MPU_Init(); MPU6050_Mahony_Init(85);while(1){   MPU_Get_Accelerometer(&aacx, &aacy, &aacz); //得到加速度传感器数据MPU_Get_Gyroscope(&gyrox, &gyroy, &gyroz);  //得到陀螺仪数据Imu_Update(gyrox, gyroy, gyroz, aacx, aacy, aacz);printf("%f, ", Pitch);printf("%f, ", Roll);printf("%f\r\n", Yaw);}
}

效果

个人感觉在51上,Mahony的效果要远远好于DMP及其他滤波算法的表现,如果把零偏处理了,效果会更好。

【51单片机快速入门指南】4.3.3: MPU6050使用Mahony AHRS算法实现六轴姿态融合获取四元数、欧拉角相关推荐

  1. 【51单片机快速入门指南】4.3.4: MPU6050使用Madgwick AHRS算法实现六轴姿态融合获取四元数、欧拉角

    目录 源码 Madgwick_6.c Madgwick_6.h 使用方法 测试程序 main.c 效果 STC89C516 32MHz Keil uVision V5.29.0.0 PK51 Prof ...

  2. 【51单片机快速入门指南】4.4.2:Mahony AHRS 九轴姿态融合获取四元数、欧拉角

    目录 传感器的方向 源码 Mahony_9.c Mahony_9.h 使用方法 测试 main.c 效果 STC15F2K60S2 22.1184MHz Keil uVision V5.29.0.0 ...

  3. 【51单片机快速入门指南】4.4.3:Madgwick AHRS 九轴姿态融合获取四元数、欧拉角

    目录 传感器的方向 源码 Madgwick_9.c Madgwick_9.h 使用方法 测试 main.c 效果 STC15F2K60S2 22.1184MHz Keil uVision V5.29. ...

  4. 【51单片机快速入门指南】6.4:DHT11、DHT22单总线温湿度传感器

    目录 硬知识 DHT11 DHT22 通信协议 读取步骤 数据解读 DHT11 DHT22 示例程序 DHT11_22.c DHT11_22.h 测试程序 main.c 实验现象 DHT11 DHT2 ...

  5. 【51单片机快速入门指南】4.6:I2C 与 PCF8563实时时钟日历芯片

    目录 硬知识 概述 特性 功能描述 报警功能模式 定时器模式 CLKOUT输出 复位低电压检测器和时钟监视器 低电压检测器和时钟监视器 寄存器结构 寄存器概述 BCD编码格式寄存器概述 Control ...

  6. 【51单片机快速入门指南】6.3:DS18B20 单总线数字温度计的多路读取

    目录 硬知识 DS18B20介绍 时序 初始化时序 写时序 读时序 命令 ROM 操作命令 ROM 搜索举例 存贮器操作命令 示例程序 DS18B20.c DS18B20.h 测试程序 定时器中断服务 ...

  7. 【51单片机快速入门指南】6.1:LCD1602的八线、四线控制及自定义符号,完美兼容Proteus仿真

    目录 硬知识 显示特性 接口定义 操作时序 写操作时序 读操作时序 寄存器 忙标志位BF 地址计数器(AC) 显示数据寄存器(DDRAM) CGROM CGRAM 指令 清屏指令 光标归位指令 进入模 ...

  8. 【51单片机快速入门指南】5.3:SPI控制晶联讯JLX12864G_08602 LCD屏幕

    目录 示例程序 JLX12864G_08602.c JLX12864G_08602.h JLX12864G_08602_Font.c JLX12864G_08602_Font.h 测试程序 main. ...

  9. 【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片

    目录 硬知识 DS1302 简介 DS1302 使用 控制寄存器 日历/时钟寄存器 DS1302 的读写时序 电路设计 示例程序 DS1302.c DS1302.h 测试程序 main.c 实验现象 ...

最新文章

  1. PCL工程的CMakeList.txt文件书写规范
  2. 机器学习常见的几个误区--逻辑回归的变量之间如果线性相关
  3. redis 导出导入详解
  4. mysql示例employees数据库
  5. 浅谈FTP服务的几个知识点
  6. SharePoint 2010 自定义Ribbon实现文档批量下载为Zip文件
  7. java语句电脑定时关机_月光软件站 - 编程文档 - Java - windows定时关机程序
  8. oracle 快速关闭_快速关闭
  9. 获取两个字符串中最大相同子串
  10. Android自定义弹窗页面,Android编程实现的自定义弹窗(PopupWindow)功能示例
  11. 如何修改PDF,PDF怎么旋转页面方向
  12. 图像处理之Texture Synthesis for Mobile Data Communications论文精读
  13. 跨越信息沟通的障碍,构建企业高效应用平台
  14. Python下十进制转换为二进制
  15. 流程图软件lauto_Iauto流程软件
  16. 浏览器页签icon图标的设置和获取
  17. python拯救爱情
  18. 【实用】OS X Lion restore Recovery HD Manually 手工创建 OS X Lion 恢复分区
  19. 热门话题“30岁还没结婚你会考虑将就么?”数据告诉你,网友们都如何做出抉择
  20. 电荷放大器的原理与应用

热门文章

  1. linux中fcntl()、lockf、flock的区别
  2. comparator接口与Comparable接口的区别
  3. php中Session的生成机制、回收机制和存储机制探究
  4. Xcode 的正确打开方式——Debugging
  5. 【pl/sql番外篇】 存储过程 游标
  6. 锐捷官方提供122套实验题.
  7. php如何减缓gc_管理信息传播-使用数据科学减缓错误信息的传播
  8. 熊猫数据集_用熊猫掌握数据聚合
  9. 2043. 简易银行系统
  10. 如何创建一个自记录的Makefile