Gurvan PRIEM
/
RaptorControl
An incomplete quadcopter control programme.
MPU6050/GurvIMU.cpp@0:9cb9445a11f0, 2013-07-17 (annotated)
- Committer:
- Gurvan
- Date:
- Wed Jul 17 15:58:25 2013 +0000
- Revision:
- 0:9cb9445a11f0
Pour Zobson, fi(r)st commit.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Gurvan | 0:9cb9445a11f0 | 1 | #include "GurvIMU.h" |
Gurvan | 0:9cb9445a11f0 | 2 | #include "MPU6050.h" |
Gurvan | 0:9cb9445a11f0 | 3 | #include "mbed.h" |
Gurvan | 0:9cb9445a11f0 | 4 | |
Gurvan | 0:9cb9445a11f0 | 5 | #define M_PI 3.1415926535897932384626433832795 |
Gurvan | 0:9cb9445a11f0 | 6 | |
Gurvan | 0:9cb9445a11f0 | 7 | #define twoKpDef (2.0f * 1.0f) // 2 * proportional gain |
Gurvan | 0:9cb9445a11f0 | 8 | #define twoKiDef (2.0f * 0.0f) // 2 * integral gain |
Gurvan | 0:9cb9445a11f0 | 9 | |
Gurvan | 0:9cb9445a11f0 | 10 | |
Gurvan | 0:9cb9445a11f0 | 11 | GurvIMU::GurvIMU() |
Gurvan | 0:9cb9445a11f0 | 12 | { |
Gurvan | 0:9cb9445a11f0 | 13 | //MPU |
Gurvan | 0:9cb9445a11f0 | 14 | mpu = MPU6050(0x69); //0x69 = MPU6050 I2C ADDRESS |
Gurvan | 0:9cb9445a11f0 | 15 | |
Gurvan | 0:9cb9445a11f0 | 16 | // Variable definitions |
Gurvan | 0:9cb9445a11f0 | 17 | q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; // quaternion of sensor frame relative to auxiliary frame |
Gurvan | 0:9cb9445a11f0 | 18 | twoKp = twoKpDef; // 2 * proportional gain (Kp) |
Gurvan | 0:9cb9445a11f0 | 19 | twoKi = twoKiDef; // 2 * integral gain (Ki) |
Gurvan | 0:9cb9445a11f0 | 20 | integralFBx = 0.0f, integralFBy = 0.0f, integralFBz = 0.0f; // integral error terms scaled by Ki |
Gurvan | 0:9cb9445a11f0 | 21 | cycle_nb = 0; |
Gurvan | 0:9cb9445a11f0 | 22 | timer_us.start(); |
Gurvan | 0:9cb9445a11f0 | 23 | } |
Gurvan | 0:9cb9445a11f0 | 24 | |
Gurvan | 0:9cb9445a11f0 | 25 | //Function definitions |
Gurvan | 0:9cb9445a11f0 | 26 | |
Gurvan | 0:9cb9445a11f0 | 27 | void GurvIMU::getValues(float * values) |
Gurvan | 0:9cb9445a11f0 | 28 | { |
Gurvan | 0:9cb9445a11f0 | 29 | int16_t accgyroval[6]; |
Gurvan | 0:9cb9445a11f0 | 30 | mpu.getMotion6(&accgyroval[0], &accgyroval[1], &accgyroval[2], &accgyroval[3], &accgyroval[4], &accgyroval[5]); |
Gurvan | 0:9cb9445a11f0 | 31 | for(int i = 0; i<3; i++) values[i] = (float) accgyroval[i]; |
Gurvan | 0:9cb9445a11f0 | 32 | for(int i = 3; i<6; i++) values[i] = (accgyroval[i]-offset[i]) * (M_PI / 180) / 16.4f; |
Gurvan | 0:9cb9445a11f0 | 33 | } |
Gurvan | 0:9cb9445a11f0 | 34 | |
Gurvan | 0:9cb9445a11f0 | 35 | void GurvIMU::getVerticalAcceleration(float av) |
Gurvan | 0:9cb9445a11f0 | 36 | { |
Gurvan | 0:9cb9445a11f0 | 37 | float values[6]; |
Gurvan | 0:9cb9445a11f0 | 38 | float q[4]; // quaternion |
Gurvan | 0:9cb9445a11f0 | 39 | float g_x, g_y, g_z; // estimated gravity direction |
Gurvan | 0:9cb9445a11f0 | 40 | getQ(q); |
Gurvan | 0:9cb9445a11f0 | 41 | |
Gurvan | 0:9cb9445a11f0 | 42 | g_x = 2 * (q[1]*q[3] - q[0]*q[2]); |
Gurvan | 0:9cb9445a11f0 | 43 | g_y = 2 * (q[0]*q[1] + q[2]*q[3]); |
Gurvan | 0:9cb9445a11f0 | 44 | g_z = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3]; |
Gurvan | 0:9cb9445a11f0 | 45 | |
Gurvan | 0:9cb9445a11f0 | 46 | getValues(values); |
Gurvan | 0:9cb9445a11f0 | 47 | av = g_x*values[0]+g_y*values[1]+g_z*values[2]-offset[2]; |
Gurvan | 0:9cb9445a11f0 | 48 | } |
Gurvan | 0:9cb9445a11f0 | 49 | |
Gurvan | 0:9cb9445a11f0 | 50 | |
Gurvan | 0:9cb9445a11f0 | 51 | void GurvIMU::getOffset(void) |
Gurvan | 0:9cb9445a11f0 | 52 | { |
Gurvan | 0:9cb9445a11f0 | 53 | int sample_nb = 50; |
Gurvan | 0:9cb9445a11f0 | 54 | float values[6]; |
Gurvan | 0:9cb9445a11f0 | 55 | for(int i=0; i<6 ; i++) offset[i] = 0; |
Gurvan | 0:9cb9445a11f0 | 56 | for(int i=0; i<sample_nb; i++) { |
Gurvan | 0:9cb9445a11f0 | 57 | getValues(values); |
Gurvan | 0:9cb9445a11f0 | 58 | for(int j=0; j<6; j++) offset[j]+=values[j]; |
Gurvan | 0:9cb9445a11f0 | 59 | } |
Gurvan | 0:9cb9445a11f0 | 60 | for(int j=0; j<6; j++) offset[j]/=sample_nb; |
Gurvan | 0:9cb9445a11f0 | 61 | } |
Gurvan | 0:9cb9445a11f0 | 62 | |
Gurvan | 0:9cb9445a11f0 | 63 | |
Gurvan | 0:9cb9445a11f0 | 64 | void GurvIMU::AHRS_update(float gx, float gy, float gz, float ax, float ay, float az) |
Gurvan | 0:9cb9445a11f0 | 65 | { |
Gurvan | 0:9cb9445a11f0 | 66 | float recipNorm; |
Gurvan | 0:9cb9445a11f0 | 67 | float halfvx, halfvy, halfvz; |
Gurvan | 0:9cb9445a11f0 | 68 | float halfex, halfey, halfez; |
Gurvan | 0:9cb9445a11f0 | 69 | float qa, qb, qc; |
Gurvan | 0:9cb9445a11f0 | 70 | |
Gurvan | 0:9cb9445a11f0 | 71 | dt_us=timer_us.read_us(); |
Gurvan | 0:9cb9445a11f0 | 72 | sample_freq = 1.0 / ((dt_us) / 1000000.0); |
Gurvan | 0:9cb9445a11f0 | 73 | timer_us.reset(); |
Gurvan | 0:9cb9445a11f0 | 74 | |
Gurvan | 0:9cb9445a11f0 | 75 | // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) |
Gurvan | 0:9cb9445a11f0 | 76 | if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { |
Gurvan | 0:9cb9445a11f0 | 77 | |
Gurvan | 0:9cb9445a11f0 | 78 | // Normalise accelerometer measurement |
Gurvan | 0:9cb9445a11f0 | 79 | recipNorm = invSqrt(ax * ax + ay * ay + az * az); |
Gurvan | 0:9cb9445a11f0 | 80 | ax *= recipNorm; |
Gurvan | 0:9cb9445a11f0 | 81 | ay *= recipNorm; |
Gurvan | 0:9cb9445a11f0 | 82 | az *= recipNorm; |
Gurvan | 0:9cb9445a11f0 | 83 | |
Gurvan | 0:9cb9445a11f0 | 84 | // Estimated direction of gravity |
Gurvan | 0:9cb9445a11f0 | 85 | halfvx = q1 * q3 - q0 * q2; |
Gurvan | 0:9cb9445a11f0 | 86 | halfvy = q0 * q1 + q2 * q3; |
Gurvan | 0:9cb9445a11f0 | 87 | halfvz = q0 * q0 - 0.5f + q3 * q3; |
Gurvan | 0:9cb9445a11f0 | 88 | |
Gurvan | 0:9cb9445a11f0 | 89 | // Error is sum of cross product between estimated and measured direction of gravity |
Gurvan | 0:9cb9445a11f0 | 90 | halfex = (ay * halfvz - az * halfvy); |
Gurvan | 0:9cb9445a11f0 | 91 | halfey = (az * halfvx - ax * halfvz); |
Gurvan | 0:9cb9445a11f0 | 92 | halfez = (ax * halfvy - ay * halfvx); |
Gurvan | 0:9cb9445a11f0 | 93 | |
Gurvan | 0:9cb9445a11f0 | 94 | // Compute and apply integral feedback if enabled |
Gurvan | 0:9cb9445a11f0 | 95 | if(twoKi > 0.0f) { |
Gurvan | 0:9cb9445a11f0 | 96 | integralFBx += twoKi * halfex * (1.0f / sample_freq); // integral error scaled by Ki |
Gurvan | 0:9cb9445a11f0 | 97 | integralFBy += twoKi * halfey * (1.0f / sample_freq); |
Gurvan | 0:9cb9445a11f0 | 98 | integralFBz += twoKi * halfez * (1.0f / sample_freq); |
Gurvan | 0:9cb9445a11f0 | 99 | gx += integralFBx; // apply integral feedback |
Gurvan | 0:9cb9445a11f0 | 100 | gy += integralFBy; |
Gurvan | 0:9cb9445a11f0 | 101 | gz += integralFBz; |
Gurvan | 0:9cb9445a11f0 | 102 | } |
Gurvan | 0:9cb9445a11f0 | 103 | else { |
Gurvan | 0:9cb9445a11f0 | 104 | integralFBx = 0.0f; // prevent integral windup |
Gurvan | 0:9cb9445a11f0 | 105 | integralFBy = 0.0f; |
Gurvan | 0:9cb9445a11f0 | 106 | integralFBz = 0.0f; |
Gurvan | 0:9cb9445a11f0 | 107 | } |
Gurvan | 0:9cb9445a11f0 | 108 | |
Gurvan | 0:9cb9445a11f0 | 109 | // Apply proportional feedback |
Gurvan | 0:9cb9445a11f0 | 110 | gx += twoKp * halfex; |
Gurvan | 0:9cb9445a11f0 | 111 | gy += twoKp * halfey; |
Gurvan | 0:9cb9445a11f0 | 112 | gz += twoKp * halfez; |
Gurvan | 0:9cb9445a11f0 | 113 | } |
Gurvan | 0:9cb9445a11f0 | 114 | |
Gurvan | 0:9cb9445a11f0 | 115 | // Integrate rate of change of quaternion |
Gurvan | 0:9cb9445a11f0 | 116 | gx *= (0.5f * (1.0f / sample_freq)); // pre-multiply common factors |
Gurvan | 0:9cb9445a11f0 | 117 | gy *= (0.5f * (1.0f / sample_freq)); |
Gurvan | 0:9cb9445a11f0 | 118 | gz *= (0.5f * (1.0f / sample_freq)); |
Gurvan | 0:9cb9445a11f0 | 119 | qa = q0; |
Gurvan | 0:9cb9445a11f0 | 120 | qb = q1; |
Gurvan | 0:9cb9445a11f0 | 121 | qc = q2; |
Gurvan | 0:9cb9445a11f0 | 122 | q0 += (-qb * gx - qc * gy - q3 * gz); |
Gurvan | 0:9cb9445a11f0 | 123 | q1 += (qa * gx + qc * gz - q3 * gy); |
Gurvan | 0:9cb9445a11f0 | 124 | q2 += (qa * gy - qb * gz + q3 * gx); |
Gurvan | 0:9cb9445a11f0 | 125 | q3 += (qa * gz + qb * gy - qc * gx); |
Gurvan | 0:9cb9445a11f0 | 126 | |
Gurvan | 0:9cb9445a11f0 | 127 | // Normalise quaternion |
Gurvan | 0:9cb9445a11f0 | 128 | recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); |
Gurvan | 0:9cb9445a11f0 | 129 | q0 *= recipNorm; |
Gurvan | 0:9cb9445a11f0 | 130 | q1 *= recipNorm; |
Gurvan | 0:9cb9445a11f0 | 131 | q2 *= recipNorm; |
Gurvan | 0:9cb9445a11f0 | 132 | q3 *= recipNorm; |
Gurvan | 0:9cb9445a11f0 | 133 | } |
Gurvan | 0:9cb9445a11f0 | 134 | |
Gurvan | 0:9cb9445a11f0 | 135 | void GurvIMU::getQ(float * q) { |
Gurvan | 0:9cb9445a11f0 | 136 | float val[6]; |
Gurvan | 0:9cb9445a11f0 | 137 | getValues(val); |
Gurvan | 0:9cb9445a11f0 | 138 | //while(cycle_nb < 1000){ |
Gurvan | 0:9cb9445a11f0 | 139 | AHRS_update(val[3], val[4], val[5], val[0], val[1], val[2]); |
Gurvan | 0:9cb9445a11f0 | 140 | //cycle_nb++;} |
Gurvan | 0:9cb9445a11f0 | 141 | |
Gurvan | 0:9cb9445a11f0 | 142 | q[0] = q0; |
Gurvan | 0:9cb9445a11f0 | 143 | q[1] = q1; |
Gurvan | 0:9cb9445a11f0 | 144 | q[2] = q2; |
Gurvan | 0:9cb9445a11f0 | 145 | q[3] = q3; |
Gurvan | 0:9cb9445a11f0 | 146 | |
Gurvan | 0:9cb9445a11f0 | 147 | } |
Gurvan | 0:9cb9445a11f0 | 148 | |
Gurvan | 0:9cb9445a11f0 | 149 | void GurvIMU::getYawPitchRollRad(float * ypr) { |
Gurvan | 0:9cb9445a11f0 | 150 | float q[4]; // quaternion |
Gurvan | 0:9cb9445a11f0 | 151 | float g_x, g_y, g_z; // estimated gravity direction |
Gurvan | 0:9cb9445a11f0 | 152 | getQ(q); |
Gurvan | 0:9cb9445a11f0 | 153 | |
Gurvan | 0:9cb9445a11f0 | 154 | g_x = 2 * (q[1]*q[3] - q[0]*q[2]); |
Gurvan | 0:9cb9445a11f0 | 155 | g_y = 2 * (q[0]*q[1] + q[2]*q[3]); |
Gurvan | 0:9cb9445a11f0 | 156 | g_z = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3]; |
Gurvan | 0:9cb9445a11f0 | 157 | |
Gurvan | 0:9cb9445a11f0 | 158 | ypr[0] = atan2(2 * q[1] * q[2] - 2 * q[0] * q[3], 2 * q[0]*q[0] + 2 * q[1] * q[1] - 1); |
Gurvan | 0:9cb9445a11f0 | 159 | ypr[1] = atan(g_x * invSqrt(g_y*g_y + g_z*g_z)); |
Gurvan | 0:9cb9445a11f0 | 160 | ypr[2] = atan(g_y * invSqrt(g_x*g_x + g_z*g_z)); |
Gurvan | 0:9cb9445a11f0 | 161 | } |
Gurvan | 0:9cb9445a11f0 | 162 | |
Gurvan | 0:9cb9445a11f0 | 163 | void GurvIMU::init() |
Gurvan | 0:9cb9445a11f0 | 164 | { |
Gurvan | 0:9cb9445a11f0 | 165 | mpu.initialize(); |
Gurvan | 0:9cb9445a11f0 | 166 | mpu.setI2CMasterModeEnabled(0); |
Gurvan | 0:9cb9445a11f0 | 167 | mpu.setI2CBypassEnabled(0); |
Gurvan | 0:9cb9445a11f0 | 168 | mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_2000); |
Gurvan | 0:9cb9445a11f0 | 169 | getOffset(); |
Gurvan | 0:9cb9445a11f0 | 170 | wait(0.005); |
Gurvan | 0:9cb9445a11f0 | 171 | } |
Gurvan | 0:9cb9445a11f0 | 172 | |
Gurvan | 0:9cb9445a11f0 | 173 | |
Gurvan | 0:9cb9445a11f0 | 174 | float invSqrt(float number) |
Gurvan | 0:9cb9445a11f0 | 175 | { |
Gurvan | 0:9cb9445a11f0 | 176 | volatile long i; |
Gurvan | 0:9cb9445a11f0 | 177 | volatile float x, y; |
Gurvan | 0:9cb9445a11f0 | 178 | volatile const float f = 1.5F; |
Gurvan | 0:9cb9445a11f0 | 179 | |
Gurvan | 0:9cb9445a11f0 | 180 | x = number * 0.5F; |
Gurvan | 0:9cb9445a11f0 | 181 | y = number; |
Gurvan | 0:9cb9445a11f0 | 182 | i = * ( long * ) &y; |
Gurvan | 0:9cb9445a11f0 | 183 | i = 0x5f375a86 - ( i >> 1 ); |
Gurvan | 0:9cb9445a11f0 | 184 | y = * ( float * ) &i; |
Gurvan | 0:9cb9445a11f0 | 185 | y = y * ( f - ( x * y * y ) ); |
Gurvan | 0:9cb9445a11f0 | 186 | return y; |
Gurvan | 0:9cb9445a11f0 | 187 | } |