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.
MahonyAHRS.cpp
00001 // Header files 00002 00003 #include "mbed.h" 00004 #include "MahonyAHRS.h" 00005 #include <math.h> 00006 00007 //--------------------------------------------------------------------------------------------------- 00008 // Definitions 00009 00010 //#define sampleFreq 512.0f // sample frequency in Hz 00011 #define twoKpDef (2.0f * 50.0f) // 2 * proportional gain 00012 #define twoKiDef (2.0f * 0.25f) // 2 * integral gain 00013 #define PI 3.14159265359f 00014 00015 //--------------------------------------------------------------------------------------------------- 00016 00017 MahonyAHRS::MahonyAHRS(float Freq){ 00018 00019 sampleFreq = Freq; 00020 00021 } 00022 00023 float twoKp = twoKpDef; // 2 * proportional gain (Kp) 00024 float twoKi = twoKiDef; // 2 * integral gain (Ki) 00025 float q4 = 1.0f, q5 = 0.0f, q6 = 0.0f, q7 = 0.0f; // quaternion of sensor frame relative to auxiliary frame 00026 float integralFBx = 0.0f, integralFBy = 0.0f, integralFBz = 0.0f; // integral error terms scaled by Ki 00027 00028 00029 float inv_Sqrt(float x); 00030 00031 //==================================================================================================== 00032 // Functions 00033 00034 //--------------------------------------------------------------------------------------------------- 00035 // AHRS algorithm update 00036 00037 void MahonyAHRS::update(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) { 00038 float recipNorm; 00039 float q4q4, q4q5, q4q6, q4q7, q5q5, q5q6, q5q7, q6q6, q6q7, q7q7; 00040 float hx, hy, bx, bz; 00041 float halfvx, halfvy, halfvz, halfwx, halfwy, halfwz; 00042 float halfex, halfey, halfez; 00043 float qa, qb, qc; 00044 00045 // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation) 00046 if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) { 00047 MahonyAHRS::updateIMU(gx, gy, gz, ax, ay, az); 00048 return; 00049 } 00050 00051 // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) 00052 if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { 00053 00054 // Normalise accelerometer measurement 00055 recipNorm = inv_Sqrt(ax * ax + ay * ay + az * az); 00056 ax *= recipNorm; 00057 ay *= recipNorm; 00058 az *= recipNorm; 00059 00060 // Normalise magnetometer measurement 00061 recipNorm = inv_Sqrt(mx * mx + my * my + mz * mz); 00062 mx *= recipNorm; 00063 my *= recipNorm; 00064 mz *= recipNorm; 00065 00066 // Auxiliary variables to avoid repeated arithmetic 00067 q4q4 = q4 * q4; 00068 q4q5 = q4 * q5; 00069 q4q6 = q4 * q6; 00070 q4q7 = q4 * q7; 00071 q5q5 = q5 * q5; 00072 q5q6 = q5 * q6; 00073 q5q7 = q5 * q7; 00074 q6q6 = q6 * q6; 00075 q6q7 = q6 * q7; 00076 q7q7 = q7 * q7; 00077 00078 // Reference direction of Earth's magnetic field 00079 hx = 2.0f * (mx * (0.5f - q6q6 - q7q7) + my * (q5q6 - q4q7) + mz * (q5q7 + q4q6)); 00080 hy = 2.0f * (mx * (q5q6 + q4q7) + my * (0.5f - q5q5 - q7q7) + mz * (q6q7 - q4q5)); 00081 bx = sqrt(hx * hx + hy * hy); 00082 bz = 2.0f * (mx * (q5q7 - q4q6) + my * (q6q7 + q4q5) + mz * (0.5f - q5q5 - q6q6)); 00083 00084 // Estimated direction of gravity and magnetic field 00085 halfvx = q5q7 - q4q6; 00086 halfvy = q4q5 + q6q7; 00087 halfvz = q4q4 - 0.5f + q7q7; 00088 halfwx = bx * (0.5f - q6q6 - q7q7) + bz * (q5q7 - q4q6); 00089 halfwy = bx * (q5q6 - q4q7) + bz * (q4q5 + q6q7); 00090 halfwz = bx * (q4q6 + q5q7) + bz * (0.5f - q5q5 - q6q6); 00091 00092 // Error is sum of cross product between estimated direction and measured direction of field vectors 00093 halfex = (ay * halfvz - az * halfvy) + (my * halfwz - mz * halfwy); 00094 halfey = (az * halfvx - ax * halfvz) + (mz * halfwx - mx * halfwz); 00095 halfez = (ax * halfvy - ay * halfvx) + (mx * halfwy - my * halfwx); 00096 00097 // Compute and apply integral feedback if enabled 00098 if(twoKi > 0.0f) { 00099 integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki 00100 integralFBy += twoKi * halfey * (1.0f / sampleFreq); 00101 integralFBz += twoKi * halfez * (1.0f / sampleFreq); 00102 gx += integralFBx; // apply integral feedback 00103 gy += integralFBy; 00104 gz += integralFBz; 00105 } 00106 else { 00107 integralFBx = 0.0f; // prevent integral windup 00108 integralFBy = 0.0f; 00109 integralFBz = 0.0f; 00110 } 00111 00112 // Apply proportional feedback 00113 gx += twoKp * halfex; 00114 gy += twoKp * halfey; 00115 gz += twoKp * halfez; 00116 } 00117 00118 // Integrate rate of change of quaternion 00119 gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors 00120 gy *= (0.5f * (1.0f / sampleFreq)); 00121 gz *= (0.5f * (1.0f / sampleFreq)); 00122 qa = q4; 00123 qb = q5; 00124 qc = q6; 00125 q4 += (-qb * gx - qc * gy - q7 * gz); 00126 q5 += (qa * gx + qc * gz - q7 * gy); 00127 q6 += (qa * gy - qb * gz + q7 * gx); 00128 q7 += (qa * gz + qb * gy - qc * gx); 00129 00130 // Normalise quaternion 00131 recipNorm = inv_Sqrt(q4 * q4 + q5 * q5 + q6 * q6 + q7 * q7); 00132 q4 *= recipNorm; 00133 q5 *= recipNorm; 00134 q6 *= recipNorm; 00135 q7 *= recipNorm; 00136 } 00137 00138 //--------------------------------------------------------------------------------------------------- 00139 // IMU algorithm update 00140 00141 void MahonyAHRS::updateIMU(float gx, float gy, float gz, float ax, float ay, float az) { 00142 float recipNorm; 00143 float halfvx, halfvy, halfvz; 00144 float halfex, halfey, halfez; 00145 float qa, qb, qc; 00146 00147 // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) 00148 if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { 00149 00150 // Normalise accelerometer measurement 00151 recipNorm = inv_Sqrt(ax * ax + ay * ay + az * az); 00152 ax *= recipNorm; 00153 ay *= recipNorm; 00154 az *= recipNorm; 00155 00156 // Estimated direction of gravity and vector perpendicular to magnetic flux 00157 halfvx = q5 * q7 - q4 * q6; 00158 halfvy = q4 * q5 + q6 * q7; 00159 halfvz = q4 * q4 - 0.5f + q7 * q7; 00160 00161 // Error is sum of cross product between estimated and measured direction of gravity 00162 halfex = (ay * halfvz - az * halfvy); 00163 halfey = (az * halfvx - ax * halfvz); 00164 halfez = (ax * halfvy - ay * halfvx); 00165 00166 // Compute and apply integral feedback if enabled 00167 if(twoKi > 0.0f) { 00168 integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki 00169 integralFBy += twoKi * halfey * (1.0f / sampleFreq); 00170 integralFBz += twoKi * halfez * (1.0f / sampleFreq); 00171 gx += integralFBx; // apply integral feedback 00172 gy += integralFBy; 00173 gz += integralFBz; 00174 } 00175 else { 00176 integralFBx = 0.0f; // prevent integral windup 00177 integralFBy = 0.0f; 00178 integralFBz = 0.0f; 00179 } 00180 00181 // Apply proportional feedback 00182 gx += twoKp * halfex; 00183 gy += twoKp * halfey; 00184 gz += twoKp * halfez; 00185 } 00186 00187 // Integrate rate of change of quaternion 00188 gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors 00189 gy *= (0.5f * (1.0f / sampleFreq)); 00190 gz *= (0.5f * (1.0f / sampleFreq)); 00191 qa = q4; 00192 qb = q5; 00193 qc = q6; 00194 q4 += (-qb * gx - qc * gy - q7 * gz); 00195 q5 += (qa * gx + qc * gz - q7 * gy); 00196 q6 += (qa * gy - qb * gz + q7 * gx); 00197 q7 += (qa * gz + qb * gy - qc * gx); 00198 00199 // Normalise quaternion 00200 recipNorm = inv_Sqrt(q4 * q4 + q5 * q5 + q6 * q6 + q7 * q7); 00201 q4 *= recipNorm; 00202 q5 *= recipNorm; 00203 q6 *= recipNorm; 00204 q7 *= recipNorm; 00205 } 00206 00207 //--------------------------------------------------------------------------------------------------- 00208 // Fast inverse square-root 00209 // See: http://en.wikipedia.org/wiki/Fast_inverse_square_root 00210 00211 float inv_Sqrt(float x) { 00212 float halfx = 0.5f * x; 00213 float y = x; 00214 long i = *(long*)&y; 00215 i = 0x5f3759df - (i>>1); 00216 y = *(float*)&i; 00217 y = y * (1.5f - (halfx * y * y)); 00218 return y; 00219 } 00220 00221 00222 void MahonyAHRS::getEuler(){ 00223 00224 float gx = 2*(q5*q7 - q4*q6); 00225 float gy = 2 * (q4*q5 + q6*q7); 00226 float gz = q4*q4 - q5*q5 - q6*q6 + q7*q7; 00227 00228 roll = atan(gy / sqrt(gx*gx + gz*gz)); 00229 pitch = atan(gx / sqrt(gy*gy + gz*gz)); 00230 yaw = atan2(2 * q5 * q6 - 2 * q4 * q7, 2 * q4*q4 + 2 * q5 * q5 - 1); 00231 00232 roll = roll*180/PI; 00233 pitch = pitch*180/PI; 00234 yaw = yaw*180/PI; 00235 00236 if (ceil(roll) - roll <= .5){ 00237 roll = ceil(roll); 00238 } 00239 else{ 00240 roll = floor(roll); 00241 } 00242 00243 if (ceil(pitch) - pitch <= .5){ 00244 pitch = ceil(pitch); 00245 } 00246 else{ 00247 pitch = floor(pitch); 00248 } 00249 00250 if (ceil(yaw) - yaw <= .5){ 00251 yaw = ceil(yaw); 00252 } 00253 else{ 00254 yaw = floor(yaw); 00255 } 00256 } 00257 00258 int16_t MahonyAHRS::getRoll(){ 00259 return (int16_t)roll; 00260 } 00261 00262 int16_t MahonyAHRS::getPitch(){ 00263 return (int16_t)pitch; 00264 } 00265 00266 int16_t MahonyAHRS::getYaw(){ 00267 return (int16_t)yaw; 00268 } 00269 00270 //==================================================================================================== 00271 // END OF CODE 00272 //====================================================================================================
Generated on Sun Jul 17 2022 01:44:57 by
1.7.2