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.
Fork of MPU6050 by
MPU6050.cpp
00001 /* MPU6050 Library 00002 * 00003 * @author: Baser Kandehir 00004 * @date: July 16, 2015 00005 * @license: MIT license 00006 * 00007 * Copyright (c) 2015, Baser Kandehir, baser.kandehir@ieee.metu.edu.tr 00008 * 00009 * Permission is hereby granted, free of charge, to any person obtaining a copy 00010 * of this software and associated documentation files (the "Software"), to deal 00011 * in the Software without restriction, including without limitation the rights 00012 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00013 * copies of the Software, and to permit persons to whom the Software is 00014 * furnished to do so, subject to the following conditions: 00015 * 00016 * The above copyright notice and this permission notice shall be included in 00017 * all copies or substantial portions of the Software. 00018 * 00019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00020 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00021 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00022 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00023 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00024 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00025 * THE SOFTWARE. 00026 * 00027 */ 00028 00029 // Most of the code is adapted from Kris Winer's MPU6050 library 00030 00031 #include "MPU6050.h" 00032 00033 /* For LPC1768 board */ 00034 //I2C i2c(p9,p10); // setup i2c (SDA,SCL) 00035 00036 /* For NUCLEO-F411RE board */ 00037 I2C i2c(D14,D15); // setup i2c (SDA,SCL) 00038 00039 /* Set initial input parameters */ 00040 00041 // Acc Full Scale Range +-2G 4G 8G 16G 00042 enum Ascale 00043 { 00044 AFS_2G=0, 00045 AFS_4G, 00046 AFS_8G, 00047 AFS_16G 00048 }; 00049 00050 // Gyro Full Scale Range +-250 500 1000 2000 Degrees per second 00051 enum Gscale 00052 { 00053 GFS_250DPS=0, 00054 GFS_500DPS, 00055 GFS_1000DPS, 00056 GFS_2000DPS 00057 }; 00058 00059 // Sensor datas 00060 float ax,ay,az; 00061 float gx,gy,gz; 00062 int16_t accelData[3],gyroData[3],tempData; 00063 float accelBias[3] = {0, 0, 0}; // Bias corrections for acc 00064 float gyroBias[3] = {0, 0, 0}; // Bias corrections for gyro 00065 00066 // Specify sensor full scale range 00067 int Ascale = AFS_2G; 00068 int Gscale = GFS_250DPS; 00069 00070 // Scale resolutions per LSB for the sensors 00071 float aRes, gRes; 00072 00073 // Calculates Acc resolution 00074 void MPU6050::getAres() 00075 { 00076 switch(Ascale) 00077 { 00078 case AFS_2G: 00079 aRes = 2.0/32768.0; 00080 break; 00081 case AFS_4G: 00082 aRes = 4.0/32768.0; 00083 break; 00084 case AFS_8G: 00085 aRes = 8.0/32768.0; 00086 break; 00087 case AFS_16G: 00088 aRes = 16.0/32768.0; 00089 break; 00090 } 00091 } 00092 00093 // Calculates Gyro resolution 00094 void MPU6050::getGres() 00095 { 00096 switch(Gscale) 00097 { 00098 case GFS_250DPS: 00099 gRes = 250.0/32768.0; 00100 break; 00101 case GFS_500DPS: 00102 gRes = 500.0/32768.0; 00103 break; 00104 case GFS_1000DPS: 00105 gRes = 1000.0/32768.0; 00106 break; 00107 case GFS_2000DPS: 00108 gRes = 2000.0/32768.0; 00109 break; 00110 } 00111 } 00112 00113 void MPU6050::writeByte(uint8_t address, uint8_t subAddress, uint8_t data) 00114 { 00115 char data_write[2]; 00116 data_write[0]=subAddress; // I2C sends MSB first. Namely >>|subAddress|>>|data| 00117 data_write[1]=data; 00118 i2c.write(address,data_write,2,0); // i2c.write(int address, char* data, int length, bool repeated=false); 00119 } 00120 00121 char MPU6050::readByte(uint8_t address, uint8_t subAddress) 00122 { 00123 char data_read[1]; // will store the register data 00124 char data_write[1]; 00125 data_write[0]=subAddress; 00126 i2c.write(address,data_write,1,1); // have not stopped yet 00127 i2c.read(address,data_read,1,0); // read the data and stop 00128 return data_read[0]; 00129 } 00130 00131 void MPU6050::readBytes(uint8_t address, uint8_t subAddress, uint8_t byteNum, uint8_t* dest) 00132 { 00133 char data[14],data_write[1]; 00134 data_write[0]=subAddress; 00135 i2c.write(address,data_write,1,1); 00136 i2c.read(address,data,byteNum,0); 00137 for(int i=0;i<byteNum;i++) // equate the addresses 00138 dest[i]=data[i]; 00139 } 00140 00141 // Communication test: WHO_AM_I register reading 00142 void MPU6050::whoAmI() 00143 { 00144 uint8_t whoAmI = readByte(MPU6050_ADDRESS, WHO_AM_I_MPU6050); // Should return 0x68 00145 pc.printf("I AM 0x%x \r\n",whoAmI); 00146 00147 if(whoAmI==0x68) 00148 { 00149 pc.printf("MPU6050 is online... \r\n"); 00150 // led2=1; 00151 } 00152 else 00153 { 00154 pc.printf("Could not connect to MPU6050 \r\nCheck the connections... \r\n"); 00155 toggler1.attach(&toggle_led1,0.1); // toggles led1 every 100 ms 00156 } 00157 } 00158 00159 // Initializes MPU6050 with the following config: 00160 // PLL with X axis gyroscope reference 00161 // Sample rate: 200Hz for gyro and acc 00162 // Interrupts are disabled 00163 void MPU6050::init() 00164 { 00165 i2c.frequency(400000); // fast i2c: 400 kHz 00166 00167 /* Wake up the device */ 00168 writeByte(MPU6050_ADDRESS, PWR_MGMT_1, 0x00); // wake up the device by clearing the sleep bit (bit6) 00169 wait_ms(100); // wait 100 ms to stabilize 00170 00171 /* Get stable time source */ 00172 // PLL with X axis gyroscope reference is used to improve stability 00173 writeByte(MPU6050_ADDRESS, PWR_MGMT_1, 0x01); 00174 00175 /* Configure Gyroscope and Accelerometer */ 00176 // Disable FSYNC, acc bandwidth: 44 Hz, gyro bandwidth: 42 Hz 00177 // Sample rates: 1kHz, maximum delay: 4.9ms (which is pretty good for a 200 Hz maximum rate) 00178 writeByte(MPU6050_ADDRESS, CONFIG, 0x03); 00179 00180 /* Set sample rate = gyroscope output rate/(1+SMPLRT_DIV) */ 00181 // SMPLRT_DIV=4 and sample rate=200 Hz (compatible with config above) 00182 writeByte(MPU6050_ADDRESS, SMPLRT_DIV, 0x04); 00183 00184 /* Accelerometer configuration */ 00185 uint8_t temp = readByte(MPU6050_ADDRESS, ACCEL_CONFIG); 00186 writeByte(MPU6050_ADDRESS, ACCEL_CONFIG, temp & ~0xE0); // Clear self-test bits [7:5] 00187 writeByte(MPU6050_ADDRESS, ACCEL_CONFIG, temp & ~0x18); // Clear AFS bits [4:3] 00188 writeByte(MPU6050_ADDRESS, ACCEL_CONFIG, temp | Ascale<<3); // Set full scale range 00189 00190 /* Gyroscope configuration */ 00191 temp = readByte(MPU6050_ADDRESS, GYRO_CONFIG); 00192 writeByte(MPU6050_ADDRESS, GYRO_CONFIG, temp & ~0xE0); // Clear self-test bits [7:5] 00193 writeByte(MPU6050_ADDRESS, GYRO_CONFIG, temp & ~0x18); // Clear FS bits [4:3] 00194 writeByte(MPU6050_ADDRESS, GYRO_CONFIG, temp | Gscale<<3); // Set full scale range 00195 } 00196 00197 // Resets the device 00198 void MPU6050::reset() 00199 { 00200 writeByte(MPU6050_ADDRESS, PWR_MGMT_1, 0x80); // set bit7 to reset the device 00201 wait_ms(100); // wait 100 ms to stabilize 00202 } 00203 00204 void MPU6050::readAccelData(int16_t* dest) 00205 { 00206 uint8_t rawData[6]; // x,y,z acc data 00207 readBytes(MPU6050_ADDRESS, ACCEL_XOUT_H, 6, &rawData[0]); // read six raw data registers sequentially and write them into data array 00208 00209 /* Turn the MSB LSB into signed 16-bit value */ 00210 dest[0] = (int16_t)(((int16_t)rawData[0]<<8) | rawData[1]); // ACCEL_XOUT 00211 dest[1] = (int16_t)(((int16_t)rawData[2]<<8) | rawData[3]); // ACCEL_YOUT 00212 dest[2] = (int16_t)(((int16_t)rawData[4]<<8) | rawData[5]); // ACCEL_ZOUT 00213 } 00214 00215 void MPU6050::readGyroData(int16_t* dest) 00216 { 00217 uint8_t rawData[6]; // x,y,z gyro data 00218 readBytes(MPU6050_ADDRESS, GYRO_XOUT_H, 6, &rawData[0]); // read the six raw data registers sequentially and write them into data array 00219 00220 /* Turn the MSB LSB into signed 16-bit value */ 00221 dest[0] = (int16_t)(((int16_t)rawData[0]<<8) | rawData[1]); // GYRO_XOUT 00222 dest[1] = (int16_t)(((int16_t)rawData[2]<<8) | rawData[3]); // GYRO_YOUT 00223 dest[2] = (int16_t)(((int16_t)rawData[4]<<8) | rawData[5]); // GYRO_ZOUT 00224 } 00225 00226 int16_t MPU6050::readTempData() 00227 { 00228 uint8_t rawData[2]; // temperature data 00229 readBytes(MPU6050_ADDRESS, TEMP_OUT_H, 2, &rawData[0]); // read the two raw data registers sequentially and write them into data array 00230 return (int16_t)(((int16_t)rawData[0]<<8) | rawData[1]); // turn the MSB LSB into signed 16-bit value 00231 } 00232 00233 /* Function which accumulates gyro and accelerometer data after device initialization. 00234 It calculates the average of the at-rest readings and 00235 then loads the resulting offsets into accelerometer and gyro bias registers. */ 00236 /* 00237 IMPORTANT NOTE: In this function; 00238 Resulting accel offsets are NOT pushed to the accel bias registers. accelBias[i] offsets are used in the main program. 00239 Resulting gyro offsets are pushed to the gyro bias registers. gyroBias[i] offsets are NOT used in the main program. 00240 Resulting data seems satisfactory. 00241 */ 00242 // dest1: accelBias dest2: gyroBias 00243 void MPU6050::calibrate(float* dest1, float* dest2) 00244 { 00245 uint8_t data[12]; // data array to hold acc and gyro x,y,z data 00246 uint16_t fifo_count, packet_count, count; 00247 int32_t accel_bias[3] = {0,0,0}; 00248 int32_t gyro_bias[3] = {0,0,0}; 00249 float aRes = 2.0/32768.0; 00250 float gRes = 250.0/32768.0; 00251 uint16_t accelsensitivity = 16384; // = 1/aRes = 16384 LSB/g 00252 //uint16_t gyrosensitivity = 131; // = 1/gRes = 131 LSB/dps 00253 00254 reset(); // Reset device 00255 00256 /* Get stable time source */ 00257 writeByte(MPU6050_ADDRESS, PWR_MGMT_1, 0x01); // PLL with X axis gyroscope reference is used to improve stability 00258 writeByte(MPU6050_ADDRESS, PWR_MGMT_2, 0x00); // Disable accel only low power mode 00259 wait(0.2); 00260 00261 /* Configure device for bias calculation */ 00262 writeByte(MPU6050_ADDRESS, INT_ENABLE, 0x00); // Disable all interrupts 00263 writeByte(MPU6050_ADDRESS, FIFO_EN, 0x00); // Disable FIFO 00264 writeByte(MPU6050_ADDRESS, PWR_MGMT_1, 0x00); // Turn on internal clock source 00265 writeByte(MPU6050_ADDRESS, I2C_MST_CTRL, 0x00); // Disable I2C master 00266 writeByte(MPU6050_ADDRESS, USER_CTRL, 0x00); // Disable FIFO and I2C master modes 00267 writeByte(MPU6050_ADDRESS, USER_CTRL, 0x04); // Reset FIFO 00268 wait(0.015); 00269 00270 /* Configure accel and gyro for bias calculation */ 00271 writeByte(MPU6050_ADDRESS, CONFIG, 0x01); // Set low-pass filter to 188 Hz 00272 writeByte(MPU6050_ADDRESS, SMPLRT_DIV, 0x00); // Set sample rate to 1 kHz 00273 writeByte(MPU6050_ADDRESS, ACCEL_CONFIG, 0x00); // Set accelerometer full-scale to 2 g, maximum sensitivity 00274 writeByte(MPU6050_ADDRESS, GYRO_CONFIG, 0x00); // Set gyro full-scale to 250 degrees per second, maximum sensitivity 00275 00276 /* Configure FIFO to capture accelerometer and gyro data for bias calculation */ 00277 writeByte(MPU6050_ADDRESS, USER_CTRL, 0x40); // Enable FIFO 00278 writeByte(MPU6050_ADDRESS, FIFO_EN, 0x78); // Enable accelerometer and gyro for FIFO (max size 1024 bytes in MPU-6050) 00279 wait(0.08); // Sample rate is 1 kHz, accumulates 80 samples in 80 milliseconds. 00280 // accX: 2 byte, accY: 2 byte, accZ: 2 byte. gyroX: 2 byte, gyroY: 2 byte, gyroZ: 2 byte. 12*80=960 byte < 1024 byte 00281 00282 /* At end of sample accumulation, turn off FIFO sensor read */ 00283 writeByte(MPU6050_ADDRESS, FIFO_EN, 0x00); // Disable FIFO 00284 readBytes(MPU6050_ADDRESS, FIFO_COUNTH, 2, &data[0]); // Read FIFO sample count 00285 fifo_count = ((uint16_t)data[0] << 8) | data[1]; 00286 packet_count = fifo_count/12; // The number of sets of full acc and gyro data for averaging. packet_count = 80 in this case 00287 00288 for(count=0; count<packet_count; count++) 00289 { 00290 int16_t accel_temp[3]={0,0,0}; 00291 int16_t gyro_temp[3]={0,0,0}; 00292 readBytes(MPU6050_ADDRESS, FIFO_R_W, 12, &data[0]); // read data for averaging 00293 00294 /* Form signed 16-bit integer for each sample in FIFO */ 00295 accel_temp[0] = (int16_t) (((int16_t)data[0] << 8) | data[1] ) ; 00296 accel_temp[1] = (int16_t) (((int16_t)data[2] << 8) | data[3] ) ; 00297 accel_temp[2] = (int16_t) (((int16_t)data[4] << 8) | data[5] ) ; 00298 gyro_temp[0] = (int16_t) (((int16_t)data[6] << 8) | data[7] ) ; 00299 gyro_temp[1] = (int16_t) (((int16_t)data[8] << 8) | data[9] ) ; 00300 gyro_temp[2] = (int16_t) (((int16_t)data[10] << 8) | data[11]) ; 00301 00302 /* Sum individual signed 16-bit biases to get accumulated signed 32-bit biases */ 00303 accel_bias[0] += (int32_t) accel_temp[0]; 00304 accel_bias[1] += (int32_t) accel_temp[1]; 00305 accel_bias[2] += (int32_t) accel_temp[2]; 00306 gyro_bias[0] += (int32_t) gyro_temp[0]; 00307 gyro_bias[1] += (int32_t) gyro_temp[1]; 00308 gyro_bias[2] += (int32_t) gyro_temp[2]; 00309 } 00310 00311 /* Normalize sums to get average count biases */ 00312 accel_bias[0] /= (int32_t) packet_count; 00313 accel_bias[1] /= (int32_t) packet_count; 00314 accel_bias[2] /= (int32_t) packet_count; 00315 gyro_bias[0] /= (int32_t) packet_count; 00316 gyro_bias[1] /= (int32_t) packet_count; 00317 gyro_bias[2] /= (int32_t) packet_count; 00318 00319 /* Remove gravity from the z-axis accelerometer bias calculation */ 00320 if(accel_bias[2] > 0) {accel_bias[2] -= (int32_t) accelsensitivity;} 00321 else {accel_bias[2] += (int32_t) accelsensitivity;} 00322 00323 /* Output scaled accelerometer biases for manual subtraction in the main program */ 00324 dest1[0] = accel_bias[0]*aRes; 00325 dest1[1] = accel_bias[1]*aRes; 00326 dest1[2] = accel_bias[2]*aRes; 00327 00328 /* Construct the gyro biases for push to the hardware gyro bias registers, which are reset to zero upon device startup */ 00329 data[0] = (-gyro_bias[0]/4 >> 8) & 0xFF; // Divide by 4 to get 32.9 LSB per deg/s to conform to expected bias input format 00330 data[1] = (-gyro_bias[0]/4) & 0xFF; // Biases are additive, so change sign on calculated average gyro biases 00331 data[2] = (-gyro_bias[1]/4 >> 8) & 0xFF; 00332 data[3] = (-gyro_bias[1]/4) & 0xFF; 00333 data[4] = (-gyro_bias[2]/4 >> 8) & 0xFF; 00334 data[5] = (-gyro_bias[2]/4) & 0xFF; 00335 00336 /* Push gyro biases to hardware registers */ 00337 writeByte(MPU6050_ADDRESS, XG_OFFS_USRH, data[0]); 00338 writeByte(MPU6050_ADDRESS, XG_OFFS_USRL, data[1]); 00339 writeByte(MPU6050_ADDRESS, YG_OFFS_USRH, data[2]); 00340 writeByte(MPU6050_ADDRESS, YG_OFFS_USRL, data[3]); 00341 writeByte(MPU6050_ADDRESS, ZG_OFFS_USRH, data[4]); 00342 writeByte(MPU6050_ADDRESS, ZG_OFFS_USRL, data[5]); 00343 00344 /* Construct gyro bias in deg/s for later manual subtraction */ 00345 dest2[0] = gyro_bias[0]*gRes; 00346 dest2[1] = gyro_bias[1]*gRes; 00347 dest2[2] = gyro_bias[2]*gRes; 00348 } 00349 00350 void MPU6050::complementaryFilter(float* pitch, float* roll) 00351 { 00352 /* Get actual acc value */ 00353 readAccelData(accelData); 00354 getAres(); 00355 ax = accelData[0]*aRes - accelBias[0]; 00356 ay = accelData[1]*aRes - accelBias[1]; 00357 az = accelData[2]*aRes - accelBias[2]; 00358 00359 /* Get actual gyro value */ 00360 readGyroData(gyroData); 00361 getGres(); 00362 gx = gyroData[0]*gRes; // - gyroBias[0]; // Results are better without extracting gyroBias[i] 00363 gy = gyroData[1]*gRes; // - gyroBias[1]; 00364 gz = gyroData[2]*gRes; // - gyroBias[2]; 00365 00366 float pitchAcc, rollAcc; 00367 00368 /* Integrate the gyro data(deg/s) over time to get angle */ 00369 *pitch += gx * dt; // Angle around the X-axis 00370 *roll -= gy * dt; // Angle around the Y-axis 00371 00372 /* Turning around the X-axis results in a vector on the Y-axis 00373 whereas turning around the Y-axis results in a vector on the X-axis. */ 00374 pitchAcc = atan2f(accelData[1], accelData[2])*180/PI; 00375 rollAcc = atan2f(accelData[0], accelData[2])*180/PI; 00376 00377 /* Apply Complementary Filter */ 00378 *pitch = *pitch * 0.98 + pitchAcc * 0.02; 00379 *roll = *roll * 0.98 + rollAcc * 0.02; 00380 }
Generated on Sat Jul 16 2022 11:48:24 by
1.7.2
