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.
DMP.cpp
00001 //Copied MPU6050.h and MPU6050.cpp from another library (otherwise MPU gets stuck randomly) 00002 00003 /*** THIS IS THE BEST VERSION OF DMP CODE 00004 This code demonstrates how to access the MPU6050 IMU and fix the 00005 connection errors that occur, using a hardware hack. 00006 It requires two hardware fixes: A transistor (PTE5) and an extra GPIO pin (PTE23) connected 00007 to the SDA line. 00008 Error 1: The SDA line gets stuck on ground. 00009 Solution 1: Use the transistor to raise the SDA voltage off of ground. This resets the I2C bus. (line 71) 00010 Error 2: The SDA line gets stuck on 3.3V 00011 Solution 2: Use the GPIO line to pull the SDA voltage down a bit to reset the I2C bus. (line 96) 00012 (I am currently trying to find a software solution for the above hack) 00013 00014 This code works for using the DMP. (See "DMP" for implementation that can do raw accel data) 00015 It appears all connection issues have been fixed. 00016 Next step: make code neater (in progress) 00017 00018 LEARNED: Do not need the PTE23 line. Only fix necessary is the transistor (PTE5) 00019 ***/ 00020 00021 #include "mbed.h" 00022 #include "DMP.h" 00023 00024 00025 //******* MPU DECLARATION THINGS *****************// 00026 int dmp_test = 1; //if this is 0, get raw MPU values 00027 //if this is 1, get DMP values 00028 00029 int acc_offset[3]; //this saves the offset for acceleration 00030 00031 int16_t ax, ay, az; 00032 int16_t gx, gy, gz; 00033 00034 //******* DMP things ****************// 00035 // MPU control/status vars 00036 bool dmpReady = false; // set true if DMP init was succesfful 00037 uint8_t mpuIntStatus; // holds interrupt status byte from MPU 00038 uint8_t devStatus; // return status after each device operation (0 = success) 00039 uint16_t packetSize; // expected DMP packet size (default is 42 bytes) 00040 uint16_t fifoCount; // count of all bytes currently in FIFO 00041 uint8_t fifoBuffer[64]; // FIFO storage buffer 00042 bool dmpReady2 = false; // set true if DMP init was succesfful 00043 uint8_t mpuIntStatus2; // holds interrupt status byte from MPU 00044 uint8_t devStatus2; // return status after each device operation (0 = success) 00045 uint16_t packetSize2; // expected DMP packet size (default is 42 bytes) 00046 uint16_t fifoCount2; // count of all bytes currently in FIFO 00047 uint8_t fifoBuffer2[64]; // FIFO storage buffer 00048 00049 00050 00051 uint8_t MPU_CONNECTION; 00052 00053 // orientation/motion vars 00054 Quaternion q; // [w,x,y,z] quaternion container 00055 Quaternion q2; // [w,x,y,z] quaternion container 00056 VectorInt16 aa; // [x,y,z] accel sensor measurements 00057 VectorInt16 aaReal; // [x,y,z] gravity-free accel sensor measurements 00058 VectorInt16 aaWorld; // [x,y,z] world-frame accel sensor measurements 00059 VectorFloat gravity; // [x,y,z] gravity vector 00060 VectorFloat gravity2; // [x,y,z] gravity vector 00061 00062 float euler[3]; // [psi,theta,phi] Euler angle container 00063 float ypr[3]; // [yaw,pitch,roll] yaw/pitch/roll container [rad]. Multiply by 180, divide by PI for [deg] 00064 float ypr2[3]; 00065 InterruptIn checkpin(PTD7); //interrupt 00066 InterruptIn checkpin2(PTD5); //PTD5 00067 //*** Interrupt Detection Routine ***// 00068 volatile bool mpuInterrupt = false; //indicates whether interrupt pin has gone high 00069 void dmpDataReady(){ 00070 mpuInterrupt = true; 00071 } 00072 volatile bool mpuInterrupt2 = false; //indicates whether interrupt pin has gone high 00073 void dmpDataReady2(){ 00074 mpuInterrupt2 = true; 00075 } 00076 00077 //****** END MPU DECLARATION ********************// 00078 00079 00080 int test_dmp(); //this wraps up the code req'd to start the DMP 00081 void start_dmp(MPU6050); //this will get the DMP ready 00082 void update_dmp(); //call this frequently 00083 00084 //*********************FUNCTIONS***************************************************************// 00085 int test_dmp(){ //returns 1 if ok (right now, it doesn't return at all if there is a problem 00086 imuSwitch = 1; 00087 LED_OFF; 00088 Thread::wait(100); 00089 00090 while(mpu.testConnection()==0) 00091 { 00092 imuSwitch = 0; 00093 Thread::wait(100); 00094 imuSwitch = 1; 00095 Thread::wait(100); 00096 bt.lock(); 00097 bt.printf("Stuck on IMU1"); 00098 bt.unlock(); 00099 } 00100 imuSwitch = 1; 00101 LED_ON //turn ON LED 00102 return 1; 00103 } 00104 int test_dmp2(){ //returns 1 if ok (right now, it doesn't return at all if there is a problem 00105 imu2Switch = 1; 00106 LED_OFF; 00107 Thread::wait(100); 00108 00109 while(mpu2.testConnection()==0) 00110 { 00111 imu2Switch = 0; 00112 Thread::wait(100); 00113 imu2Switch = 1; 00114 Thread::wait(100); 00115 bt.lock(); 00116 bt.printf("Stuck on IMU2"); 00117 bt.unlock(); 00118 } 00119 imu2Switch = 1; 00120 LED_ON //turn ON LED 00121 return 1; 00122 } 00123 00124 void start_dmp(MPU6050 mpu1){ //this will get the DMP ready 00125 //initialize device 00126 mpu1.reset(); 00127 DMP_DBG_MSG("\n\rInitializing I2C devices...") 00128 devStatus = mpu1.dmpInitialize(); 00129 //insert gyro offsets here// Write a calibration algorithm in the future 00130 mpu1.setXGyroOffset(0); //800/25=32 //-31 is the largest offset available 00131 mpu1.setYGyroOffset(0); 00132 mpu1.setZGyroOffset(0); 00133 mpu1.setXAccelOffset(0); //the accel offsets don't do anything 00134 mpu1.setYAccelOffset(0); 00135 mpu1.setZAccelOffset(0); 00136 00137 mpu1.setFullScaleGyroRange(MPU6050_GYRO_FS_2000); 00138 00139 if(devStatus == 0){ //this means initialize was successful 00140 //turn on DMP 00141 DMP_DBG_MSG("\n\rEnabling DMP") 00142 mpu1.setDMPEnabled(true); 00143 00144 // enable interrupt detection 00145 DMP_DBG_MSG("Enabling interrupt detection (Arduino external interrupt 0)...\r\n") 00146 checkpin.rise(&dmpDataReady); 00147 00148 mpuIntStatus = mpu1.getIntStatus(); 00149 00150 //set the DMP ready flag so main loop knows when it is ok to use 00151 DMP_DBG_MSG("DMP ready! Waiting for first interrupt") 00152 dmpReady = true; 00153 00154 //get expected DMP packet size 00155 packetSize = mpu1.dmpGetFIFOPacketSize(); 00156 }else{ 00157 DMP_DBG_MSG("\n\rDMP Initialization failed") 00158 DMP_DBG_MSG("\t%d",devStatus) 00159 Thread::wait(1000); 00160 } 00161 acc_offset[0]=0; 00162 acc_offset[1]=0; 00163 acc_offset[2]=0; 00164 mpu.setDLPFMode(MPU6050_DLPF_BW_42); 00165 } 00166 void start_dmp2(MPU6051 mpu1){ //this will get the DMP ready 00167 //initialize device 00168 mpu2.reset(); 00169 DMP_DBG_MSG("\n\rInitializing I2C devices...") 00170 devStatus2 = mpu2.dmpInitialize(); 00171 //insert gyro offsets here// Write a calibration algorithm in the future 00172 mpu2.setXGyroOffset(0); //800/25=32 //-31 is the largest offset available 00173 mpu2.setYGyroOffset(0); 00174 mpu2.setZGyroOffset(0); 00175 mpu2.setXAccelOffset(0); //the accel offsets don't do anything 00176 mpu2.setYAccelOffset(0); 00177 mpu2.setZAccelOffset(0); 00178 00179 mpu2.setFullScaleGyroRange(MPU6050_GYRO_FS_2000); 00180 00181 if(devStatus2 == 0){ //this means initialize was successful 00182 //turn on DMP 00183 DMP_DBG_MSG("\n\rEnabling DMP") 00184 mpu2.setDMPEnabled(true); 00185 00186 // enable interrupt detection 00187 DMP_DBG_MSG("Enabling interrupt detection (Arduino external interrupt 0)...\r\n") 00188 checkpin2.rise(&dmpDataReady2); 00189 00190 mpuIntStatus2 = mpu2.getIntStatus(); 00191 00192 //set the DMP ready flag so main loop knows when it is ok to use 00193 DMP_DBG_MSG("DMP ready! Waiting for first interrupt") 00194 dmpReady2 = true; 00195 00196 //get expected DMP packet size 00197 packetSize2 = mpu2.dmpGetFIFOPacketSize(); 00198 }else{ 00199 DMP_DBG_MSG("\n\rDMP Initialization failed") 00200 DMP_DBG_MSG("\t%d",devStatus2) 00201 Thread::wait(1000); 00202 } 00203 acc_offset[0]=0; 00204 acc_offset[1]=0; 00205 acc_offset[2]=0; 00206 mpu2.setDLPFMode(MPU6050_DLPF_BW_42); 00207 } 00208 00209 void update_dmp(){ 00210 if (!dmpReady) return; 00211 while (!mpuInterrupt && fifoCount < packetSize) { 00212 // other program behavior stuff here 00213 // if you are really paranoid you can frequently test in between other 00214 // stuff to see if mpuInterrupt is true, and if so, "break;" from the 00215 // while() loop to immediately process the MPU data 00216 // . 00217 } 00218 // reset interrupt flag and get INT_STATUS byte 00219 mpuInterrupt = false; //this resets the interrupt flag 00220 mpuIntStatus = mpu.getIntStatus(); 00221 00222 //get current FIFO count; 00223 fifoCount = mpu.getFIFOCount(); 00224 00225 //check for overflow (only happens if your code sucks) 00226 if((mpuIntStatus & 0x10) || fifoCount == 1024){ 00227 //reset so we can continue cleanly 00228 mpu.resetFIFO(); 00229 DMP_DBG_MSG("\n\rFIFO overflow") 00230 } else if (mpuIntStatus & 0x02){ 00231 int16_t x,y,z; 00232 //wait for correct available data length (should be very short) 00233 while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount(); 00234 00235 //read a packet from FIFO 00236 mpu.getFIFOBytes(fifoBuffer, packetSize); 00237 00238 //track FIFO count here in the case there is > 1 packet available 00239 //(allows us to immediately read more w/o waiting for interrupt) 00240 fifoCount -= packetSize; 00241 00242 mpu.dmpGetQuaternion(&q,fifoBuffer); 00243 imu_data.quat[0]=q.w; 00244 imu_data.quat[1]=q.x; 00245 imu_data.quat[2]=q.y; 00246 imu_data.quat[3]=q.z; 00247 mpu.dmpGetGravity(&gravity, &q); 00248 mpu.dmpGetYawPitchRoll(ypr,&q,&gravity); 00249 imu_data.ypr[0] = ypr[0]*180/M_PI;//MARK - this saves the yaw data so everyone can access it 00250 imu_data.ypr[1] = ypr[1]*180/M_PI; 00251 imu_data.ypr[2] = ypr[2]*180/M_PI; 00252 00253 mpu.getAcceleration(&x,&y,&z); 00254 imu_data.acc[0] = (x-acc_offset[0]) *9.81/16384; 00255 imu_data.acc[1] = (y-acc_offset[1]) *9.81/16384; 00256 imu_data.acc[2] = (z-acc_offset[2]) *9.81/16384; 00257 #ifdef PRINT_GYR 00258 DMP_DBG_MSG("\n\rypr\t %f\t %f\t %f",ypr[0]*180/PI,ypr[1]*180/PI,ypr[2]*180/PI) 00259 #endif 00260 00261 mpu.dmpGetAccel(&aa, fifoBuffer); 00262 mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity); 00263 #ifdef PRINT_ACC 00264 DMP_DBG_MSG("\n\rareal\t%d\t%d\t%d",aaReal.x,aaReal.y,aaReal.z) 00265 #endif 00266 //get rotations 00267 mpu.getMotion6(&x,&y,&z,&gx,&gy,&gz); 00268 float scale = 250/16384; 00269 imu_data.gyr[0] = gx*scale; 00270 imu_data.gyr[1] = gy*scale; 00271 imu_data.gyr[2] = gz*scale; 00272 00273 } 00274 } 00275 void update_dmp2(){ 00276 if (!dmpReady2) return; 00277 while (!mpuInterrupt2 && fifoCount2 < packetSize2) { 00278 // other program behavior stuff here 00279 // if you are really paranoid you can frequently test in between other 00280 // stuff to see if mpuInterrupt is true, and if so, "break;" from the 00281 // while() loop to immediately process the MPU data 00282 // . 00283 } 00284 // reset interrupt flag and get INT_STATUS byte 00285 mpuInterrupt2 = false; //this resets the interrupt flag 00286 mpuIntStatus2 = mpu2.getIntStatus(); 00287 00288 //get current FIFO count; 00289 fifoCount2 = mpu2.getFIFOCount(); 00290 00291 //check for overflow (only happens if your code sucks) 00292 if((mpuIntStatus2 & 0x10) || fifoCount2 == 1024){ 00293 //reset so we can continue cleanly 00294 mpu2.resetFIFO(); 00295 DMP_DBG_MSG("\n\rFIFO overflow") 00296 } else if (mpuIntStatus2 & 0x02){ 00297 int16_t x,y,z; 00298 //wait for correct available data length (should be very short) 00299 while (fifoCount2 < packetSize2) fifoCount2 = mpu2.getFIFOCount(); 00300 00301 //read a packet from FIFO 00302 mpu2.getFIFOBytes(fifoBuffer2, packetSize2); 00303 00304 //track FIFO count here in the case there is > 1 packet available 00305 //(allows us to immediately read more w/o waiting for interrupt) 00306 fifoCount2 -= packetSize2; 00307 00308 mpu2.dmpGetQuaternion(&q2,fifoBuffer2); 00309 imu2_data.quat[0]=q2.w; 00310 imu2_data.quat[1]=q2.x; 00311 imu2_data.quat[2]=q2.y; 00312 imu2_data.quat[3]=q2.z; 00313 mpu2.dmpGetGravity(&gravity2, &q2); 00314 mpu2.dmpGetYawPitchRoll(ypr2,&q2,&gravity2); 00315 imu2_data.ypr[0] = ypr2[0]*180/M_PI;//MARK - this saves the yaw data so everyone can access it 00316 imu2_data.ypr[1] = ypr2[1]*180/M_PI; 00317 imu2_data.ypr[2] = ypr2[2]*180/M_PI; 00318 00319 mpu2.getAcceleration(&x,&y,&z); 00320 imu2_data.acc[0] = (x-acc_offset[0]) *9.81/16384; 00321 imu2_data.acc[1] = (y-acc_offset[1]) *9.81/16384; 00322 imu2_data.acc[2] = (z-acc_offset[2]) *9.81/16384; 00323 #ifdef PRINT_GYR 00324 DMP_DBG_MSG("\n\rypr\t %f\t %f\t %f",ypr2[0]*180/PI,ypr2[1]*180/PI,ypr2[2]*180/PI) 00325 #endif 00326 00327 mpu2.dmpGetAccel(&aa, fifoBuffer2); 00328 mpu2.dmpGetLinearAccel(&aaReal, &aa, &gravity2); 00329 #ifdef PRINT_ACC 00330 DMP_DBG_MSG("\n\rareal\t%d\t%d\t%d",aaReal.x,aaReal.y,aaReal.z) 00331 #endif 00332 //get rotations 00333 mpu2.getMotion6(&x,&y,&z,&gx,&gy,&gz); 00334 float scale = 250/16384; 00335 imu2_data.gyr[0] = gx*scale; 00336 imu2_data.gyr[1] = gy*scale; 00337 imu2_data.gyr[2] = gz*scale; 00338 00339 } 00340 } 00341 void update_acc() 00342 { 00343 int16_t x,y,z; 00344 mpu.getAcceleration(&x,&y,&z); 00345 imu_data.acc[0] = (x-acc_offset[0]) *9.81/16384; 00346 imu_data.acc[1] = (y-acc_offset[1]) *9.81/16384; 00347 imu_data.acc[2] = (z-acc_offset[2]) *9.81/16384; 00348 } 00349 void calibrate_1() //call this to calibrate the accelerometer 00350 { //in the future, modify the OFFSET REGISTERS to make the DMP converge faster 00351 //right now, I am only calculating the offset for the accelerometers 00352 int sum[3] = {0,0,0}; 00353 int i; 00354 int16_t x,y,z; 00355 00356 int count=0; 00357 int t_now = t.read_ms(); 00358 while((t.read_ms()-t_now) < 1000) //loop for one second 00359 { 00360 mpu.getAcceleration(&x,&y,&z); 00361 sum[0] += x; 00362 sum[1] += y; 00363 sum[2] += z; 00364 Thread::wait(5); 00365 count++; 00366 } 00367 for(i = 0; i<3; i++) 00368 acc_offset[i] = (sum[i]/count); 00369 //bt.printf("ACC_OFF:%d;%d;%d;",acc_offset[0],acc_offset[1],acc_offset[2]);//print the offset used by accelerometer 00370 }
Generated on Tue Jul 12 2022 21:27:00 by
