失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 【51单片机快速入门指南】4.4.3:Madgwick AHRS 九轴姿态融合获取四元数 欧拉角

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

时间:2022-05-02 14:09:00

相关推荐

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

目录

传感器的方向源码Madgwick_9.cMadgwick_9.h使用方法测试main.c效果

STC15F2K60S2 22.1184MHz

Keil uVision V5.29.0.0

PK51 Prof.Developers Kit Version:9.60.0.0

上位机:Vofa+ 1.3.10


移植自AHRS —— LOXO,算法作者:SOH Madgwick

传感器的方向

源码

所用MCU为STC15F2K60S2 使用内部RC时钟,22.1184MHz

stdint.h见【51单片机快速入门指南】1:基础知识和工程创建

软件I2C程序见【51单片机快速入门指南】4: 软件 I2C

串口部分见【51单片机快速入门指南】3.3:USART 串口通信

MPU6050驱动程序见【51单片机快速入门指南】4.3: I2C读取MPU6050陀螺仪的原始数据

HMC5883L/QMC5883L驱动程序见【51单片机快速入门指南】4.4:I2C 读取HMC5883L / QMC5883L 磁力计

磁力计的椭球拟合校准见【51单片机快速入门指南】4.4.1:python串口接收磁力计数据并进行最小二乘法椭球拟合

beta要按需调整,我这里取1.0

Madgwick_9.c

