Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
MadgwickAHRS.cpp
00001 //===================================================================================================== 00002 // MadgwickAHRS.c 00003 //===================================================================================================== 00004 // 00005 // Implementation of Madgwick's IMU and AHRS algorithms. 00006 // See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms 00007 // 00008 // Date Author Notes 00009 // 29/09/2011 SOH Madgwick Initial release 00010 // 02/10/2011 SOH Madgwick Optimised for reduced CPU load 00011 // 19/02/2012 SOH Madgwick Magnetometer measurement is normalised 00012 // 00013 //===================================================================================================== 00014 00015 //--------------------------------------------------------------------------------------------------- 00016 // Header files 00017 00018 #include "MadgwickAHRS.h" 00019 #include <math.h> 00020 00021 //--------------------------------------------------------------------------------------------------- 00022 // Definitions 00023 00024 #define sampleFreq 512.0f // sample frequency in Hz 00025 #define betaDef 0.1f // 2 * proportional gain 00026 00027 //--------------------------------------------------------------------------------------------------- 00028 // Variable definitions 00029 00030 volatile float beta = betaDef; // 2 * proportional gain (Kp) 00031 volatile float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; // quaternion of sensor frame relative to auxiliary frame 00032 00033 //--------------------------------------------------------------------------------------------------- 00034 // Function declarations 00035 00036 float invSqrt(float x); 00037 00038 //==================================================================================================== 00039 // Functions 00040 00041 //--------------------------------------------------------------------------------------------------- 00042 // AHRS algorithm update 00043 00044 void MadgwickAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) { 00045 float recipNorm; 00046 float s0, s1, s2, s3; 00047 float qDot1, qDot2, qDot3, qDot4; 00048 float hx, hy; 00049 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; 00050 00051 // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation) 00052 if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) { 00053 MadgwickAHRSupdateIMU(gx, gy, gz, ax, ay, az); 00054 return; 00055 } 00056 00057 // Rate of change of quaternion from gyroscope 00058 qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz); 00059 qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy); 00060 qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx); 00061 qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx); 00062 00063 // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) 00064 if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { 00065 00066 // Normalise accelerometer measurement 00067 recipNorm = invSqrt(ax * ax + ay * ay + az * az); 00068 ax *= recipNorm; 00069 ay *= recipNorm; 00070 az *= recipNorm; 00071 00072 // Normalise magnetometer measurement 00073 recipNorm = invSqrt(mx * mx + my * my + mz * mz); 00074 mx *= recipNorm; 00075 my *= recipNorm; 00076 mz *= recipNorm; 00077 00078 // Auxiliary variables to avoid repeated arithmetic 00079 _2q0mx = 2.0f * q0 * mx; 00080 _2q0my = 2.0f * q0 * my; 00081 _2q0mz = 2.0f * q0 * mz; 00082 _2q1mx = 2.0f * q1 * mx; 00083 _2q0 = 2.0f * q0; 00084 _2q1 = 2.0f * q1; 00085 _2q2 = 2.0f * q2; 00086 _2q3 = 2.0f * q3; 00087 _2q0q2 = 2.0f * q0 * q2; 00088 _2q2q3 = 2.0f * q2 * q3; 00089 q0q0 = q0 * q0; 00090 q0q1 = q0 * q1; 00091 q0q2 = q0 * q2; 00092 q0q3 = q0 * q3; 00093 q1q1 = q1 * q1; 00094 q1q2 = q1 * q2; 00095 q1q3 = q1 * q3; 00096 q2q2 = q2 * q2; 00097 q2q3 = q2 * q3; 00098 q3q3 = q3 * q3; 00099 00100 // Reference direction of Earth's magnetic field 00101 hx = mx * q0q0 - _2q0my * q3 + _2q0mz * q2 + mx * q1q1 + _2q1 * my * q2 + _2q1 * mz * q3 - mx * q2q2 - mx * q3q3; 00102 hy = _2q0mx * q3 + my * q0q0 - _2q0mz * q1 + _2q1mx * q2 - my * q1q1 + my * q2q2 + _2q2 * mz * q3 - my * q3q3; 00103 _2bx = sqrt(hx * hx + hy * hy); 00104 _2bz = -_2q0mx * q2 + _2q0my * q1 + mz * q0q0 + _2q1mx * q3 - mz * q1q1 + _2q2 * my * q3 - mz * q2q2 + mz * q3q3; 00105 _4bx = 2.0f * _2bx; 00106 _4bz = 2.0f * _2bz; 00107 00108 // Gradient decent algorithm corrective step 00109 s0 = -_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); 00110 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); 00111 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); 00112 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); 00113 recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude 00114 s0 *= recipNorm; 00115 s1 *= recipNorm; 00116 s2 *= recipNorm; 00117 s3 *= recipNorm; 00118 00119 // Apply feedback step 00120 qDot1 -= beta * s0; 00121 qDot2 -= beta * s1; 00122 qDot3 -= beta * s2; 00123 qDot4 -= beta * s3; 00124 } 00125 00126 // Integrate rate of change of quaternion to yield quaternion 00127 q0 += qDot1 * (1.0f / sampleFreq); 00128 q1 += qDot2 * (1.0f / sampleFreq); 00129 q2 += qDot3 * (1.0f / sampleFreq); 00130 q3 += qDot4 * (1.0f / sampleFreq); 00131 00132 // Normalise quaternion 00133 recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); 00134 q0 *= recipNorm; 00135 q1 *= recipNorm; 00136 q2 *= recipNorm; 00137 q3 *= recipNorm; 00138 } 00139 00140 //--------------------------------------------------------------------------------------------------- 00141 // IMU algorithm update 00142 00143 void MadgwickAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az) { 00144 float recipNorm; 00145 float s0, s1, s2, s3; 00146 float qDot1, qDot2, qDot3, qDot4; 00147 float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3; 00148 00149 // Rate of change of quaternion from gyroscope 00150 qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz); 00151 qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy); 00152 qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx); 00153 qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx); 00154 00155 // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) 00156 if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { 00157 00158 // Normalise accelerometer measurement 00159 recipNorm = invSqrt(ax * ax + ay * ay + az * az); 00160 ax *= recipNorm; 00161 ay *= recipNorm; 00162 az *= recipNorm; 00163 00164 // Auxiliary variables to avoid repeated arithmetic 00165 _2q0 = 2.0f * q0; 00166 _2q1 = 2.0f * q1; 00167 _2q2 = 2.0f * q2; 00168 _2q3 = 2.0f * q3; 00169 _4q0 = 4.0f * q0; 00170 _4q1 = 4.0f * q1; 00171 _4q2 = 4.0f * q2; 00172 _8q1 = 8.0f * q1; 00173 _8q2 = 8.0f * q2; 00174 q0q0 = q0 * q0; 00175 q1q1 = q1 * q1; 00176 q2q2 = q2 * q2; 00177 q3q3 = q3 * q3; 00178 00179 // Gradient decent algorithm corrective step 00180 s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay; 00181 s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az; 00182 s2 = 4.0f * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az; 00183 s3 = 4.0f * q1q1 * q3 - _2q1 * ax + 4.0f * q2q2 * q3 - _2q2 * ay; 00184 recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude 00185 s0 *= recipNorm; 00186 s1 *= recipNorm; 00187 s2 *= recipNorm; 00188 s3 *= recipNorm; 00189 00190 // Apply feedback step 00191 qDot1 -= beta * s0; 00192 qDot2 -= beta * s1; 00193 qDot3 -= beta * s2; 00194 qDot4 -= beta * s3; 00195 } 00196 00197 // Integrate rate of change of quaternion to yield quaternion 00198 q0 += qDot1 * (1.0f / sampleFreq); 00199 q1 += qDot2 * (1.0f / sampleFreq); 00200 q2 += qDot3 * (1.0f / sampleFreq); 00201 q3 += qDot4 * (1.0f / sampleFreq); 00202 00203 // Normalise quaternion 00204 recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); 00205 q0 *= recipNorm; 00206 q1 *= recipNorm; 00207 q2 *= recipNorm; 00208 q3 *= recipNorm; 00209 } 00210 00211 //--------------------------------------------------------------------------------------------------- 00212 // Fast inverse square-root 00213 // See: http://en.wikipedia.org/wiki/Fast_inverse_square_root 00214 00215 float invSqrt(float x) { 00216 float halfx = 0.5f * x; 00217 float y = x; 00218 long i = *(long*)&y; 00219 i = 0x5f3759df - (i>>1); 00220 y = *(float*)&i; 00221 y = y * (1.5f - (halfx * y * y)); 00222 return y; 00223 } 00224 00225 //==================================================================================================== 00226 // END OF CODE 00227 //====================================================================================================
Generated on Mon Jul 18 2022 10:36:03 by
1.7.2