→目次 | |||
| |||
ネット上で有名な9軸センサーMahonyAHRSアルゴリズムのソースコードMahonyAHRS.cを読んだので注釈を付けました。クォータニオン(四元数)などの知識を事前に軽く勉強すれば、早く理解できるかもしれません。 | |||
1 //===================================================================================================== 2 // MahonyAHRS.c 3 //===================================================================================================== 4 // 5 // Madgwick's implementation of Mayhony's AHRS algorithm. 6 // See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms 7 // 8 // Date Author Notes 9 // 29/09/2011 SOH Madgwick Initial release 10 // 02/10/2011 SOH Madgwick Optimised for reduced CPU load 11 // 12 //===================================================================================================== 13 14 //--------------------------------------------------------------------------------------------------- 15 // Header files 16 17 #include "MahonyAHRS.h" 18 #include < math.h > 19 | |||
| |||
20 //--------------------------------------------------------------------------------------------------- 21 // Definitions 22 23 #define sampleFreq 512.0f // sample frequency in Hz 24 #define twoKpDef (2.0f * 0.5f) // 2 * proportional gain 25 #define twoKiDef (2.0f * 0.0f) // 2 * integral gain 26 | |||
変数宣言: 積分制御係数, 比例制御係数, 姿勢のクォータニオン(四元数)宣言と初期化, 積分制御の為の積分値 | |||
27 //--------------------------------------------------------------------------------------------------- 28 // Variable definitions 29 30 volatile float twoKp = twoKpDef; // 2 * proportional gain (Kp) 31 volatile float twoKi = twoKiDef; // 2 * integral gain (Ki) 32 volatile float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; // quaternion of sensor frame relative to auxiliary frame 33 volatile float integralFBx = 0.0f, integralFBy = 0.0f, integralFBz = 0.0f; // integral error terms scaled by Ki 34 35 //--------------------------------------------------------------------------------------------------- 36 // AHRS algorithm update 37 | |||
この関数ですよ。ジャイロ、加速度、磁気から姿勢のクォータニオン(四元数)を求める パラメータ:ジャイロ(オイラー角)、加速度(ベクトル)、磁気(ベクトル) | |||
38 void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) { 39 float recipNorm; 40 float q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3; 41 float hx, hy, bx, bz; 42 float halfvx, halfvy, halfvz, halfwx, halfwy, halfwz; 43 float halfex, halfey, halfez; 44 float qa, qb, qc; 45 | |||
センサーから加速度ベクトルの成分があれば、PI制御処理を続ける | |||
46 // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) 47 if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { 48 | |||
加速度ベクトルを単位化する | |||
49 // Normalise accelerometer measurement 50 recipNorm = sqrt(ax * ax + ay * ay + az * az); 51 ax /= recipNorm; 52 ay /= recipNorm; 53 az /= recipNorm; 54 | |||
磁気ベクトルを単位化する | |||
55 // Normalise magnetometer measurement 56 recipNorm = sqrt(mx * mx + my * my + mz * mz); 57 mx /= recipNorm; 58 my /= recipNorm; 59 mz /= recipNorm; 60 | |||
重複の掛け算を避けるために、中間変数を用意する | |||
61 // Auxiliary variables to avoid repeated arithmetic 62 q0q0 = q0 * q0; 63 q0q1 = q0 * q1; 64 q0q2 = q0 * q2; 65 q0q3 = q0 * q3; 66 q1q1 = q1 * q1; 67 q1q2 = q1 * q2; 68 q1q3 = q1 * q3; 69 q2q2 = q2 * q2; 70 q2q3 = q2 * q3; 71 q3q3 = q3 * q3; 72 | |||
座標系は北をX、西をY、上空をZ軸とする。 ボディー座標系は装置の座標系で、参照座標系は地面座標である、一番最初に、ボディー座標系が参照座標系と重なっている!! 磁気センサーから取得した磁気ベクトルを姿勢のクォータニオン回転行列でボディー座標系から参照座標系へ変換する。 磁気ベクトルのY成分をX成分に移す。{bx, by=0, bz}のようにする。なぜなら、参照座標系のY軸に磁力線が通らないからだ。 (クォータニオン回転行列について) | |||
73 // Reference direction of Earth's magnetic field 74 hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2)); 75 hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1)); 76 bx = sqrt(hx * hx + hy * hy); 77 bz = 2.0f * (mx * (q1q3 - q0q2) + my * (q2q3 + q0q1) + mz * (0.5f - q1q1 - q2q2)); 78 | |||
参照座標系の重力による加速度ベクトルは{ax=0,xy=0,az=1}(単位化)をクォータニオン回転行列の置換行列でボディー座標系に変換する。 (クォータニオン回転行列の置換行列について) | |||
79 // Estimated direction of gravity and magnetic field 80 halfvx = q1q3 - q0q2; 81 halfvy = q0q1 + q2q3; 82 halfvz = q0q0 - 0.5f + q3q3; | |||
上記の参照座標系の磁気ベクトルをクォータニオン回転行列の置換行列でボディー座標系に変換し戻す。 | |||
83 halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2); 84 halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3); 85 halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2); 86 | |||
センサーから取得したボディー座標系の加速度と{0,0,1}から作成したボディー座標系の加速度ベクトルを行列クロス乗算する。 2つの磁気ベクトルも行列クロス乗算する。 行列クロス乗算の結果を自動制御理論上の誤差として保持する。 | |||
87 // Error is sum of cross product between estimated direction and measured direction of field vectors 88 halfex = (ay * halfvz - az * halfvy) + (my * halfwz - mz * halfwy); 89 halfey = (az * halfvx - ax * halfvz) + (mz * halfwx - mx * halfwz); 90 halfez = (ax * halfvy - ay * halfvx) + (mx * halfwy - my * halfwx); 91 | |||
誤差を積分制御係数と掛け算した結果を積分累計値に加える。 積分累計値をジャイロのベクトルの各成分に足す。 | |||
92 // Compute and apply integral feedback if enabled 93 integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki 94 integralFBy += twoKi * halfey * (1.0f / sampleFreq); 95 integralFBz += twoKi * halfez * (1.0f / sampleFreq); 96 gx += integralFBx; // apply integral feedback 97 gy += integralFBy; 98 gz += integralFBz; 99 | |||
誤差を比例制御係数と掛け算して、ジャイロベクトルの成分に足す | |||
100 // Apply proportional feedback 101 gx += twoKp * halfex; 102 gy += twoKp * halfey; 103 gz += twoKp * halfez; 104 } 105 | |||
オイラー角であるジャイロの角速度と1周期の時間で姿勢のクォータニオンを変更させる。(オイラー角変化(微分)によりクォータニオンの変化を参照してくだい。) | |||
106 // Integrate rate of change of quaternion 107 gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors 108 gy *= (0.5f * (1.0f / sampleFreq)); 109 gz *= (0.5f * (1.0f / sampleFreq)); 110 qa = q0; 111 qb = q1; 112 qc = q2; 113 q0 += (-qb * gx - qc * gy - q3 * gz); 114 q1 += (qa * gx + qc * gz - q3 * gy); 115 q2 += (qa * gy - qb * gz + q3 * gx); 116 q3 += (qa * gz + qb * gy - qc * gx); 117 | |||
姿勢のクォータニオンを単位化する | |||
118 // Normalise quaternion 119 recipNorm = sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); 120 q0 /= recipNorm; 121 q1 /= recipNorm; 122 q2 /= recipNorm; 123 q3 /= recipNorm; 124 } | |||
================================================= 加速度、磁気から姿勢のクォータニオン(四元数)を初期化する関数 | |||
125 void AHRSinit(double ax, double ay, double az, double mx, double my, double mz)// Inialize quaternion 126 { 127 double initialRoll, initialPitch; 128 double cosRoll, sinRoll, cosPitch, sinPitch; 129 double magX, magY; 130 double initialHdg, cosHeading, sinHeading; | |||
センサーから取得した加速度からrollとpitchを算出する。重力がマイナス方向なので、atan2(-ay, -az)の-ayと-azがマイナスである。 一方、atan2(ax, -az)のaxにマイナスが付いていない理由は、pitchの回転の正方向に合わせるからである。 | |||
132 initialRoll = atan2(-ay, -az); 133 initialPitch = atan2(ax, -az); 134 135 cosRoll = cos(initialRoll); 136 sinRoll = sin(initialRoll); 137 cosPitch = cos(initialPitch); 138 sinPitch = sin(initialPitch); 139 | |||
センサーから取得した磁気の(mx,my,mz)をrollで回転してpitchで再回転して、参照座標系の磁気magYとmagXを算出します。算出方法の詳細については、「加速度センサー、磁気センサーから姿勢算出」を参照してください。 | |||
140 magX = mx * cosPitch + my * sinRoll * sinPitch + mz * cosRoll * sinPitch; 141 magY = my * cosRoll - mz * sinRoll; | |||
Heading(=yaw)の角度を算出する。-magYの-符号は、yawの回転の正方向に合わせるからである為に付けたのである。 | |||
143 initialHdg = atan2(-magY, magX); 144 145 cosRoll = cos(initialRoll * 0.5); 146 sinRoll = sin(initialRoll * 0.5); 147 cosPitch = cos(initialPitch * 0.5); 148 sinPitch = sin(initialPitch * 0.5); 149 cosHeading = cos(initialHdg * 0.5); 150 sinHeading = sin(initialHdg * 0.5); | |||
以下は単純にオイラー角からクォータニオン(四元数)へ変換するだけ。 | |||
152 q0 = cosRoll * cosPitch * cosHeading + sinRoll * sinPitch * sinHeading; 153 q1 = sinRoll * cosPitch * cosHeading - cosRoll * sinPitch * sinHeading; 154 q2 = cosRoll * sinPitch * cosHeading + sinRoll * cosPitch * sinHeading; 155 q3 = cosRoll * cosPitch * sinHeading - sinRoll * sinPitch * cosHeading; 156 } | |||
================================================= ヘッダファイル | |||
//===================================================================================================== 1 2 // MahonyAHRS.h 3 //===================================================================================================== 4 // 5 // Madgwick's implementation of Mayhony's AHRS algorithm. 6 // See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms 7 // 8 // Date Author Notes 9 // 29/09/2011 SOH Madgwick Initial release 10 // 02/10/2011 SOH Madgwick Optimised for reduced CPU load 11 // 12 //===================================================================================================== 13 #ifndef MahonyAHRS_h 14 #define MahonyAHRS_h 15 16 //---------------------------------------------------------------------------------------------------- 17 // Variable declaration 18 19 extern volatile float twoKp; // 2 * proportional gain (Kp) 20 extern volatile float twoKi; // 2 * integral gain (Ki) 21 extern volatile float q0, q1, q2, q3; // quaternion of sensor frame relative to auxiliary frame 22 23 //--------------------------------------------------------------------------------------------------- 24 // Function declarations 25 26 void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz); 27 void AHRSinit(double ax, double ay, double az, double mx, double my, double mz); 28 29 #endif 30 //===================================================================================================== 31 // End of file 32 //===================================================================================================== |