//=====================================================================================================//// Implementation of Madgwick's IMU and AHRS algorithms.// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms//// DateAuthorNotes// 29/09/SOH Madgwick Initial release// 02/10/SOH MadgwickOptimised for reduced CPU load// 19/02/SOH MadgwickMagnetometer measurement is normalised////=====================================================================================================//---------------------------------------------------------------------------------------------------// Header files#include <math.h>#include "MPU6050.h"//---------------------------------------------------------------------------------------------------// Definitions#define beta1.0f// 2 * proportional gain (Kp)//---------------------------------------------------------------------------------------------------// Variable definitionsfloat q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f;// quaternion of sensor frame relative to auxiliary framefloat Pitch = 0.0f, Roll = 0.0f, Yaw = 0.0f;//====================================================================================================// Functionsfloat sampleFreq = 1;float GYRO_K = 1;void MPU6050_Madgwick_Init(float loop_ms){sampleFreq = 1000. / loop_ms;//sample frequency in Hzswitch((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;}}//---------------------------------------------------------------------------------------------------// Fast inverse square-root// See: /wiki/Fast_inverse_square_rootfloat invSqrt(float 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;}//---------------------------------------------------------------------------------------------------// AHRS algorithm update//---------------------------------------------------------------------------------------------------// IMU algorithm updatevoid MadgwickAHRSupdate_6(float gx, float gy, float gz, float ax, float ay, float az) {float recipNorm;float s0, s1, s2, s3;float qDot1, qDot2, qDot3, qDot4;float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3;//将陀螺仪AD值转换为 弧度/sgx = gx * GYRO_K;gy = gy * GYRO_K;gz = gz * GYRO_K;// Rate of change of quaternion from gyroscopeqDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz);qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy);qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx);qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx);// Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {// Normalise accelerometer measurementrecipNorm = invSqrt(ax * ax + ay * ay + az * az);ax *= recipNorm;ay *= recipNorm;az *= recipNorm; // Auxiliary variables to avoid repeated arithmetic_2q0 = 2.0f * q0;_2q1 = 2.0f * q1;_2q2 = 2.0f * q2;_2q3 = 2.0f * q3;_4q0 = 4.0f * q0;_4q1 = 4.0f * q1;_4q2 = 4.0f * q2;_8q1 = 8.0f * q1;_8q2 = 8.0f * q2;q0q0 = q0 * q0;q1q1 = q1 * q1;q2q2 = q2 * q2;q3q3 = q3 * q3;// Gradient decent algorithm corrective steps0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay;s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az;s2 = 4.0f * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az;s3 = 4.0f * q1q1 * q3 - _2q1 * ax + 4.0f * q2q2 * q3 - _2q2 * ay;recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitudes0 *= recipNorm;s1 *= recipNorm;s2 *= recipNorm;s3 *= recipNorm;// Apply feedback stepqDot1 -= beta * s0;qDot2 -= beta * s1;qDot3 -= beta * s2;qDot4 -= beta * s3;}// Integrate rate of change of quaternion to yield quaternionq0 += qDot1 * (1.0f / sampleFreq);q1 += qDot2 * (1.0f / sampleFreq);q2 += qDot3 * (1.0f / sampleFreq);q3 += qDot4 * (1.0f / sampleFreq);// Normalise quaternionrecipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);q0 *= recipNorm;q1 *= recipNorm;q2 *= recipNorm;q3 *= recipNorm;Pitch = asin(-2.0f * (q1*q3 - q0*q2))* 57.3f;Roll = atan2(q0*q1 + q2*q3, 0.5f - q1*q1 - q2*q2) * 57.3f;Yaw = atan2(q1*q2 + q0*q3, 0.5f - q2*q2 - q3*q3)* 57.3f;}void MadgwickAHRSupdate_9(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) {float recipNorm;float s0, s1, s2, s3;float qDot1, qDot2, qDot3, qDot4;float hx, hy;float _2q0mx, _2q0my, _2q0mz, _2q1mx, _2bx, _2bz, _4bx, _4bz, _2q0, _2q1, _2q2, _2q3, _2q0q2, _2q2q3, q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3;// Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation)if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) {MadgwickAHRSupdate_6(gx, gy, gz, ax, ay, az);return;}//将陀螺仪AD值转换为 弧度/sgx = gx * GYRO_K;gy = gy * GYRO_K;gz = gz * GYRO_K;// Rate of change of quaternion from gyroscopeqDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz);qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy);qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx);qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx);// Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {// Normalise accelerometer measurementrecipNorm = invSqrt(ax * ax + ay * ay + az * az);ax *= recipNorm;ay *= recipNorm;az *= recipNorm; // Normalise magnetometer measurementrecipNorm = invSqrt(mx * mx + my * my + mz * mz);mx *= recipNorm;my *= recipNorm;mz *= recipNorm;// Auxiliary variables to avoid repeated arithmetic_2q0mx = 2.0f * q0 * mx;_2q0my = 2.0f * q0 * my;_2q0mz = 2.0f * q0 * mz;_2q1mx = 2.0f * q1 * mx;_2q0 = 2.0f * q0;_2q1 = 2.0f * q1;_2q2 = 2.0f * q2;_2q3 = 2.0f * q3;_2q0q2 = 2.0f * q0 * q2;_2q2q3 = 2.0f * q2 * q3;q0q0 = q0 * q0;q0q1 = q0 * q1;q0q2 = q0 * q2;q0q3 = q0 * q3;q1q1 = q1 * q1;q1q2 = q1 * q2;q1q3 = q1 * q3;q2q2 = q2 * q2;q2q3 = q2 * q3;q3q3 = q3 * q3;// Reference direction of Earth's magnetic fieldhx = mx * q0q0 - _2q0my * q3 + _2q0mz * q2 + mx * q1q1 + _2q1 * my * q2 + _2q1 * mz * q3 - mx * q2q2 - mx * q3q3;hy = _2q0mx * q3 + my * q0q0 - _2q0mz * q1 + _2q1mx * q2 - my * q1q1 + my * q2q2 + _2q2 * mz * q3 - my * q3q3;_2bx = sqrt(hx * hx + hy * hy);_2bz = -_2q0mx * q2 + _2q0my * q1 + mz * q0q0 + _2q1mx * q3 - mz * q1q1 + _2q2 * my * q3 - mz * q2q2 + mz * q3q3;_4bx = 2.0f * _2bx;_4bz = 2.0f * _2bz;// Gradient decent algorithm corrective steps0 = -_2q2 * (2.0f * q1q3 - _2q0q2 - ax) + _2q1 * (2.0f * q0q1 + _2q2q3 - ay) - _2bz * q2 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q3 + _2bz * q1) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q2 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);s1 = _2q3 * (2.0f * q1q3 - _2q0q2 - ax) + _2q0 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q1 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + _2bz * q3 * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q2 + _2bz * q0) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q3 - _4bz * q1) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);s2 = -_2q0 * (2.0f * q1q3 - _2q0q2 - ax) + _2q3 * (2.0f * q0q1 + _2q2q3 - ay) - 4.0f * q2 * (1 - 2.0f * q1q1 - 2.0f * q2q2 - az) + (-_4bx * q2 - _2bz * q0) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (_2bx * q1 + _2bz * q3) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + (_2bx * q0 - _4bz * q2) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);s3 = _2q1 * (2.0f * q1q3 - _2q0q2 - ax) + _2q2 * (2.0f * q0q1 + _2q2q3 - ay) + (-_4bx * q3 + _2bz * q1) * (_2bx * (0.5f - q2q2 - q3q3) + _2bz * (q1q3 - q0q2) - mx) + (-_2bx * q0 + _2bz * q2) * (_2bx * (q1q2 - q0q3) + _2bz * (q0q1 + q2q3) - my) + _2bx * q1 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5f - q1q1 - q2q2) - mz);recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitudes0 *= recipNorm;s1 *= recipNorm;s2 *= recipNorm;s3 *= recipNorm;// Apply feedback stepqDot1 -= beta * s0;qDot2 -= beta * s1;qDot3 -= beta * s2;qDot4 -= beta * s3;}// Integrate rate of change of quaternion to yield quaternionq0 += qDot1 * (1.0f / sampleFreq);q1 += qDot2 * (1.0f / sampleFreq);q2 += qDot3 * (1.0f / sampleFreq);q3 += qDot4 * (1.0f / sampleFreq);// Normalise quaternionrecipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);q0 *= recipNorm;q1 *= recipNorm;q2 *= recipNorm;q3 *= recipNorm;Pitch = asin(-2.0f * (q1*q3 - q0*q2))* 57.3f;Roll = atan2(q0*q1 + q2*q3, 0.5f - q1*q1 - q2*q2) * 57.3f;Yaw = atan2(q1*q2 + q0*q3, 0.5f - q2*q2 - q3*q3)* 57.3f;}//====================================================================================================// END OF CODE//====================================================================================================

