Dependents:   controller_with_backup

Committer:
yxyang
Date:
Tue May 30 06:54:27 2017 +0000
Revision:
0:d23cb6fd82b7

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
yxyang 0:d23cb6fd82b7 1 #ifndef MPU6050_H
yxyang 0:d23cb6fd82b7 2 #define MPU6050_H
yxyang 0:d23cb6fd82b7 3
yxyang 0:d23cb6fd82b7 4 #include "math.h"
yxyang 0:d23cb6fd82b7 5 #include "mbed.h"
yxyang 0:d23cb6fd82b7 6
yxyang 0:d23cb6fd82b7 7 // Define registers per MPU6050, Register Map and Descriptions, Rev 4.2,
yxyang 0:d23cb6fd82b7 8 // 08/19/2013 6 DOF Motion sensor fusion device
yxyang 0:d23cb6fd82b7 9 // Invensense Inc., www.invensense.com
yxyang 0:d23cb6fd82b7 10 // See also MPU-6050 Register Map and Descriptions, Revision 4.0,
yxyang 0:d23cb6fd82b7 11 // RM-MPU-6050A-00, 9/12/2012 for registers not listed in
yxyang 0:d23cb6fd82b7 12 // above document; the MPU6050 and MPU 9150 are virtually identical but the
yxyang 0:d23cb6fd82b7 13 // latter has an on-board magnetic sensor
yxyang 0:d23cb6fd82b7 14 //
yxyang 0:d23cb6fd82b7 15 #define XGOFFS_TC \
yxyang 0:d23cb6fd82b7 16 0x00 // Bit 7 PWR_MODE, bits 6:1 XG_OFFS_TC, bit 0 OTP_BNK_VLD
yxyang 0:d23cb6fd82b7 17 #define YGOFFS_TC 0x01
yxyang 0:d23cb6fd82b7 18 #define ZGOFFS_TC 0x02
yxyang 0:d23cb6fd82b7 19 #define X_FINE_GAIN 0x03 // [7:0] fine gain
yxyang 0:d23cb6fd82b7 20 #define Y_FINE_GAIN 0x04
yxyang 0:d23cb6fd82b7 21 #define Z_FINE_GAIN 0x05
yxyang 0:d23cb6fd82b7 22 #define XA_OFFSET_H 0x06 // User-defined trim values for accelerometer
yxyang 0:d23cb6fd82b7 23 #define XA_OFFSET_L_TC 0x07
yxyang 0:d23cb6fd82b7 24 #define YA_OFFSET_H 0x08
yxyang 0:d23cb6fd82b7 25 #define YA_OFFSET_L_TC 0x09
yxyang 0:d23cb6fd82b7 26 #define ZA_OFFSET_H 0x0A
yxyang 0:d23cb6fd82b7 27 #define ZA_OFFSET_L_TC 0x0B
yxyang 0:d23cb6fd82b7 28 #define SELF_TEST_X 0x0D
yxyang 0:d23cb6fd82b7 29 #define SELF_TEST_Y 0x0E
yxyang 0:d23cb6fd82b7 30 #define SELF_TEST_Z 0x0F
yxyang 0:d23cb6fd82b7 31 #define SELF_TEST_A 0x10
yxyang 0:d23cb6fd82b7 32 #define XG_OFFS_USRH \
yxyang 0:d23cb6fd82b7 33 0x13 // User-defined trim values for gyroscope; supported in MPU-6050?
yxyang 0:d23cb6fd82b7 34 #define XG_OFFS_USRL 0x14
yxyang 0:d23cb6fd82b7 35 #define YG_OFFS_USRH 0x15
yxyang 0:d23cb6fd82b7 36 #define YG_OFFS_USRL 0x16
yxyang 0:d23cb6fd82b7 37 #define ZG_OFFS_USRH 0x17
yxyang 0:d23cb6fd82b7 38 #define ZG_OFFS_USRL 0x18
yxyang 0:d23cb6fd82b7 39 #define SMPLRT_DIV 0x19
yxyang 0:d23cb6fd82b7 40 #define CONFIG 0x1A
yxyang 0:d23cb6fd82b7 41 #define GYRO_CONFIG 0x1B
yxyang 0:d23cb6fd82b7 42 #define ACCEL_CONFIG 0x1C
yxyang 0:d23cb6fd82b7 43 #define FF_THR 0x1D // Free-fall
yxyang 0:d23cb6fd82b7 44 #define FF_DUR 0x1E // Free-fall
yxyang 0:d23cb6fd82b7 45 #define MOT_THR 0x1F // Motion detection threshold bits [7:0]
yxyang 0:d23cb6fd82b7 46 #define MOT_DUR \
yxyang 0:d23cb6fd82b7 47 0x20 // Duration counter threshold for motion interrupt generation, 1 kHz
yxyang 0:d23cb6fd82b7 48 // rate, LSB = 1 ms
yxyang 0:d23cb6fd82b7 49 #define ZMOT_THR 0x21 // Zero-motion detection threshold bits [7:0]
yxyang 0:d23cb6fd82b7 50 #define ZRMOT_DUR \
yxyang 0:d23cb6fd82b7 51 0x22 // Duration counter threshold for zero motion interrupt generation, 16
yxyang 0:d23cb6fd82b7 52 // Hz rate, LSB = 64 ms
yxyang 0:d23cb6fd82b7 53 #define FIFO_EN 0x23
yxyang 0:d23cb6fd82b7 54 #define I2C_MST_CTRL 0x24
yxyang 0:d23cb6fd82b7 55 #define I2C_SLV0_ADDR 0x25
yxyang 0:d23cb6fd82b7 56 #define I2C_SLV0_REG 0x26
yxyang 0:d23cb6fd82b7 57 #define I2C_SLV0_CTRL 0x27
yxyang 0:d23cb6fd82b7 58 #define I2C_SLV1_ADDR 0x28
yxyang 0:d23cb6fd82b7 59 #define I2C_SLV1_REG 0x29
yxyang 0:d23cb6fd82b7 60 #define I2C_SLV1_CTRL 0x2A
yxyang 0:d23cb6fd82b7 61 #define I2C_SLV2_ADDR 0x2B
yxyang 0:d23cb6fd82b7 62 #define I2C_SLV2_REG 0x2C
yxyang 0:d23cb6fd82b7 63 #define I2C_SLV2_CTRL 0x2D
yxyang 0:d23cb6fd82b7 64 #define I2C_SLV3_ADDR 0x2E
yxyang 0:d23cb6fd82b7 65 #define I2C_SLV3_REG 0x2F
yxyang 0:d23cb6fd82b7 66 #define I2C_SLV3_CTRL 0x30
yxyang 0:d23cb6fd82b7 67 #define I2C_SLV4_ADDR 0x31
yxyang 0:d23cb6fd82b7 68 #define I2C_SLV4_REG 0x32
yxyang 0:d23cb6fd82b7 69 #define I2C_SLV4_DO 0x33
yxyang 0:d23cb6fd82b7 70 #define I2C_SLV4_CTRL 0x34
yxyang 0:d23cb6fd82b7 71 #define I2C_SLV4_DI 0x35
yxyang 0:d23cb6fd82b7 72 #define I2C_MST_STATUS 0x36
yxyang 0:d23cb6fd82b7 73 #define INT_PIN_CFG 0x37
yxyang 0:d23cb6fd82b7 74 #define INT_ENABLE 0x38
yxyang 0:d23cb6fd82b7 75 #define DMP_INT_STATUS 0x39 // Check DMP interrupt
yxyang 0:d23cb6fd82b7 76 #define INT_STATUS 0x3A
yxyang 0:d23cb6fd82b7 77 #define ACCEL_XOUT_H 0x3B
yxyang 0:d23cb6fd82b7 78 #define ACCEL_XOUT_L 0x3C
yxyang 0:d23cb6fd82b7 79 #define ACCEL_YOUT_H 0x3D
yxyang 0:d23cb6fd82b7 80 #define ACCEL_YOUT_L 0x3E
yxyang 0:d23cb6fd82b7 81 #define ACCEL_ZOUT_H 0x3F
yxyang 0:d23cb6fd82b7 82 #define ACCEL_ZOUT_L 0x40
yxyang 0:d23cb6fd82b7 83 #define TEMP_OUT_H 0x41
yxyang 0:d23cb6fd82b7 84 #define TEMP_OUT_L 0x42
yxyang 0:d23cb6fd82b7 85 #define GYRO_XOUT_H 0x43
yxyang 0:d23cb6fd82b7 86 #define GYRO_XOUT_L 0x44
yxyang 0:d23cb6fd82b7 87 #define GYRO_YOUT_H 0x45
yxyang 0:d23cb6fd82b7 88 #define GYRO_YOUT_L 0x46
yxyang 0:d23cb6fd82b7 89 #define GYRO_ZOUT_H 0x47
yxyang 0:d23cb6fd82b7 90 #define GYRO_ZOUT_L 0x48
yxyang 0:d23cb6fd82b7 91 #define EXT_SENS_DATA_00 0x49
yxyang 0:d23cb6fd82b7 92 #define EXT_SENS_DATA_01 0x4A
yxyang 0:d23cb6fd82b7 93 #define EXT_SENS_DATA_02 0x4B
yxyang 0:d23cb6fd82b7 94 #define EXT_SENS_DATA_03 0x4C
yxyang 0:d23cb6fd82b7 95 #define EXT_SENS_DATA_04 0x4D
yxyang 0:d23cb6fd82b7 96 #define EXT_SENS_DATA_05 0x4E
yxyang 0:d23cb6fd82b7 97 #define EXT_SENS_DATA_06 0x4F
yxyang 0:d23cb6fd82b7 98 #define EXT_SENS_DATA_07 0x50
yxyang 0:d23cb6fd82b7 99 #define EXT_SENS_DATA_08 0x51
yxyang 0:d23cb6fd82b7 100 #define EXT_SENS_DATA_09 0x52
yxyang 0:d23cb6fd82b7 101 #define EXT_SENS_DATA_10 0x53
yxyang 0:d23cb6fd82b7 102 #define EXT_SENS_DATA_11 0x54
yxyang 0:d23cb6fd82b7 103 #define EXT_SENS_DATA_12 0x55
yxyang 0:d23cb6fd82b7 104 #define EXT_SENS_DATA_13 0x56
yxyang 0:d23cb6fd82b7 105 #define EXT_SENS_DATA_14 0x57
yxyang 0:d23cb6fd82b7 106 #define EXT_SENS_DATA_15 0x58
yxyang 0:d23cb6fd82b7 107 #define EXT_SENS_DATA_16 0x59
yxyang 0:d23cb6fd82b7 108 #define EXT_SENS_DATA_17 0x5A
yxyang 0:d23cb6fd82b7 109 #define EXT_SENS_DATA_18 0x5B
yxyang 0:d23cb6fd82b7 110 #define EXT_SENS_DATA_19 0x5C
yxyang 0:d23cb6fd82b7 111 #define EXT_SENS_DATA_20 0x5D
yxyang 0:d23cb6fd82b7 112 #define EXT_SENS_DATA_21 0x5E
yxyang 0:d23cb6fd82b7 113 #define EXT_SENS_DATA_22 0x5F
yxyang 0:d23cb6fd82b7 114 #define EXT_SENS_DATA_23 0x60
yxyang 0:d23cb6fd82b7 115 #define MOT_DETECT_STATUS 0x61
yxyang 0:d23cb6fd82b7 116 #define I2C_SLV0_DO 0x63
yxyang 0:d23cb6fd82b7 117 #define I2C_SLV1_DO 0x64
yxyang 0:d23cb6fd82b7 118 #define I2C_SLV2_DO 0x65
yxyang 0:d23cb6fd82b7 119 #define I2C_SLV3_DO 0x66
yxyang 0:d23cb6fd82b7 120 #define I2C_MST_DELAY_CTRL 0x67
yxyang 0:d23cb6fd82b7 121 #define SIGNAL_PATH_RESET 0x68
yxyang 0:d23cb6fd82b7 122 #define MOT_DETECT_CTRL 0x69
yxyang 0:d23cb6fd82b7 123 #define USER_CTRL 0x6A // Bit 7 enable DMP, bit 3 reset DMP
yxyang 0:d23cb6fd82b7 124 #define PWR_MGMT_1 0x6B // Device defaults to the SLEEP mode
yxyang 0:d23cb6fd82b7 125 #define PWR_MGMT_2 0x6C
yxyang 0:d23cb6fd82b7 126 #define DMP_BANK 0x6D // Activates a specific bank in the DMP
yxyang 0:d23cb6fd82b7 127 #define DMP_RW_PNT \
yxyang 0:d23cb6fd82b7 128 0x6E // Set read/write pointer to a specific start address in specified DMP
yxyang 0:d23cb6fd82b7 129 // bank
yxyang 0:d23cb6fd82b7 130 #define DMP_REG 0x6F // Register in DMP from which to read or to which to write
yxyang 0:d23cb6fd82b7 131 #define DMP_REG_1 0x70
yxyang 0:d23cb6fd82b7 132 #define DMP_REG_2 0x71
yxyang 0:d23cb6fd82b7 133 #define FIFO_COUNTH 0x72
yxyang 0:d23cb6fd82b7 134 #define FIFO_COUNTL 0x73
yxyang 0:d23cb6fd82b7 135 #define FIFO_R_W 0x74
yxyang 0:d23cb6fd82b7 136 #define WHO_AM_I_MPU6050 0x75 // Should return 0x68
yxyang 0:d23cb6fd82b7 137
yxyang 0:d23cb6fd82b7 138 // Using the GY-521 breakout board, I set ADO to 0 by grounding through a 4k7
yxyang 0:d23cb6fd82b7 139 // resistor
yxyang 0:d23cb6fd82b7 140 // Seven-bit device address is 110100 for ADO = 0 and 110101 for ADO = 1
yxyang 0:d23cb6fd82b7 141 #define ADO 0
yxyang 0:d23cb6fd82b7 142 #if ADO
yxyang 0:d23cb6fd82b7 143 #define MPU6050_ADDRESS 0x69 << 1 // Device address when ADO = 1
yxyang 0:d23cb6fd82b7 144 #else
yxyang 0:d23cb6fd82b7 145 #define MPU6050_ADDRESS 0x68 << 1 // Device address when ADO = 0
yxyang 0:d23cb6fd82b7 146 #endif
yxyang 0:d23cb6fd82b7 147
yxyang 0:d23cb6fd82b7 148 // Set initial input parameters
yxyang 0:d23cb6fd82b7 149 enum Ascale
yxyang 0:d23cb6fd82b7 150 {
yxyang 0:d23cb6fd82b7 151 AFS_2G = 0,
yxyang 0:d23cb6fd82b7 152 AFS_4G,
yxyang 0:d23cb6fd82b7 153 AFS_8G,
yxyang 0:d23cb6fd82b7 154 AFS_16G
yxyang 0:d23cb6fd82b7 155 };
yxyang 0:d23cb6fd82b7 156
yxyang 0:d23cb6fd82b7 157 enum Gscale
yxyang 0:d23cb6fd82b7 158 {
yxyang 0:d23cb6fd82b7 159 GFS_250DPS = 0,
yxyang 0:d23cb6fd82b7 160 GFS_500DPS,
yxyang 0:d23cb6fd82b7 161 GFS_1000DPS,
yxyang 0:d23cb6fd82b7 162 GFS_2000DPS
yxyang 0:d23cb6fd82b7 163 };
yxyang 0:d23cb6fd82b7 164
yxyang 0:d23cb6fd82b7 165 // Specify sensor full scale
yxyang 0:d23cb6fd82b7 166 int Gscale = GFS_250DPS;
yxyang 0:d23cb6fd82b7 167 int Ascale = AFS_2G;
yxyang 0:d23cb6fd82b7 168
yxyang 0:d23cb6fd82b7 169 // Set up I2C, (SDA,SCL)
yxyang 0:d23cb6fd82b7 170 #define MPU_SDA p9
yxyang 0:d23cb6fd82b7 171 #define MPU_SCL p10
yxyang 0:d23cb6fd82b7 172 I2C i2c (MPU_SDA, MPU_SCL);
yxyang 0:d23cb6fd82b7 173
yxyang 0:d23cb6fd82b7 174 // DigitalOut myled(LED1);
yxyang 0:d23cb6fd82b7 175
yxyang 0:d23cb6fd82b7 176 float aRes, gRes; // scale resolutions per LSB for the sensors
yxyang 0:d23cb6fd82b7 177
yxyang 0:d23cb6fd82b7 178 // Pin definitions
yxyang 0:d23cb6fd82b7 179 int intPin = 12; // These can be changed, 2 and 3 are the Arduinos ext int pins
yxyang 0:d23cb6fd82b7 180
yxyang 0:d23cb6fd82b7 181 int16_t accelCount[3]; // Stores the 16-bit signed accelerometer sensor output
yxyang 0:d23cb6fd82b7 182 float ax, ay, az; // Stores the real accel value in g's
yxyang 0:d23cb6fd82b7 183 int16_t gyroCount[3]; // Stores the 16-bit signed gyro sensor output
yxyang 0:d23cb6fd82b7 184 float gx, gy, gz; // Stores the real gyro value in degrees per seconds
yxyang 0:d23cb6fd82b7 185 float gyroBias[3] = { 0, 0, 0 },
yxyang 0:d23cb6fd82b7 186 accelBias[3]
yxyang 0:d23cb6fd82b7 187 = { 0, 0, 0 }; // Bias corrections for gyro and accelerometer
yxyang 0:d23cb6fd82b7 188 int16_t
yxyang 0:d23cb6fd82b7 189 tempCount; // Stores the real internal chip temperature in degrees Celsius
yxyang 0:d23cb6fd82b7 190 float temperature;
yxyang 0:d23cb6fd82b7 191 float SelfTest[6];
yxyang 0:d23cb6fd82b7 192
yxyang 0:d23cb6fd82b7 193 int delt_t = 0; // used to control display output rate
yxyang 0:d23cb6fd82b7 194 int count = 0; // used to control display output rate
yxyang 0:d23cb6fd82b7 195
yxyang 0:d23cb6fd82b7 196 // parameters for 6 DoF sensor fusion calculations
yxyang 0:d23cb6fd82b7 197 float PI = 3.14159265358979323846f;
yxyang 0:d23cb6fd82b7 198 float GyroMeasError = PI * (60.0f / 180.0f); // gyroscope measurement error in
yxyang 0:d23cb6fd82b7 199 // rads/s (start at 60 deg/s),
yxyang 0:d23cb6fd82b7 200 // then reduce after ~10 s to 3
yxyang 0:d23cb6fd82b7 201 float beta = sqrt (3.0f / 4.0f) * GyroMeasError; // compute beta
yxyang 0:d23cb6fd82b7 202 float GyroMeasDrift = PI * (1.0f / 180.0f); // gyroscope measurement drift in
yxyang 0:d23cb6fd82b7 203 // rad/s/s (start at 0.0 deg/s/s)
yxyang 0:d23cb6fd82b7 204 float zeta = sqrt (3.0f / 4.0f) * GyroMeasDrift; // compute zeta, the other
yxyang 0:d23cb6fd82b7 205 // free parameter in the
yxyang 0:d23cb6fd82b7 206 // Madgwick scheme usually set
yxyang 0:d23cb6fd82b7 207 // to a small or zero value
yxyang 0:d23cb6fd82b7 208 float pitch, yaw, roll;
yxyang 0:d23cb6fd82b7 209 float deltat = 0.0f; // integration interval for both filter schemes
yxyang 0:d23cb6fd82b7 210 int lastUpdate = 0, firstUpdate = 0,
yxyang 0:d23cb6fd82b7 211 Now = 0; // used to calculate integration interval
yxyang 0:d23cb6fd82b7 212 // // used to calculate integration interval
yxyang 0:d23cb6fd82b7 213 float q[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; // vector to hold quaternion
yxyang 0:d23cb6fd82b7 214
yxyang 0:d23cb6fd82b7 215 class MPU6050
yxyang 0:d23cb6fd82b7 216 {
yxyang 0:d23cb6fd82b7 217
yxyang 0:d23cb6fd82b7 218 protected:
yxyang 0:d23cb6fd82b7 219 public:
yxyang 0:d23cb6fd82b7 220 //===================================================================================================================
yxyang 0:d23cb6fd82b7 221 //====== Set of useful function to access acceleratio, gyroscope, and
yxyang 0:d23cb6fd82b7 222 // temperature data
yxyang 0:d23cb6fd82b7 223 //===================================================================================================================
yxyang 0:d23cb6fd82b7 224
yxyang 0:d23cb6fd82b7 225 void
yxyang 0:d23cb6fd82b7 226 writeByte (uint8_t address, uint8_t subAddress, uint8_t data)
yxyang 0:d23cb6fd82b7 227 {
yxyang 0:d23cb6fd82b7 228 char data_write[2];
yxyang 0:d23cb6fd82b7 229 data_write[0] = subAddress;
yxyang 0:d23cb6fd82b7 230 data_write[1] = data;
yxyang 0:d23cb6fd82b7 231 i2c.write (address, data_write, 2, 0);
yxyang 0:d23cb6fd82b7 232 }
yxyang 0:d23cb6fd82b7 233
yxyang 0:d23cb6fd82b7 234 char
yxyang 0:d23cb6fd82b7 235 readByte (uint8_t address, uint8_t subAddress)
yxyang 0:d23cb6fd82b7 236 {
yxyang 0:d23cb6fd82b7 237 char data[1]; // `data` will store the register data
yxyang 0:d23cb6fd82b7 238 char data_write[1];
yxyang 0:d23cb6fd82b7 239 data_write[0] = subAddress;
yxyang 0:d23cb6fd82b7 240 i2c.write (address, data_write, 1, 1); // no stop
yxyang 0:d23cb6fd82b7 241 i2c.read (address, data, 1, 0);
yxyang 0:d23cb6fd82b7 242 return data[0];
yxyang 0:d23cb6fd82b7 243 }
yxyang 0:d23cb6fd82b7 244
yxyang 0:d23cb6fd82b7 245 void
yxyang 0:d23cb6fd82b7 246 readBytes (uint8_t address, uint8_t subAddress, uint8_t count, uint8_t *dest)
yxyang 0:d23cb6fd82b7 247 {
yxyang 0:d23cb6fd82b7 248 char data[14];
yxyang 0:d23cb6fd82b7 249 char data_write[1];
yxyang 0:d23cb6fd82b7 250 data_write[0] = subAddress;
yxyang 0:d23cb6fd82b7 251 i2c.write (address, data_write, 1, 1); // no stop
yxyang 0:d23cb6fd82b7 252 i2c.read (address, data, count, 0);
yxyang 0:d23cb6fd82b7 253 for (int ii = 0; ii < count; ii++)
yxyang 0:d23cb6fd82b7 254 {
yxyang 0:d23cb6fd82b7 255 dest[ii] = data[ii];
yxyang 0:d23cb6fd82b7 256 }
yxyang 0:d23cb6fd82b7 257 }
yxyang 0:d23cb6fd82b7 258
yxyang 0:d23cb6fd82b7 259 void
yxyang 0:d23cb6fd82b7 260 getGres ()
yxyang 0:d23cb6fd82b7 261 {
yxyang 0:d23cb6fd82b7 262 switch (Gscale)
yxyang 0:d23cb6fd82b7 263 {
yxyang 0:d23cb6fd82b7 264 // Possible gyro scales (and their register bit settings) are:
yxyang 0:d23cb6fd82b7 265 // 250 DPS (00), 500 DPS (01), 1000 DPS (10), and 2000 DPS (11).
yxyang 0:d23cb6fd82b7 266 // Here's a bit of an algorith to calculate DPS/(ADC tick) based on that
yxyang 0:d23cb6fd82b7 267 // 2-bit value:
yxyang 0:d23cb6fd82b7 268 case GFS_250DPS:
yxyang 0:d23cb6fd82b7 269 gRes = 250.0 / 32768.0;
yxyang 0:d23cb6fd82b7 270 break;
yxyang 0:d23cb6fd82b7 271 case GFS_500DPS:
yxyang 0:d23cb6fd82b7 272 gRes = 500.0 / 32768.0;
yxyang 0:d23cb6fd82b7 273 break;
yxyang 0:d23cb6fd82b7 274 case GFS_1000DPS:
yxyang 0:d23cb6fd82b7 275 gRes = 1000.0 / 32768.0;
yxyang 0:d23cb6fd82b7 276 break;
yxyang 0:d23cb6fd82b7 277 case GFS_2000DPS:
yxyang 0:d23cb6fd82b7 278 gRes = 2000.0 / 32768.0;
yxyang 0:d23cb6fd82b7 279 break;
yxyang 0:d23cb6fd82b7 280 }
yxyang 0:d23cb6fd82b7 281 }
yxyang 0:d23cb6fd82b7 282
yxyang 0:d23cb6fd82b7 283 void
yxyang 0:d23cb6fd82b7 284 getAres ()
yxyang 0:d23cb6fd82b7 285 {
yxyang 0:d23cb6fd82b7 286 switch (Ascale)
yxyang 0:d23cb6fd82b7 287 {
yxyang 0:d23cb6fd82b7 288 // Possible accelerometer scales (and their register bit settings) are:
yxyang 0:d23cb6fd82b7 289 // 2 Gs (00), 4 Gs (01), 8 Gs (10), and 16 Gs (11).
yxyang 0:d23cb6fd82b7 290 // Here's a bit of an algorith to calculate DPS/(ADC tick) based on that
yxyang 0:d23cb6fd82b7 291 // 2-bit value:
yxyang 0:d23cb6fd82b7 292 case AFS_2G:
yxyang 0:d23cb6fd82b7 293 aRes = 2.0 / 32768.0;
yxyang 0:d23cb6fd82b7 294 break;
yxyang 0:d23cb6fd82b7 295 case AFS_4G:
yxyang 0:d23cb6fd82b7 296 aRes = 4.0 / 32768.0;
yxyang 0:d23cb6fd82b7 297 break;
yxyang 0:d23cb6fd82b7 298 case AFS_8G:
yxyang 0:d23cb6fd82b7 299 aRes = 8.0 / 32768.0;
yxyang 0:d23cb6fd82b7 300 break;
yxyang 0:d23cb6fd82b7 301 case AFS_16G:
yxyang 0:d23cb6fd82b7 302 aRes = 16.0 / 32768.0;
yxyang 0:d23cb6fd82b7 303 break;
yxyang 0:d23cb6fd82b7 304 }
yxyang 0:d23cb6fd82b7 305 }
yxyang 0:d23cb6fd82b7 306
yxyang 0:d23cb6fd82b7 307 void
yxyang 0:d23cb6fd82b7 308 readAccelData (int16_t *destination)
yxyang 0:d23cb6fd82b7 309 {
yxyang 0:d23cb6fd82b7 310 uint8_t rawData[6]; // x/y/z accel register data stored here
yxyang 0:d23cb6fd82b7 311 readBytes (MPU6050_ADDRESS, ACCEL_XOUT_H, 6,
yxyang 0:d23cb6fd82b7 312 &rawData[0]); // Read the six raw data registers into data array
yxyang 0:d23cb6fd82b7 313 destination[0] = (int16_t) (
yxyang 0:d23cb6fd82b7 314 ((int16_t)rawData[0] << 8)
yxyang 0:d23cb6fd82b7 315 | rawData[1]); // Turn the MSB and LSB into a signed 16-bit value
yxyang 0:d23cb6fd82b7 316 destination[1] = (int16_t) (((int16_t)rawData[2] << 8) | rawData[3]);
yxyang 0:d23cb6fd82b7 317 destination[2] = (int16_t) (((int16_t)rawData[4] << 8) | rawData[5]);
yxyang 0:d23cb6fd82b7 318 }
yxyang 0:d23cb6fd82b7 319
yxyang 0:d23cb6fd82b7 320 void
yxyang 0:d23cb6fd82b7 321 readGyroData (int16_t *destination)
yxyang 0:d23cb6fd82b7 322 {
yxyang 0:d23cb6fd82b7 323 uint8_t rawData[6]; // x/y/z gyro register data stored here
yxyang 0:d23cb6fd82b7 324 readBytes (MPU6050_ADDRESS, GYRO_XOUT_H, 6,
yxyang 0:d23cb6fd82b7 325 &rawData[0]); // Read the six raw data registers sequentially
yxyang 0:d23cb6fd82b7 326 // into data array
yxyang 0:d23cb6fd82b7 327 destination[0] = (int16_t) (
yxyang 0:d23cb6fd82b7 328 ((int16_t)rawData[0] << 8)
yxyang 0:d23cb6fd82b7 329 | rawData[1]); // Turn the MSB and LSB into a signed 16-bit value
yxyang 0:d23cb6fd82b7 330 destination[1] = (int16_t) (((int16_t)rawData[2] << 8) | rawData[3]);
yxyang 0:d23cb6fd82b7 331 destination[2] = (int16_t) (((int16_t)rawData[4] << 8) | rawData[5]);
yxyang 0:d23cb6fd82b7 332 }
yxyang 0:d23cb6fd82b7 333
yxyang 0:d23cb6fd82b7 334 int16_t
yxyang 0:d23cb6fd82b7 335 readTempData ()
yxyang 0:d23cb6fd82b7 336 {
yxyang 0:d23cb6fd82b7 337 uint8_t rawData[2]; // x/y/z gyro register data stored here
yxyang 0:d23cb6fd82b7 338 readBytes (MPU6050_ADDRESS, TEMP_OUT_H, 2,
yxyang 0:d23cb6fd82b7 339 &rawData[0]); // Read the two raw data registers sequentially
yxyang 0:d23cb6fd82b7 340 // into data array
yxyang 0:d23cb6fd82b7 341 return (int16_t) (
yxyang 0:d23cb6fd82b7 342 ((int16_t)rawData[0]) << 8
yxyang 0:d23cb6fd82b7 343 | rawData[1]); // Turn the MSB and LSB into a 16-bit value
yxyang 0:d23cb6fd82b7 344 }
yxyang 0:d23cb6fd82b7 345
yxyang 0:d23cb6fd82b7 346 // Configure the motion detection control for low power accelerometer mode
yxyang 0:d23cb6fd82b7 347 void
yxyang 0:d23cb6fd82b7 348 LowPowerAccelOnly ()
yxyang 0:d23cb6fd82b7 349 {
yxyang 0:d23cb6fd82b7 350
yxyang 0:d23cb6fd82b7 351 // The sensor has a high-pass filter necessary to invoke to allow the
yxyang 0:d23cb6fd82b7 352 // sensor motion detection algorithms work properly
yxyang 0:d23cb6fd82b7 353 // Motion detection occurs on free-fall (acceleration below a threshold for
yxyang 0:d23cb6fd82b7 354 // some time for all axes), motion (acceleration
yxyang 0:d23cb6fd82b7 355 // above a threshold for some time on at least one axis), and zero-motion
yxyang 0:d23cb6fd82b7 356 // toggle (acceleration on each axis less than a
yxyang 0:d23cb6fd82b7 357 // threshold for some time sets this flag, motion above the threshold turns
yxyang 0:d23cb6fd82b7 358 // it off). The high-pass filter takes gravity out
yxyang 0:d23cb6fd82b7 359 // consideration for these threshold evaluations; otherwise, the flags
yxyang 0:d23cb6fd82b7 360 // would be set all the time!
yxyang 0:d23cb6fd82b7 361
yxyang 0:d23cb6fd82b7 362 uint8_t c = readByte (MPU6050_ADDRESS, PWR_MGMT_1);
yxyang 0:d23cb6fd82b7 363 writeByte (MPU6050_ADDRESS, PWR_MGMT_1,
yxyang 0:d23cb6fd82b7 364 c & ~0x30); // Clear sleep and cycle bits [5:6]
yxyang 0:d23cb6fd82b7 365 writeByte (MPU6050_ADDRESS, PWR_MGMT_1,
yxyang 0:d23cb6fd82b7 366 c | 0x30); // Set sleep and cycle bits [5:6] to zero to make
yxyang 0:d23cb6fd82b7 367 // sure accelerometer is running
yxyang 0:d23cb6fd82b7 368
yxyang 0:d23cb6fd82b7 369 c = readByte (MPU6050_ADDRESS, PWR_MGMT_2);
yxyang 0:d23cb6fd82b7 370 writeByte (MPU6050_ADDRESS, PWR_MGMT_2,
yxyang 0:d23cb6fd82b7 371 c & ~0x38); // Clear standby XA, YA, and ZA bits [3:5]
yxyang 0:d23cb6fd82b7 372 writeByte (MPU6050_ADDRESS, PWR_MGMT_2,
yxyang 0:d23cb6fd82b7 373 c | 0x00); // Set XA, YA, and ZA bits [3:5] to zero to make sure
yxyang 0:d23cb6fd82b7 374 // accelerometer is running
yxyang 0:d23cb6fd82b7 375
yxyang 0:d23cb6fd82b7 376 c = readByte (MPU6050_ADDRESS, ACCEL_CONFIG);
yxyang 0:d23cb6fd82b7 377 writeByte (MPU6050_ADDRESS, ACCEL_CONFIG,
yxyang 0:d23cb6fd82b7 378 c & ~0x07); // Clear high-pass filter bits [2:0]
yxyang 0:d23cb6fd82b7 379 // Set high-pass filter to 0) reset (disable), 1) 5 Hz, 2) 2.5 Hz, 3) 1.25
yxyang 0:d23cb6fd82b7 380 // Hz, 4) 0.63 Hz, or 7) Hold
yxyang 0:d23cb6fd82b7 381 writeByte (
yxyang 0:d23cb6fd82b7 382 MPU6050_ADDRESS, ACCEL_CONFIG,
yxyang 0:d23cb6fd82b7 383 c | 0x00); // Set ACCEL_HPF to 0; reset mode disbaling high-pass filter
yxyang 0:d23cb6fd82b7 384
yxyang 0:d23cb6fd82b7 385 c = readByte (MPU6050_ADDRESS, CONFIG);
yxyang 0:d23cb6fd82b7 386 writeByte (MPU6050_ADDRESS, CONFIG,
yxyang 0:d23cb6fd82b7 387 c & ~0x07); // Clear low-pass filter bits [2:0]
yxyang 0:d23cb6fd82b7 388 writeByte (MPU6050_ADDRESS, CONFIG,
yxyang 0:d23cb6fd82b7 389 c | 0x00); // Set DLPD_CFG to 0; 260 Hz bandwidth, 1 kHz rate
yxyang 0:d23cb6fd82b7 390
yxyang 0:d23cb6fd82b7 391 c = readByte (MPU6050_ADDRESS, INT_ENABLE);
yxyang 0:d23cb6fd82b7 392 writeByte (MPU6050_ADDRESS, INT_ENABLE, c & ~0xFF); // Clear all interrupts
yxyang 0:d23cb6fd82b7 393 writeByte (MPU6050_ADDRESS, INT_ENABLE,
yxyang 0:d23cb6fd82b7 394 0x40); // Enable motion threshold (bits 5) interrupt only
yxyang 0:d23cb6fd82b7 395
yxyang 0:d23cb6fd82b7 396 // Motion detection interrupt requires the absolute value of any axis to
yxyang 0:d23cb6fd82b7 397 // lie above the detection threshold
yxyang 0:d23cb6fd82b7 398 // for at least the counter duration
yxyang 0:d23cb6fd82b7 399 writeByte (MPU6050_ADDRESS, MOT_THR,
yxyang 0:d23cb6fd82b7 400 0x80); // Set motion detection to 0.256 g; LSB = 2 mg
yxyang 0:d23cb6fd82b7 401 writeByte (
yxyang 0:d23cb6fd82b7 402 MPU6050_ADDRESS, MOT_DUR,
yxyang 0:d23cb6fd82b7 403 0x01); // Set motion detect duration to 1 ms; LSB is 1 ms @ 1 kHz rate
yxyang 0:d23cb6fd82b7 404
yxyang 0:d23cb6fd82b7 405 wait (0.1); // Add delay for accumulation of samples
yxyang 0:d23cb6fd82b7 406
yxyang 0:d23cb6fd82b7 407 c = readByte (MPU6050_ADDRESS, ACCEL_CONFIG);
yxyang 0:d23cb6fd82b7 408 writeByte (MPU6050_ADDRESS, ACCEL_CONFIG,
yxyang 0:d23cb6fd82b7 409 c & ~0x07); // Clear high-pass filter bits [2:0]
yxyang 0:d23cb6fd82b7 410 writeByte (MPU6050_ADDRESS, ACCEL_CONFIG, c | 0x07); // Set ACCEL_HPF to 7;
yxyang 0:d23cb6fd82b7 411 // hold the initial
yxyang 0:d23cb6fd82b7 412 // accleration value
yxyang 0:d23cb6fd82b7 413 // as a referance
yxyang 0:d23cb6fd82b7 414
yxyang 0:d23cb6fd82b7 415 c = readByte (MPU6050_ADDRESS, PWR_MGMT_2);
yxyang 0:d23cb6fd82b7 416 writeByte (MPU6050_ADDRESS, PWR_MGMT_2,
yxyang 0:d23cb6fd82b7 417 c & ~0xC7); // Clear standby XA, YA, and ZA bits [3:5] and
yxyang 0:d23cb6fd82b7 418 // LP_WAKE_CTRL bits [6:7]
yxyang 0:d23cb6fd82b7 419 writeByte (MPU6050_ADDRESS, PWR_MGMT_2, c | 0x47); // Set wakeup frequency
yxyang 0:d23cb6fd82b7 420 // to 5 Hz, and disable
yxyang 0:d23cb6fd82b7 421 // XG, YG, and ZG gyros
yxyang 0:d23cb6fd82b7 422 // (bits [0:2])
yxyang 0:d23cb6fd82b7 423
yxyang 0:d23cb6fd82b7 424 c = readByte (MPU6050_ADDRESS, PWR_MGMT_1);
yxyang 0:d23cb6fd82b7 425 writeByte (MPU6050_ADDRESS, PWR_MGMT_1,
yxyang 0:d23cb6fd82b7 426 c & ~0x20); // Clear sleep and cycle bit 5
yxyang 0:d23cb6fd82b7 427 writeByte (MPU6050_ADDRESS, PWR_MGMT_1, c | 0x20); // Set cycle bit 5 to
yxyang 0:d23cb6fd82b7 428 // begin low power
yxyang 0:d23cb6fd82b7 429 // accelerometer motion
yxyang 0:d23cb6fd82b7 430 // interrupts
yxyang 0:d23cb6fd82b7 431 }
yxyang 0:d23cb6fd82b7 432
yxyang 0:d23cb6fd82b7 433 void
yxyang 0:d23cb6fd82b7 434 resetMPU6050 ()
yxyang 0:d23cb6fd82b7 435 {
yxyang 0:d23cb6fd82b7 436 // reset device
yxyang 0:d23cb6fd82b7 437 writeByte (MPU6050_ADDRESS, PWR_MGMT_1,
yxyang 0:d23cb6fd82b7 438 0x80); // Write a one to bit 7 reset bit; toggle reset device
yxyang 0:d23cb6fd82b7 439 wait (0.1);
yxyang 0:d23cb6fd82b7 440 }
yxyang 0:d23cb6fd82b7 441
yxyang 0:d23cb6fd82b7 442 void
yxyang 0:d23cb6fd82b7 443 initMPU6050 ()
yxyang 0:d23cb6fd82b7 444 {
yxyang 0:d23cb6fd82b7 445 // Initialize MPU6050 device
yxyang 0:d23cb6fd82b7 446 // wake up device
yxyang 0:d23cb6fd82b7 447 writeByte (MPU6050_ADDRESS, PWR_MGMT_1,
yxyang 0:d23cb6fd82b7 448 0x00); // Clear sleep mode bit (6), enable all sensors
yxyang 0:d23cb6fd82b7 449 wait (0.1); // Delay 100 ms for PLL to get established on x-axis gyro;
yxyang 0:d23cb6fd82b7 450 // should check for PLL ready interrupt
yxyang 0:d23cb6fd82b7 451
yxyang 0:d23cb6fd82b7 452 // get stable time source
yxyang 0:d23cb6fd82b7 453 writeByte (MPU6050_ADDRESS, PWR_MGMT_1, 0x01); // Set clock source to be
yxyang 0:d23cb6fd82b7 454 // PLL with x-axis gyroscope
yxyang 0:d23cb6fd82b7 455 // reference, bits 2:0 = 001
yxyang 0:d23cb6fd82b7 456
yxyang 0:d23cb6fd82b7 457 // Configure Gyro and Accelerometer
yxyang 0:d23cb6fd82b7 458 // Disable FSYNC and set accelerometer and gyro bandwidth to 44 and 42 Hz,
yxyang 0:d23cb6fd82b7 459 // respectively;
yxyang 0:d23cb6fd82b7 460 // DLPF_CFG = bits 2:0 = 010; this sets the sample rate at 1 kHz for both
yxyang 0:d23cb6fd82b7 461 // Maximum delay is 4.9 ms which is just over a 200 Hz maximum rate
yxyang 0:d23cb6fd82b7 462 writeByte (MPU6050_ADDRESS, CONFIG, 0x03);
yxyang 0:d23cb6fd82b7 463
yxyang 0:d23cb6fd82b7 464 // Set sample rate = gyroscope output rate/(1 + SMPLRT_DIV)
yxyang 0:d23cb6fd82b7 465 writeByte (MPU6050_ADDRESS, SMPLRT_DIV,
yxyang 0:d23cb6fd82b7 466 0x04); // Use a 200 Hz rate; the same rate set in CONFIG above
yxyang 0:d23cb6fd82b7 467
yxyang 0:d23cb6fd82b7 468 // Set gyroscope full scale range
yxyang 0:d23cb6fd82b7 469 // Range selects FS_SEL and AFS_SEL are 0 - 3, so 2-bit values are
yxyang 0:d23cb6fd82b7 470 // left-shifted into positions 4:3
yxyang 0:d23cb6fd82b7 471 uint8_t c = readByte (MPU6050_ADDRESS, GYRO_CONFIG);
yxyang 0:d23cb6fd82b7 472 writeByte (MPU6050_ADDRESS, GYRO_CONFIG,
yxyang 0:d23cb6fd82b7 473 c & ~0xE0); // Clear self-test bits [7:5]
yxyang 0:d23cb6fd82b7 474 writeByte (MPU6050_ADDRESS, GYRO_CONFIG,
yxyang 0:d23cb6fd82b7 475 c & ~0x18); // Clear AFS bits [4:3]
yxyang 0:d23cb6fd82b7 476 writeByte (MPU6050_ADDRESS, GYRO_CONFIG,
yxyang 0:d23cb6fd82b7 477 c | Gscale << 3); // Set full scale range for the gyro
yxyang 0:d23cb6fd82b7 478
yxyang 0:d23cb6fd82b7 479 // Set accelerometer configuration
yxyang 0:d23cb6fd82b7 480 c = readByte (MPU6050_ADDRESS, ACCEL_CONFIG);
yxyang 0:d23cb6fd82b7 481 writeByte (MPU6050_ADDRESS, ACCEL_CONFIG,
yxyang 0:d23cb6fd82b7 482 c & ~0xE0); // Clear self-test bits [7:5]
yxyang 0:d23cb6fd82b7 483 writeByte (MPU6050_ADDRESS, ACCEL_CONFIG,
yxyang 0:d23cb6fd82b7 484 c & ~0x18); // Clear AFS bits [4:3]
yxyang 0:d23cb6fd82b7 485 writeByte (MPU6050_ADDRESS, ACCEL_CONFIG,
yxyang 0:d23cb6fd82b7 486 c | Ascale << 3); // Set full scale range for the accelerometer
yxyang 0:d23cb6fd82b7 487
yxyang 0:d23cb6fd82b7 488 // Configure Interrupts and Bypass Enable
yxyang 0:d23cb6fd82b7 489 // Set interrupt pin active high, push-pull, and clear on read of
yxyang 0:d23cb6fd82b7 490 // INT_STATUS, enable I2C_BYPASS_EN so additional chips
yxyang 0:d23cb6fd82b7 491 // can join the I2C bus and all can be controlled by the Arduino as master
yxyang 0:d23cb6fd82b7 492 writeByte (MPU6050_ADDRESS, INT_PIN_CFG, 0x22);
yxyang 0:d23cb6fd82b7 493 writeByte (MPU6050_ADDRESS, INT_ENABLE,
yxyang 0:d23cb6fd82b7 494 0x01); // Enable data ready (bit 0) interrupt
yxyang 0:d23cb6fd82b7 495 }
yxyang 0:d23cb6fd82b7 496
yxyang 0:d23cb6fd82b7 497 // Function which accumulates gyro and accelerometer data after device
yxyang 0:d23cb6fd82b7 498 // initialization. It calculates the average
yxyang 0:d23cb6fd82b7 499 // of the at-rest readings and then loads the resulting offsets into
yxyang 0:d23cb6fd82b7 500 // accelerometer and gyro bias registers.
yxyang 0:d23cb6fd82b7 501 void
yxyang 0:d23cb6fd82b7 502 calibrateMPU6050 (float *dest1, float *dest2)
yxyang 0:d23cb6fd82b7 503 {
yxyang 0:d23cb6fd82b7 504 uint8_t
yxyang 0:d23cb6fd82b7 505 data[12]; // data array to hold accelerometer and gyro x, y, z, data
yxyang 0:d23cb6fd82b7 506 uint16_t ii, packet_count, fifo_count;
yxyang 0:d23cb6fd82b7 507 int32_t gyro_bias[3] = { 0, 0, 0 }, accel_bias[3] = { 0, 0, 0 };
yxyang 0:d23cb6fd82b7 508
yxyang 0:d23cb6fd82b7 509 // reset device, reset all registers, clear gyro and accelerometer bias
yxyang 0:d23cb6fd82b7 510 // registers
yxyang 0:d23cb6fd82b7 511 writeByte (MPU6050_ADDRESS, PWR_MGMT_1,
yxyang 0:d23cb6fd82b7 512 0x80); // Write a one to bit 7 reset bit; toggle reset device
yxyang 0:d23cb6fd82b7 513 wait (0.1);
yxyang 0:d23cb6fd82b7 514
yxyang 0:d23cb6fd82b7 515 // get stable time source
yxyang 0:d23cb6fd82b7 516 // Set clock source to be PLL with x-axis gyroscope reference, bits 2:0 =
yxyang 0:d23cb6fd82b7 517 // 001
yxyang 0:d23cb6fd82b7 518 writeByte (MPU6050_ADDRESS, PWR_MGMT_1, 0x01);
yxyang 0:d23cb6fd82b7 519 writeByte (MPU6050_ADDRESS, PWR_MGMT_2, 0x00);
yxyang 0:d23cb6fd82b7 520 wait (0.2);
yxyang 0:d23cb6fd82b7 521
yxyang 0:d23cb6fd82b7 522 // Configure device for bias calculation
yxyang 0:d23cb6fd82b7 523 writeByte (MPU6050_ADDRESS, INT_ENABLE, 0x00); // Disable all interrupts
yxyang 0:d23cb6fd82b7 524 writeByte (MPU6050_ADDRESS, FIFO_EN, 0x00); // Disable FIFO
yxyang 0:d23cb6fd82b7 525 writeByte (MPU6050_ADDRESS, PWR_MGMT_1,
yxyang 0:d23cb6fd82b7 526 0x00); // Turn on internal clock source
yxyang 0:d23cb6fd82b7 527 writeByte (MPU6050_ADDRESS, I2C_MST_CTRL, 0x00); // Disable I2C master
yxyang 0:d23cb6fd82b7 528 writeByte (MPU6050_ADDRESS, USER_CTRL,
yxyang 0:d23cb6fd82b7 529 0x00); // Disable FIFO and I2C master modes
yxyang 0:d23cb6fd82b7 530 writeByte (MPU6050_ADDRESS, USER_CTRL, 0x0C); // Reset FIFO and DMP
yxyang 0:d23cb6fd82b7 531 wait (0.015);
yxyang 0:d23cb6fd82b7 532
yxyang 0:d23cb6fd82b7 533 // Configure MPU6050 gyro and accelerometer for bias calculation
yxyang 0:d23cb6fd82b7 534 writeByte (MPU6050_ADDRESS, CONFIG, 0x01); // Set low-pass filter to 188 Hz
yxyang 0:d23cb6fd82b7 535 writeByte (MPU6050_ADDRESS, SMPLRT_DIV, 0x00); // Set sample rate to 1 kHz
yxyang 0:d23cb6fd82b7 536 writeByte (MPU6050_ADDRESS, GYRO_CONFIG, 0x00); // Set gyro full-scale to
yxyang 0:d23cb6fd82b7 537 // 250 degrees per second,
yxyang 0:d23cb6fd82b7 538 // maximum sensitivity
yxyang 0:d23cb6fd82b7 539 writeByte (
yxyang 0:d23cb6fd82b7 540 MPU6050_ADDRESS, ACCEL_CONFIG,
yxyang 0:d23cb6fd82b7 541 0x00); // Set accelerometer full-scale to 2 g, maximum sensitivity
yxyang 0:d23cb6fd82b7 542
yxyang 0:d23cb6fd82b7 543 uint16_t gyrosensitivity = 131; // = 131 LSB/degrees/sec
yxyang 0:d23cb6fd82b7 544 uint16_t accelsensitivity = 16384; // = 16384 LSB/g
yxyang 0:d23cb6fd82b7 545
yxyang 0:d23cb6fd82b7 546 // Configure FIFO to capture accelerometer and gyro data for bias
yxyang 0:d23cb6fd82b7 547 // calculation
yxyang 0:d23cb6fd82b7 548 writeByte (MPU6050_ADDRESS, USER_CTRL, 0x40); // Enable FIFO
yxyang 0:d23cb6fd82b7 549 writeByte (MPU6050_ADDRESS, FIFO_EN, 0x78); // Enable gyro and
yxyang 0:d23cb6fd82b7 550 // accelerometer sensors for
yxyang 0:d23cb6fd82b7 551 // FIFO (max size 1024 bytes
yxyang 0:d23cb6fd82b7 552 // in MPU-6050)
yxyang 0:d23cb6fd82b7 553 wait (0.08); // accumulate 80 samples in 80 milliseconds = 960 bytes
yxyang 0:d23cb6fd82b7 554
yxyang 0:d23cb6fd82b7 555 // At end of sample accumulation, turn off FIFO sensor read
yxyang 0:d23cb6fd82b7 556 writeByte (MPU6050_ADDRESS, FIFO_EN,
yxyang 0:d23cb6fd82b7 557 0x00); // Disable gyro and accelerometer sensors for FIFO
yxyang 0:d23cb6fd82b7 558 readBytes (MPU6050_ADDRESS, FIFO_COUNTH, 2,
yxyang 0:d23cb6fd82b7 559 &data[0]); // read FIFO sample count
yxyang 0:d23cb6fd82b7 560 fifo_count = ((uint16_t)data[0] << 8) | data[1];
yxyang 0:d23cb6fd82b7 561 packet_count = fifo_count / 12; // How many sets of full gyro and
yxyang 0:d23cb6fd82b7 562 // accelerometer data for averaging
yxyang 0:d23cb6fd82b7 563
yxyang 0:d23cb6fd82b7 564 for (ii = 0; ii < packet_count; ii++)
yxyang 0:d23cb6fd82b7 565 {
yxyang 0:d23cb6fd82b7 566 int16_t accel_temp[3] = { 0, 0, 0 }, gyro_temp[3] = { 0, 0, 0 };
yxyang 0:d23cb6fd82b7 567 readBytes (MPU6050_ADDRESS, FIFO_R_W, 12,
yxyang 0:d23cb6fd82b7 568 &data[0]); // read data for averaging
yxyang 0:d23cb6fd82b7 569 accel_temp[0] = (int16_t) (
yxyang 0:d23cb6fd82b7 570 ((int16_t)data[0] << 8)
yxyang 0:d23cb6fd82b7 571 | data[1]); // Form signed 16-bit integer for each sample in FIFO
yxyang 0:d23cb6fd82b7 572 accel_temp[1] = (int16_t) (((int16_t)data[2] << 8) | data[3]);
yxyang 0:d23cb6fd82b7 573 accel_temp[2] = (int16_t) (((int16_t)data[4] << 8) | data[5]);
yxyang 0:d23cb6fd82b7 574 gyro_temp[0] = (int16_t) (((int16_t)data[6] << 8) | data[7]);
yxyang 0:d23cb6fd82b7 575 gyro_temp[1] = (int16_t) (((int16_t)data[8] << 8) | data[9]);
yxyang 0:d23cb6fd82b7 576 gyro_temp[2] = (int16_t) (((int16_t)data[10] << 8) | data[11]);
yxyang 0:d23cb6fd82b7 577
yxyang 0:d23cb6fd82b7 578 accel_bias[0] += (int32_t)accel_temp[0]; // Sum individual signed
yxyang 0:d23cb6fd82b7 579 // 16-bit biases to get
yxyang 0:d23cb6fd82b7 580 // accumulated signed 32-bit
yxyang 0:d23cb6fd82b7 581 // biases
yxyang 0:d23cb6fd82b7 582 accel_bias[1] += (int32_t)accel_temp[1];
yxyang 0:d23cb6fd82b7 583 accel_bias[2] += (int32_t)accel_temp[2];
yxyang 0:d23cb6fd82b7 584 gyro_bias[0] += (int32_t)gyro_temp[0];
yxyang 0:d23cb6fd82b7 585 gyro_bias[1] += (int32_t)gyro_temp[1];
yxyang 0:d23cb6fd82b7 586 gyro_bias[2] += (int32_t)gyro_temp[2];
yxyang 0:d23cb6fd82b7 587 }
yxyang 0:d23cb6fd82b7 588 accel_bias[0]
yxyang 0:d23cb6fd82b7 589 /= (int32_t)packet_count; // Normalize sums to get average count biases
yxyang 0:d23cb6fd82b7 590 accel_bias[1] /= (int32_t)packet_count;
yxyang 0:d23cb6fd82b7 591 accel_bias[2] /= (int32_t)packet_count;
yxyang 0:d23cb6fd82b7 592 gyro_bias[0] /= (int32_t)packet_count;
yxyang 0:d23cb6fd82b7 593 gyro_bias[1] /= (int32_t)packet_count;
yxyang 0:d23cb6fd82b7 594 gyro_bias[2] /= (int32_t)packet_count;
yxyang 0:d23cb6fd82b7 595
yxyang 0:d23cb6fd82b7 596 if (accel_bias[2] > 0L)
yxyang 0:d23cb6fd82b7 597 {
yxyang 0:d23cb6fd82b7 598 accel_bias[2] -= (int32_t)accelsensitivity;
yxyang 0:d23cb6fd82b7 599 } // Remove gravity from the z-axis accelerometer bias calculation
yxyang 0:d23cb6fd82b7 600 else
yxyang 0:d23cb6fd82b7 601 {
yxyang 0:d23cb6fd82b7 602 accel_bias[2] += (int32_t)accelsensitivity;
yxyang 0:d23cb6fd82b7 603 }
yxyang 0:d23cb6fd82b7 604
yxyang 0:d23cb6fd82b7 605 // Construct the gyro biases for push to the hardware gyro bias registers,
yxyang 0:d23cb6fd82b7 606 // which are reset to zero upon device startup
yxyang 0:d23cb6fd82b7 607 data[0] = (-gyro_bias[0] / 4 >> 8) & 0xFF; // Divide by 4 to get 32.9 LSB
yxyang 0:d23cb6fd82b7 608 // per deg/s to conform to
yxyang 0:d23cb6fd82b7 609 // expected bias input format
yxyang 0:d23cb6fd82b7 610 data[1] = (-gyro_bias[0] / 4) & 0xFF; // Biases are additive, so change
yxyang 0:d23cb6fd82b7 611 // sign on calculated average gyro
yxyang 0:d23cb6fd82b7 612 // biases
yxyang 0:d23cb6fd82b7 613 data[2] = (-gyro_bias[1] / 4 >> 8) & 0xFF;
yxyang 0:d23cb6fd82b7 614 data[3] = (-gyro_bias[1] / 4) & 0xFF;
yxyang 0:d23cb6fd82b7 615 data[4] = (-gyro_bias[2] / 4 >> 8) & 0xFF;
yxyang 0:d23cb6fd82b7 616 data[5] = (-gyro_bias[2] / 4) & 0xFF;
yxyang 0:d23cb6fd82b7 617
yxyang 0:d23cb6fd82b7 618 // Push gyro biases to hardware registers
yxyang 0:d23cb6fd82b7 619 writeByte (MPU6050_ADDRESS, XG_OFFS_USRH, data[0]);
yxyang 0:d23cb6fd82b7 620 writeByte (MPU6050_ADDRESS, XG_OFFS_USRL, data[1]);
yxyang 0:d23cb6fd82b7 621 writeByte (MPU6050_ADDRESS, YG_OFFS_USRH, data[2]);
yxyang 0:d23cb6fd82b7 622 writeByte (MPU6050_ADDRESS, YG_OFFS_USRL, data[3]);
yxyang 0:d23cb6fd82b7 623 writeByte (MPU6050_ADDRESS, ZG_OFFS_USRH, data[4]);
yxyang 0:d23cb6fd82b7 624 writeByte (MPU6050_ADDRESS, ZG_OFFS_USRL, data[5]);
yxyang 0:d23cb6fd82b7 625
yxyang 0:d23cb6fd82b7 626 dest1[0] = (float)gyro_bias[0]
yxyang 0:d23cb6fd82b7 627 / (float)gyrosensitivity; // construct gyro bias in deg/s for
yxyang 0:d23cb6fd82b7 628 // later manual subtraction
yxyang 0:d23cb6fd82b7 629 dest1[1] = (float)gyro_bias[1] / (float)gyrosensitivity;
yxyang 0:d23cb6fd82b7 630 dest1[2] = (float)gyro_bias[2] / (float)gyrosensitivity;
yxyang 0:d23cb6fd82b7 631
yxyang 0:d23cb6fd82b7 632 // Construct the accelerometer biases for push to the hardware
yxyang 0:d23cb6fd82b7 633 // accelerometer bias registers. These registers contain
yxyang 0:d23cb6fd82b7 634 // factory trim values which must be added to the calculated accelerometer
yxyang 0:d23cb6fd82b7 635 // biases; on boot up these registers will hold
yxyang 0:d23cb6fd82b7 636 // non-zero values. In addition, bit 0 of the lower byte must be preserved
yxyang 0:d23cb6fd82b7 637 // since it is used for temperature
yxyang 0:d23cb6fd82b7 638 // compensation calculations. Accelerometer bias registers expect bias
yxyang 0:d23cb6fd82b7 639 // input as 2048 LSB per g, so that
yxyang 0:d23cb6fd82b7 640 // the accelerometer biases calculated above must be divided by 8.
yxyang 0:d23cb6fd82b7 641
yxyang 0:d23cb6fd82b7 642 int32_t accel_bias_reg[3]
yxyang 0:d23cb6fd82b7 643 = { 0, 0, 0 }; // A place to hold the factory accelerometer trim biases
yxyang 0:d23cb6fd82b7 644 readBytes (MPU6050_ADDRESS, XA_OFFSET_H, 2,
yxyang 0:d23cb6fd82b7 645 &data[0]); // Read factory accelerometer trim values
yxyang 0:d23cb6fd82b7 646 accel_bias_reg[0] = (int16_t) ((int16_t)data[0] << 8) | data[1];
yxyang 0:d23cb6fd82b7 647 readBytes (MPU6050_ADDRESS, YA_OFFSET_H, 2, &data[0]);
yxyang 0:d23cb6fd82b7 648 accel_bias_reg[1] = (int16_t) ((int16_t)data[0] << 8) | data[1];
yxyang 0:d23cb6fd82b7 649 readBytes (MPU6050_ADDRESS, ZA_OFFSET_H, 2, &data[0]);
yxyang 0:d23cb6fd82b7 650 accel_bias_reg[2] = (int16_t) ((int16_t)data[0] << 8) | data[1];
yxyang 0:d23cb6fd82b7 651
yxyang 0:d23cb6fd82b7 652 uint32_t mask = 1uL; // Define mask for temperature compensation bit 0 of
yxyang 0:d23cb6fd82b7 653 // lower byte of accelerometer bias registers
yxyang 0:d23cb6fd82b7 654 uint8_t mask_bit[3] = {
yxyang 0:d23cb6fd82b7 655 0, 0, 0
yxyang 0:d23cb6fd82b7 656 }; // Define array to hold mask bit for each accelerometer bias axis
yxyang 0:d23cb6fd82b7 657
yxyang 0:d23cb6fd82b7 658 for (ii = 0; ii < 3; ii++)
yxyang 0:d23cb6fd82b7 659 {
yxyang 0:d23cb6fd82b7 660 if (accel_bias_reg[ii] & mask)
yxyang 0:d23cb6fd82b7 661 mask_bit[ii] = 0x01; // If temperature compensation bit is set,
yxyang 0:d23cb6fd82b7 662 // record that fact in mask_bit
yxyang 0:d23cb6fd82b7 663 }
yxyang 0:d23cb6fd82b7 664
yxyang 0:d23cb6fd82b7 665 // Construct total accelerometer bias, including calculated average
yxyang 0:d23cb6fd82b7 666 // accelerometer bias from above
yxyang 0:d23cb6fd82b7 667 accel_bias_reg[0] -= (accel_bias[0] / 8); // Subtract calculated averaged
yxyang 0:d23cb6fd82b7 668 // accelerometer bias scaled to
yxyang 0:d23cb6fd82b7 669 // 2048 LSB/g (16 g full scale)
yxyang 0:d23cb6fd82b7 670 accel_bias_reg[1] -= (accel_bias[1] / 8);
yxyang 0:d23cb6fd82b7 671 accel_bias_reg[2] -= (accel_bias[2] / 8);
yxyang 0:d23cb6fd82b7 672
yxyang 0:d23cb6fd82b7 673 data[0] = (accel_bias_reg[0] >> 8) & 0xFF;
yxyang 0:d23cb6fd82b7 674 data[1] = (accel_bias_reg[0]) & 0xFF;
yxyang 0:d23cb6fd82b7 675 data[1] = data[1] | mask_bit[0]; // preserve temperature compensation bit
yxyang 0:d23cb6fd82b7 676 // when writing back to accelerometer bias
yxyang 0:d23cb6fd82b7 677 // registers
yxyang 0:d23cb6fd82b7 678 data[2] = (accel_bias_reg[1] >> 8) & 0xFF;
yxyang 0:d23cb6fd82b7 679 data[3] = (accel_bias_reg[1]) & 0xFF;
yxyang 0:d23cb6fd82b7 680 data[3] = data[3] | mask_bit[1]; // preserve temperature compensation bit
yxyang 0:d23cb6fd82b7 681 // when writing back to accelerometer bias
yxyang 0:d23cb6fd82b7 682 // registers
yxyang 0:d23cb6fd82b7 683 data[4] = (accel_bias_reg[2] >> 8) & 0xFF;
yxyang 0:d23cb6fd82b7 684 data[5] = (accel_bias_reg[2]) & 0xFF;
yxyang 0:d23cb6fd82b7 685 data[5] = data[5] | mask_bit[2]; // preserve temperature compensation bit
yxyang 0:d23cb6fd82b7 686 // when writing back to accelerometer bias
yxyang 0:d23cb6fd82b7 687 // registers
yxyang 0:d23cb6fd82b7 688
yxyang 0:d23cb6fd82b7 689 // Push accelerometer biases to hardware registers
yxyang 0:d23cb6fd82b7 690 // writeByte(MPU6050_ADDRESS, XA_OFFSET_H, data[0]);
yxyang 0:d23cb6fd82b7 691 // writeByte(MPU6050_ADDRESS, XA_OFFSET_L_TC, data[1]);
yxyang 0:d23cb6fd82b7 692 // writeByte(MPU6050_ADDRESS, YA_OFFSET_H, data[2]);
yxyang 0:d23cb6fd82b7 693 // writeByte(MPU6050_ADDRESS, YA_OFFSET_L_TC, data[3]);
yxyang 0:d23cb6fd82b7 694 // writeByte(MPU6050_ADDRESS, ZA_OFFSET_H, data[4]);
yxyang 0:d23cb6fd82b7 695 // writeByte(MPU6050_ADDRESS, ZA_OFFSET_L_TC, data[5]);
yxyang 0:d23cb6fd82b7 696
yxyang 0:d23cb6fd82b7 697 // Output scaled accelerometer biases for manual subtraction in the main
yxyang 0:d23cb6fd82b7 698 // program
yxyang 0:d23cb6fd82b7 699 dest2[0] = (float)accel_bias[0] / (float)accelsensitivity;
yxyang 0:d23cb6fd82b7 700 dest2[1] = (float)accel_bias[1] / (float)accelsensitivity;
yxyang 0:d23cb6fd82b7 701 dest2[2] = (float)accel_bias[2] / (float)accelsensitivity;
yxyang 0:d23cb6fd82b7 702 }
yxyang 0:d23cb6fd82b7 703
yxyang 0:d23cb6fd82b7 704 // Accelerometer and gyroscope self test; check calibration wrt factory
yxyang 0:d23cb6fd82b7 705 // settings
yxyang 0:d23cb6fd82b7 706 void MPU6050SelfTest (float *destination) // Should return percent deviation
yxyang 0:d23cb6fd82b7 707 // from factory trim values, +/- 14
yxyang 0:d23cb6fd82b7 708 // or less deviation is a pass
yxyang 0:d23cb6fd82b7 709 {
yxyang 0:d23cb6fd82b7 710 uint8_t rawData[4] = { 0, 0, 0, 0 };
yxyang 0:d23cb6fd82b7 711 uint8_t selfTest[6];
yxyang 0:d23cb6fd82b7 712 float factoryTrim[6];
yxyang 0:d23cb6fd82b7 713
yxyang 0:d23cb6fd82b7 714 // Configure the accelerometer for self-test
yxyang 0:d23cb6fd82b7 715 writeByte (MPU6050_ADDRESS, ACCEL_CONFIG, 0xF0); // Enable self test on all
yxyang 0:d23cb6fd82b7 716 // three axes and set
yxyang 0:d23cb6fd82b7 717 // accelerometer range to
yxyang 0:d23cb6fd82b7 718 // +/- 8 g
yxyang 0:d23cb6fd82b7 719 writeByte (MPU6050_ADDRESS, GYRO_CONFIG, 0xE0); // Enable self test on all
yxyang 0:d23cb6fd82b7 720 // three axes and set gyro
yxyang 0:d23cb6fd82b7 721 // range to +/- 250
yxyang 0:d23cb6fd82b7 722 // degrees/s
yxyang 0:d23cb6fd82b7 723 wait (0.25); // Delay a while to let the device execute the self-test
yxyang 0:d23cb6fd82b7 724 // rawData[0]
yxyang 0:d23cb6fd82b7 725 // = readByte (MPU6050_ADDRESS, SELF_TEST_X); // X-axis self-test
yxyang 0:d23cb6fd82b7 726 // results
yxyang 0:d23cb6fd82b7 727 // rawData[1]
yxyang 0:d23cb6fd82b7 728 // = readByte (MPU6050_ADDRESS, SELF_TEST_Y); // Y-axis self-test
yxyang 0:d23cb6fd82b7 729 // results
yxyang 0:d23cb6fd82b7 730 // rawData[2]
yxyang 0:d23cb6fd82b7 731 // = readByte (MPU6050_ADDRESS, SELF_TEST_Z); // Z-axis self-test
yxyang 0:d23cb6fd82b7 732 // results
yxyang 0:d23cb6fd82b7 733 // rawData[3] = readByte (MPU6050_ADDRESS,
yxyang 0:d23cb6fd82b7 734 // SELF_TEST_A);
yxyang 0:d23cb6fd82b7 735 // Mixed-axis self-test results
yxyang 0:d23cb6fd82b7 736 // Extract the acceleration test results first
yxyang 0:d23cb6fd82b7 737 selfTest[0] = (rawData[0] >> 3)
yxyang 0:d23cb6fd82b7 738 | (rawData[3] & 0x30)
yxyang 0:d23cb6fd82b7 739 >> 4; // XA_TEST result is a five-bit unsigned integer
yxyang 0:d23cb6fd82b7 740 selfTest[1] = (rawData[1] >> 3)
yxyang 0:d23cb6fd82b7 741 | (rawData[3] & 0x0C)
yxyang 0:d23cb6fd82b7 742 >> 4; // YA_TEST result is a five-bit unsigned integer
yxyang 0:d23cb6fd82b7 743 selfTest[2] = (rawData[2] >> 3)
yxyang 0:d23cb6fd82b7 744 | (rawData[3] & 0x03)
yxyang 0:d23cb6fd82b7 745 >> 4; // ZA_TEST result is a five-bit unsigned integer
yxyang 0:d23cb6fd82b7 746 // Extract the gyration test results first
yxyang 0:d23cb6fd82b7 747 selfTest[3]
yxyang 0:d23cb6fd82b7 748 = rawData[0] & 0x1F; // XG_TEST result is a five-bit unsigned integer
yxyang 0:d23cb6fd82b7 749 selfTest[4]
yxyang 0:d23cb6fd82b7 750 = rawData[1] & 0x1F; // YG_TEST result is a five-bit unsigned integer
yxyang 0:d23cb6fd82b7 751 selfTest[5]
yxyang 0:d23cb6fd82b7 752 = rawData[2] & 0x1F; // ZG_TEST result is a five-bit unsigned integer
yxyang 0:d23cb6fd82b7 753 // Process results to allow final comparison with factory set values
yxyang 0:d23cb6fd82b7 754 factoryTrim[0] = (4096.0f * 0.34f)
yxyang 0:d23cb6fd82b7 755 * (pow ((0.92f / 0.34f),
yxyang 0:d23cb6fd82b7 756 ((selfTest[0] - 1.0f)
yxyang 0:d23cb6fd82b7 757 / 30.0f))); // FT[Xa] factory trim calculation
yxyang 0:d23cb6fd82b7 758 factoryTrim[1] = (4096.0f * 0.34f)
yxyang 0:d23cb6fd82b7 759 * (pow ((0.92f / 0.34f),
yxyang 0:d23cb6fd82b7 760 ((selfTest[1] - 1.0f)
yxyang 0:d23cb6fd82b7 761 / 30.0f))); // FT[Ya] factory trim calculation
yxyang 0:d23cb6fd82b7 762 factoryTrim[2] = (4096.0f * 0.34f)
yxyang 0:d23cb6fd82b7 763 * (pow ((0.92f / 0.34f),
yxyang 0:d23cb6fd82b7 764 ((selfTest[2] - 1.0f)
yxyang 0:d23cb6fd82b7 765 / 30.0f))); // FT[Za] factory trim calculation
yxyang 0:d23cb6fd82b7 766 factoryTrim[3]
yxyang 0:d23cb6fd82b7 767 = (25.0f * 131.0f)
yxyang 0:d23cb6fd82b7 768 * (pow (1.046f,
yxyang 0:d23cb6fd82b7 769 (selfTest[3] - 1.0f))); // FT[Xg] factory trim calculation
yxyang 0:d23cb6fd82b7 770 factoryTrim[4]
yxyang 0:d23cb6fd82b7 771 = (-25.0f * 131.0f)
yxyang 0:d23cb6fd82b7 772 * (pow (1.046f,
yxyang 0:d23cb6fd82b7 773 (selfTest[4] - 1.0f))); // FT[Yg] factory trim calculation
yxyang 0:d23cb6fd82b7 774 factoryTrim[5]
yxyang 0:d23cb6fd82b7 775 = (25.0f * 131.0f)
yxyang 0:d23cb6fd82b7 776 * (pow (1.046f,
yxyang 0:d23cb6fd82b7 777 (selfTest[5] - 1.0f))); // FT[Zg] factory trim calculation
yxyang 0:d23cb6fd82b7 778
yxyang 0:d23cb6fd82b7 779 // Output self-test results and factory trim calculation if desired
yxyang 0:d23cb6fd82b7 780 // Serial.println(selfTest[0]); Serial.println(selfTest[1]);
yxyang 0:d23cb6fd82b7 781 // Serial.println(selfTest[2]);
yxyang 0:d23cb6fd82b7 782 // Serial.println(selfTest[3]); Serial.println(selfTest[4]);
yxyang 0:d23cb6fd82b7 783 // Serial.println(selfTest[5]);
yxyang 0:d23cb6fd82b7 784 // Serial.println(factoryTrim[0]); Serial.println(factoryTrim[1]);
yxyang 0:d23cb6fd82b7 785 // Serial.println(factoryTrim[2]);
yxyang 0:d23cb6fd82b7 786 // Serial.println(factoryTrim[3]); Serial.println(factoryTrim[4]);
yxyang 0:d23cb6fd82b7 787 // Serial.println(factoryTrim[5]);
yxyang 0:d23cb6fd82b7 788
yxyang 0:d23cb6fd82b7 789 // Report results as a ratio of (STR - FT)/FT; the change from Factory Trim
yxyang 0:d23cb6fd82b7 790 // of the Self-Test Response
yxyang 0:d23cb6fd82b7 791 // To get to percent, must multiply by 100 and subtract result from 100
yxyang 0:d23cb6fd82b7 792 for (int i = 0; i < 6; i++)
yxyang 0:d23cb6fd82b7 793 {
yxyang 0:d23cb6fd82b7 794 destination[i] = 100.0f
yxyang 0:d23cb6fd82b7 795 + 100.0f * (selfTest[i] - factoryTrim[i])
yxyang 0:d23cb6fd82b7 796 / factoryTrim[i]; // Report percent differences
yxyang 0:d23cb6fd82b7 797 }
yxyang 0:d23cb6fd82b7 798 }
yxyang 0:d23cb6fd82b7 799
yxyang 0:d23cb6fd82b7 800 // Implementation of Sebastian Madgwick's "...efficient orientation filter
yxyang 0:d23cb6fd82b7 801 // for... inertial/magnetic sensor arrays"
yxyang 0:d23cb6fd82b7 802 // (see http://www.x-io.co.uk/category/open-source/ for examples and more
yxyang 0:d23cb6fd82b7 803 // details)
yxyang 0:d23cb6fd82b7 804 // which fuses acceleration and rotation rate to produce a quaternion-based
yxyang 0:d23cb6fd82b7 805 // estimate of relative
yxyang 0:d23cb6fd82b7 806 // device orientation -- which can be converted to yaw, pitch, and roll.
yxyang 0:d23cb6fd82b7 807 // Useful for stabilizing quadcopters, etc.
yxyang 0:d23cb6fd82b7 808 // The performance of the orientation filter is at least as good as
yxyang 0:d23cb6fd82b7 809 // conventional Kalman-based filtering algorithms
yxyang 0:d23cb6fd82b7 810 // but is much less computationally intensive---it can be performed on a 3.3
yxyang 0:d23cb6fd82b7 811 // V Pro Mini operating at 8 MHz!
yxyang 0:d23cb6fd82b7 812 void
yxyang 0:d23cb6fd82b7 813 MadgwickQuaternionUpdate (float ax, float ay, float az, float gx, float gy,
yxyang 0:d23cb6fd82b7 814 float gz)
yxyang 0:d23cb6fd82b7 815 {
yxyang 0:d23cb6fd82b7 816 float q1 = q[0], q2 = q[1], q3 = q[2],
yxyang 0:d23cb6fd82b7 817 q4 = q[3]; // short name local variable for readability
yxyang 0:d23cb6fd82b7 818 float norm; // vector norm
yxyang 0:d23cb6fd82b7 819 float f1, f2, f3; // objective funcyion elements
yxyang 0:d23cb6fd82b7 820 float J_11or24, J_12or23, J_13or22, J_14or21, J_32,
yxyang 0:d23cb6fd82b7 821 J_33; // objective function Jacobian elements
yxyang 0:d23cb6fd82b7 822 float qDot1, qDot2, qDot3, qDot4;
yxyang 0:d23cb6fd82b7 823 float hatDot1, hatDot2, hatDot3, hatDot4;
yxyang 0:d23cb6fd82b7 824 float gerrx, gerry, gerrz, gbiasx, gbiasy, gbiasz; // gyro bias error
yxyang 0:d23cb6fd82b7 825
yxyang 0:d23cb6fd82b7 826 // Auxiliary variables to avoid repeated arithmetic
yxyang 0:d23cb6fd82b7 827 float _halfq1 = 0.5f * q1;
yxyang 0:d23cb6fd82b7 828 float _halfq2 = 0.5f * q2;
yxyang 0:d23cb6fd82b7 829 float _halfq3 = 0.5f * q3;
yxyang 0:d23cb6fd82b7 830 float _halfq4 = 0.5f * q4;
yxyang 0:d23cb6fd82b7 831 float _2q1 = 2.0f * q1;
yxyang 0:d23cb6fd82b7 832 float _2q2 = 2.0f * q2;
yxyang 0:d23cb6fd82b7 833 float _2q3 = 2.0f * q3;
yxyang 0:d23cb6fd82b7 834 float _2q4 = 2.0f * q4;
yxyang 0:d23cb6fd82b7 835 // float _2q1q3 = 2.0f * q1 * q3;
yxyang 0:d23cb6fd82b7 836 // float _2q3q4 = 2.0f * q3 * q4;
yxyang 0:d23cb6fd82b7 837
yxyang 0:d23cb6fd82b7 838 // Normalise accelerometer measurement
yxyang 0:d23cb6fd82b7 839 norm = sqrt (ax * ax + ay * ay + az * az);
yxyang 0:d23cb6fd82b7 840 if (norm == 0.0f)
yxyang 0:d23cb6fd82b7 841 return; // handle NaN
yxyang 0:d23cb6fd82b7 842 norm = 1.0f / norm;
yxyang 0:d23cb6fd82b7 843 ax *= norm;
yxyang 0:d23cb6fd82b7 844 ay *= norm;
yxyang 0:d23cb6fd82b7 845 az *= norm;
yxyang 0:d23cb6fd82b7 846
yxyang 0:d23cb6fd82b7 847 // Compute the objective function and Jacobian
yxyang 0:d23cb6fd82b7 848 f1 = _2q2 * q4 - _2q1 * q3 - ax;
yxyang 0:d23cb6fd82b7 849 f2 = _2q1 * q2 + _2q3 * q4 - ay;
yxyang 0:d23cb6fd82b7 850 f3 = 1.0f - _2q2 * q2 - _2q3 * q3 - az;
yxyang 0:d23cb6fd82b7 851 J_11or24 = _2q3;
yxyang 0:d23cb6fd82b7 852 J_12or23 = _2q4;
yxyang 0:d23cb6fd82b7 853 J_13or22 = _2q1;
yxyang 0:d23cb6fd82b7 854 J_14or21 = _2q2;
yxyang 0:d23cb6fd82b7 855 J_32 = 2.0f * J_14or21;
yxyang 0:d23cb6fd82b7 856 J_33 = 2.0f * J_11or24;
yxyang 0:d23cb6fd82b7 857
yxyang 0:d23cb6fd82b7 858 // Compute the gradient (matrix multiplication)
yxyang 0:d23cb6fd82b7 859 hatDot1 = J_14or21 * f2 - J_11or24 * f1;
yxyang 0:d23cb6fd82b7 860 hatDot2 = J_12or23 * f1 + J_13or22 * f2 - J_32 * f3;
yxyang 0:d23cb6fd82b7 861 hatDot3 = J_12or23 * f2 - J_33 * f3 - J_13or22 * f1;
yxyang 0:d23cb6fd82b7 862 hatDot4 = J_14or21 * f1 + J_11or24 * f2;
yxyang 0:d23cb6fd82b7 863
yxyang 0:d23cb6fd82b7 864 // Normalize the gradient
yxyang 0:d23cb6fd82b7 865 norm = sqrt (hatDot1 * hatDot1 + hatDot2 * hatDot2 + hatDot3 * hatDot3
yxyang 0:d23cb6fd82b7 866 + hatDot4 * hatDot4);
yxyang 0:d23cb6fd82b7 867 hatDot1 /= norm;
yxyang 0:d23cb6fd82b7 868 hatDot2 /= norm;
yxyang 0:d23cb6fd82b7 869 hatDot3 /= norm;
yxyang 0:d23cb6fd82b7 870 hatDot4 /= norm;
yxyang 0:d23cb6fd82b7 871
yxyang 0:d23cb6fd82b7 872 // Compute estimated gyroscope biases
yxyang 0:d23cb6fd82b7 873 gerrx = _2q1 * hatDot2 - _2q2 * hatDot1 - _2q3 * hatDot4 + _2q4 * hatDot3;
yxyang 0:d23cb6fd82b7 874 gerry = _2q1 * hatDot3 + _2q2 * hatDot4 - _2q3 * hatDot1 - _2q4 * hatDot2;
yxyang 0:d23cb6fd82b7 875 gerrz = _2q1 * hatDot4 - _2q2 * hatDot3 + _2q3 * hatDot2 - _2q4 * hatDot1;
yxyang 0:d23cb6fd82b7 876
yxyang 0:d23cb6fd82b7 877 // Compute and remove gyroscope biases
yxyang 0:d23cb6fd82b7 878 gbiasx += gerrx * deltat * zeta;
yxyang 0:d23cb6fd82b7 879 gbiasy += gerry * deltat * zeta;
yxyang 0:d23cb6fd82b7 880 gbiasz += gerrz * deltat * zeta;
yxyang 0:d23cb6fd82b7 881 // gx -= gbiasx;
yxyang 0:d23cb6fd82b7 882 // gy -= gbiasy;
yxyang 0:d23cb6fd82b7 883 // gz -= gbiasz;
yxyang 0:d23cb6fd82b7 884
yxyang 0:d23cb6fd82b7 885 // Compute the quaternion derivative
yxyang 0:d23cb6fd82b7 886 qDot1 = -_halfq2 * gx - _halfq3 * gy - _halfq4 * gz;
yxyang 0:d23cb6fd82b7 887 qDot2 = _halfq1 * gx + _halfq3 * gz - _halfq4 * gy;
yxyang 0:d23cb6fd82b7 888 qDot3 = _halfq1 * gy - _halfq2 * gz + _halfq4 * gx;
yxyang 0:d23cb6fd82b7 889 qDot4 = _halfq1 * gz + _halfq2 * gy - _halfq3 * gx;
yxyang 0:d23cb6fd82b7 890
yxyang 0:d23cb6fd82b7 891 // Compute then integrate estimated quaternion derivative
yxyang 0:d23cb6fd82b7 892 q1 += (qDot1 - (beta * hatDot1)) * deltat;
yxyang 0:d23cb6fd82b7 893 q2 += (qDot2 - (beta * hatDot2)) * deltat;
yxyang 0:d23cb6fd82b7 894 q3 += (qDot3 - (beta * hatDot3)) * deltat;
yxyang 0:d23cb6fd82b7 895 q4 += (qDot4 - (beta * hatDot4)) * deltat;
yxyang 0:d23cb6fd82b7 896
yxyang 0:d23cb6fd82b7 897 // Normalize the quaternion
yxyang 0:d23cb6fd82b7 898 norm
yxyang 0:d23cb6fd82b7 899 = sqrt (q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4); // normalise quaternion
yxyang 0:d23cb6fd82b7 900 norm = 1.0f / norm;
yxyang 0:d23cb6fd82b7 901 q[0] = q1 * norm;
yxyang 0:d23cb6fd82b7 902 q[1] = q2 * norm;
yxyang 0:d23cb6fd82b7 903 q[2] = q3 * norm;
yxyang 0:d23cb6fd82b7 904 q[3] = q4 * norm;
yxyang 0:d23cb6fd82b7 905 }
yxyang 0:d23cb6fd82b7 906 };
yxyang 0:d23cb6fd82b7 907 #endif