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/open-source-imu-and-ahrs-algorithms/ 00007 // 00008 // From the x-io website "Open-source resources available on this website are 00009 // provided under the GNU General Public Licence unless an alternative licence 00010 // is provided in source." 00011 // 00012 // Date Author Notes 00013 // 29/09/2011 SOH Madgwick Initial release 00014 // 02/10/2011 SOH Madgwick Optimised for reduced CPU load 00015 // 19/02/2012 SOH Madgwick Magnetometer measurement is normalised 00016 // 00017 //============================================================================================= 00018 00019 //------------------------------------------------------------------------------------------- 00020 // Header files 00021 00022 #include "MadgwickAHRS.h" 00023 #include <math.h> 00024 #include <stdio.h> 00025 #include "ros.h" 00026 00027 #if (NO_ROS) 00028 extern Serial pc; 00029 #else 00030 extern ros::NodeHandle nh; 00031 #endif 00032 //------------------------------------------------------------------------------------------- 00033 // Definitions 00034 00035 #define sampleFreqDef 512.0f // sample frequency in Hz 00036 #define betaDef 0.1f // 2 * proportional gain 00037 00038 00039 00040 //============================================================================================ 00041 // Functions 00042 00043 //------------------------------------------------------------------------------------------- 00044 // AHRS algorithm update 00045 00046 Madgwick::Madgwick() { 00047 beta = betaDef; 00048 q0 = 1.0f; 00049 q1 = 0.0f; 00050 q2 = 0.0f; 00051 q3 = 0.0f; 00052 invSampleFreq = 1.0f / sampleFreqDef; 00053 00054 anglesComputed = 0; 00055 00056 } 00057 00058 void Madgwick::update(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) { 00059 float recipNorm; 00060 float s0, s1, s2, s3; 00061 float qDot1, qDot2, qDot3, qDot4; 00062 float hx, hy; 00063 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; 00064 00065 00066 // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation) 00067 if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) { 00068 updateIMU(gx, gy, gz, ax, ay, az); 00069 return; 00070 } 00071 00072 // Convert gyroscope degrees/sec to radians/sec 00073 gx *= 0.0174533f; 00074 gy *= 0.0174533f; 00075 gz *= 0.0174533f; 00076 00077 // Rate of change of quaternion from gyroscope 00078 qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz); 00079 qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy); 00080 qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx); 00081 qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx); 00082 00083 // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) 00084 if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { 00085 00086 // Normalise accelerometer measurement 00087 recipNorm = invSqrt(ax * ax + ay * ay + az * az); 00088 ax *= recipNorm; 00089 ay *= recipNorm; 00090 az *= recipNorm; 00091 00092 // Normalise magnetometer measurement 00093 recipNorm = invSqrt(mx * mx + my * my + mz * mz); 00094 mx *= recipNorm; 00095 my *= recipNorm; 00096 mz *= recipNorm; 00097 00098 // Auxiliary variables to avoid repeated arithmetic 00099 _2q0mx = 2.0f * q0 * mx; 00100 _2q0my = 2.0f * q0 * my; 00101 _2q0mz = 2.0f * q0 * mz; 00102 _2q1mx = 2.0f * q1 * mx; 00103 _2q0 = 2.0f * q0; 00104 _2q1 = 2.0f * q1; 00105 _2q2 = 2.0f * q2; 00106 _2q3 = 2.0f * q3; 00107 _2q0q2 = 2.0f * q0 * q2; 00108 _2q2q3 = 2.0f * q2 * q3; 00109 q0q0 = q0 * q0; 00110 q0q1 = q0 * q1; 00111 q0q2 = q0 * q2; 00112 q0q3 = q0 * q3; 00113 q1q1 = q1 * q1; 00114 q1q2 = q1 * q2; 00115 q1q3 = q1 * q3; 00116 q2q2 = q2 * q2; 00117 q2q3 = q2 * q3; 00118 q3q3 = q3 * q3; 00119 00120 // Reference direction of Earth's magnetic field 00121 hx = mx * q0q0 - _2q0my * q3 + _2q0mz * q2 + mx * q1q1 + _2q1 * my * q2 + _2q1 * mz * q3 - mx * q2q2 - mx * q3q3; 00122 hy = _2q0mx * q3 + my * q0q0 - _2q0mz * q1 + _2q1mx * q2 - my * q1q1 + my * q2q2 + _2q2 * mz * q3 - my * q3q3; 00123 _2bx = sqrtf(hx * hx + hy * hy); 00124 _2bz = -_2q0mx * q2 + _2q0my * q1 + mz * q0q0 + _2q1mx * q3 - mz * q1q1 + _2q2 * my * q3 - mz * q2q2 + mz * q3q3; 00125 _4bx = 2.0f * _2bx; 00126 _4bz = 2.0f * _2bz; 00127 00128 // Gradient decent algorithm corrective step 00129 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); 00130 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); 00131 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); 00132 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); 00133 recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude 00134 s0 *= recipNorm; 00135 s1 *= recipNorm; 00136 s2 *= recipNorm; 00137 s3 *= recipNorm; 00138 00139 // Apply feedback step 00140 qDot1 -= beta * s0; 00141 qDot2 -= beta * s1; 00142 qDot3 -= beta * s2; 00143 qDot4 -= beta * s3; 00144 } 00145 00146 // Integrate rate of change of quaternion to yield quaternion 00147 q0 += qDot1 * invSampleFreq; 00148 q1 += qDot2 * invSampleFreq; 00149 q2 += qDot3 * invSampleFreq; 00150 q3 += qDot4 * invSampleFreq; 00151 00152 // Normalise quaternion 00153 recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); 00154 q0 *= recipNorm; 00155 q1 *= recipNorm; 00156 q2 *= recipNorm; 00157 q3 *= recipNorm; 00158 anglesComputed = 0; 00159 } 00160 00161 //------------------------------------------------------------------------------------------- 00162 // IMU algorithm update 00163 00164 void Madgwick::updateIMU(float gx, float gy, float gz, float ax, float ay, float az) { 00165 float recipNorm; 00166 float s0, s1, s2, s3; 00167 float qDot1, qDot2, qDot3, qDot4; 00168 float _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3; 00169 char tempstr[64] = {}; 00170 //pc.printf("q_pre: %.3f %.3f %.3f %.3f\n\r",q0,q1,q2,q3); 00171 /* 00172 sprintf(tempstr,"%f %f %f %f %f %f",gx,gy,gz,ax,ay,az); 00173 nh.loginfo("gx gy gz ax ay az"); 00174 nh.loginfo(tempstr); 00175 */ 00176 00177 // Convert gyroscope degrees/sec to radians/sec 00178 00179 gx *= 0.0174533f; 00180 gy *= 0.0174533f; 00181 gz *= 0.0174533f; 00182 //pc.printf("%f %f %f %f %f %f \n\r",gx,gy,gz,ax,ay,az); 00183 // Rate of change of quaternion from gyroscope 00184 00185 qDot1 = 0.5f * (-q1 * gx - q2 * gy - q3 * gz); 00186 qDot2 = 0.5f * (q0 * gx + q2 * gz - q3 * gy); 00187 qDot3 = 0.5f * (q0 * gy - q1 * gz + q3 * gx); 00188 qDot4 = 0.5f * (q0 * gz + q1 * gy - q2 * gx); 00189 //pc.printf("%.5f %.5f %.5f %.5f ",qDot1,qDot2,qDot3,qDot4); 00190 // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) 00191 if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { 00192 00193 // Normalise accelerometer measurement 00194 recipNorm = invSqrt(ax * ax + ay * ay + az * az); 00195 //pc.printf("nomalized acc: %.5f\n\r",recipNorm); 00196 ax *= recipNorm; 00197 ay *= recipNorm; 00198 az *= recipNorm; 00199 00200 // Auxiliary variables to avoid repeated arithmetic 00201 _2q0 = 2.0f * q0; 00202 _2q1 = 2.0f * q1; 00203 _2q2 = 2.0f * q2; 00204 _2q3 = 2.0f * q3; 00205 _4q0 = 4.0f * q0; 00206 _4q1 = 4.0f * q1; 00207 _4q2 = 4.0f * q2; 00208 _8q1 = 8.0f * q1; 00209 _8q2 = 8.0f * q2; 00210 q0q0 = q0 * q0; 00211 q1q1 = q1 * q1; 00212 q2q2 = q2 * q2; 00213 q3q3 = q3 * q3; 00214 00215 // Gradient decent algorithm corrective step 00216 s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1 - _2q1 * ay; 00217 s1 = _4q1 * q3q3 - _2q3 * ax + 4.0f * q0q0 * q1 - _2q0 * ay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az; 00218 s2 = 4.0f * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3 - _2q3 * ay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az; 00219 s3 = 4.0f * q1q1 * q3 - _2q1 * ax + 4.0f * q2q2 * q3 - _2q2 * ay; 00220 00221 recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude 00222 //pc.printf("nomalized step: %.5f\n\r",recipNorm); 00223 s0 *= recipNorm; 00224 s1 *= recipNorm; 00225 s2 *= recipNorm; 00226 s3 *= recipNorm; 00227 //pc.printf("%.5f %.5f %.5f %.5f ",s0,s1,s2,s3); 00228 // Apply feedback step 00229 qDot1 -= beta * s0; 00230 qDot2 -= beta * s1; 00231 qDot3 -= beta * s2; 00232 qDot4 -= beta * s3; 00233 //pc.printf("%.5f %.5f %.5f %.5f ",qDot1,qDot2,qDot3,qDot4); 00234 //pc.printf("\n\r---------------------------------------------------------------------------\n\r"); 00235 } 00236 00237 // Integrate rate of change of quaternion to yield quaternion 00238 q0 += qDot1 * invSampleFreq; 00239 q1 += qDot2 * invSampleFreq; 00240 q2 += qDot3 * invSampleFreq; 00241 q3 += qDot4 * invSampleFreq; 00242 //pc.printf("\n\rinvSampleFreq: %.5f\n\r",invSampleFreq); 00243 // Normalise quaternion 00244 recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); 00245 q0 *= recipNorm; 00246 q1 *= recipNorm; 00247 q2 *= recipNorm; 00248 q3 *= recipNorm; 00249 //pc.printf("nomalized quaternion: %.5f\n\r",recipNorm); 00250 anglesComputed = 0; 00251 } 00252 00253 //------------------------------------------------------------------------------------------- 00254 // Fast inverse square-root 00255 // See: http://en.wikipedia.org/wiki/Fast_inverse_square_root 00256 00257 float Madgwick::invSqrt(float x) { 00258 float halfx = 0.5f * x; 00259 float y = x; 00260 long i = *(long*)&y; 00261 i = 0x5f3759df - (i>>1); 00262 y = *(float*)&i; 00263 y = y * (1.5f - (halfx * y * y)); 00264 y = y * (1.5f - (halfx * y * y)); 00265 return y; 00266 } 00267 00268 //------------------------------------------------------------------------------------------- 00269 00270 void Madgwick::computeAngles() 00271 { 00272 roll = atan2f(q0*q1 + q2*q3, 0.5f - q1*q1 - q2*q2); 00273 pitch = asinf(-2.0f * (q1*q3 - q0*q2)); 00274 yaw = atan2f(q1*q2 + q0*q3, 0.5f - q2*q2 - q3*q3); 00275 anglesComputed = 1; 00276 } 00277 00278
Generated on Tue Jul 12 2022 18:31:23 by
1.7.2