Madgwick_9.h

#ifndef Madgwick_9_H_#define Madgwick_9_H_extern float Pitch, Roll, Yaw;extern float q0, q1, q2, q3;void MPU6050_Madgwick_Init(float loop_ms);void MadgwickAHRSupdate_6(float gx, float gy, float gz, float ax, float ay, float az);void MadgwickAHRSupdate_9(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz);#endif

使用方法

先调用MPU6050_Madgwick_Init(dt),参数为一次循环的时间,单位为ms

再使用MadgwickAHRSupdate_9姿态融合函数。

测试

陀螺仪、磁力计的原始数据经校准后输入MadgwickAHRSupdate_9函数

main.c

#include <STC15F2K60S2.H>#include "intrins.h"#include "stdint.h"#include "USART.h"#include "./Software_I2C/Software_I2C.h"#include "XMC5883L.h"#include "./MPU6050/MPU6050.h"#include "./MPU6050/Madgwick_9.h"void Delay1ms()//@22.1184MHz{unsigned char i, j;_nop_();_nop_();i = 22;j = 128;do{while (--j);} while (--i);}void delay_ms(uint32_t ms){while(ms --)Delay1ms();}#define LED_PORT P0void main(void){int16_t mag_x, mag_y, mag_z;int16_t aacx,aacy,aacz;//加速度传感器原始数据int16_t gyrox,gyroy,gyroz;//陀螺仪原始数据MPU_Init();xmc5883lInit();AUXR &= 0xBF;//定时器时钟12T模式 1T的51使用12T的定时器程序时需要加入这两句AUXR &= 0xFE;//串口1选择定时器1为波特率发生器USART_Init(USART_MODE_1, Rx_ENABLE, STC_USART_Priority_Lowest, 22118400, 115200, DOUBLE_BAUD_ENABLE, USART_TIMER_1);MPU6050_Madgwick_Init(10.48);while(1){MPU_Get_Accelerometer(&aacx, &aacy, &aacz);//得到加速度传感器数据MPU_Get_Gyroscope(&gyrox, &gyroy, &gyroz);//得到陀螺仪数据xmc5883lRead(&mag_x, &mag_y, &mag_z);MadgwickAHRSupdate_9(gyrox+7, gyroy+23, gyroz-1, aacx, aacy, aacz, 1.108270606866881 * (mag_x + 297.2882033958856), 0.9218994400020794 * (mag_y + 3088.0092054124193), 0.9871899380641738 * (mag_z + 782.925290575134));printf("%f, ", Pitch);printf("%f, ", Roll);printf("%f\r\n", Yaw);}}

效果

如果觉得《【51单片机快速入门指南】4.4.3:Madgwick AHRS 九轴姿态融合获取四元数 欧拉角》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。