asdfsaf
Dependencies: MPU6050-DMP-Ian mbed-rtos mbed
Diff: DMP.cpp
- Revision:
- 0:dceb852b19f3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DMP.cpp Tue May 27 09:23:23 2014 +0000 @@ -0,0 +1,205 @@ +//Copied MPU6050.h and MPU6050.cpp from another library (otherwise MPU gets stuck randomly) + +/*** THIS IS THE BEST VERSION OF DMP CODE + This code demonstrates how to access the MPU6050 IMU and fix the + connection errors that occur, using a hardware hack. + It requires two hardware fixes: A transistor (PTE5) and an extra GPIO pin (PTE23) connected + to the SDA line. + Error 1: The SDA line gets stuck on ground. + Solution 1: Use the transistor to raise the SDA voltage off of ground. This resets the I2C bus. (line 71) + Error 2: The SDA line gets stuck on 3.3V + Solution 2: Use the GPIO line to pull the SDA voltage down a bit to reset the I2C bus. (line 96) + (I am currently trying to find a software solution for the above hack) + + This code works for using the DMP. (See "DMP" for implementation that can do raw accel data) + It appears all connection issues have been fixed. + Next step: make code neater (in progress) + + LEARNED: Do not need the PTE23 line. Only fix necessary is the transistor (PTE5) +***/ + +#include "mbed.h" +#include "I2Cdev.h" +#include "MPU6050_6Axis_MotionApps20.h" +#include "robot.h" + + +//******* MPU DECLARATION THINGS *****************// +int dmp_test =1; //if this is 0, get raw MPU values + //if this is 1, get DMP values + +int16_t ax, ay, az; +int16_t gx, gy, gz; + +//******* DMP things ****************// +// MPU control/status vars +bool dmpReady = false; // set true if DMP init was succesfful +uint8_t mpuIntStatus; // holds interrupt status byte from MPU +uint8_t devStatus; // return status after each device operation (0 = success) +uint16_t packetSize; // expected DMP packet size (default is 42 bytes) +uint16_t fifoCount; // count of all bytes currently in FIFO +uint8_t fifoBuffer[64]; // FIFO storage buffer + + +uint8_t MPU_CONNECTION; + +// orientation/motion vars +Quaternion q; // [w,x,y,z] quaternion container +VectorInt16 aa; // [x,y,z] accel sensor measurements +VectorInt16 aaReal; // [x,y,z] gravity-free accel sensor measurements +VectorInt16 aaWorld; // [x,y,z] world-frame accel sensor measurements +VectorFloat gravity; // [x,y,z] gravity vector +float euler[3]; // [psi,theta,phi] Euler angle container +float ypr[3]; // [yaw,pitch,roll] yaw/pitch/roll container [rad]. Multiply by 180, divide by PI for [deg] +InterruptIn checkpin(PTD7); //interrupt +//*** Interrupt Detection Routine ***// +volatile bool mpuInterrupt = false; //indicates whether interrupt pin has gone high +void dmpDataReady(){ + mpuInterrupt = true; +} + +//****** END MPU DECLARATION ********************// + + +int test_dmp(); //this wraps up the code req'd to start the DMP +void start_dmp(MPU6050 mpu); //this will get the DMP ready +void update_dmp(MPU6050 mpu); //call this frequently + +//*********************FUNCTIONS***************************************************************// +int test_dmp(){ //returns 1 if ok (right now, it doesn't return at all if there is a problem + /// This function tests the I2C port for the MPU6050 and resets it if it is not working + //NOTE: when the I2C connection is not successful, calling initialize() will cause the board to freeze + DigitalOut reset_pin(PTE5); //Transistor to pull up SDA line + reset_pin = 0; //start the transistor in OFF mode + //int count = 0; + DigitalIn sample_1(PTE0); //(this pin will be used as the SDA pin when an MPU6050 object is declared + int temp = sample_1; //Sample what is happening on the SDA line to guess what the solution is. + myled = 1; //turn OFF LED. This will turn on again when the MPU is connected. + //bt.baud(baudRate); + DigitalOut reset_1(PTE0);//change the SDA pin to output. + reset_1 = 0; + if(temp == 1){ //if SDA line starts high, unstick by pulling it low + bt.printf("\n\rSetting up I2C connection..."); + reset_1 = 0; //SDA pin = low + wait_ms(100); + MPU6050 *mpu2 = new MPU6050; //create a temporary MPU connection for testing + mpu2->reset(); + //bt.baud(baudRate); + while(mpu2->testConnection() == 0){ + delete mpu2; //delete mpu2 so I can use PTE0 as a GPIO again + bt.baud(baudRate); //you must reset baud rate whenever a new MPU6050 is declared + DigitalOut sda_pinx(PTE0); + sda_pinx = 0; //set this to 0 to pull the SDA line down from 3.3V + reset_pin = 0; //make sure transistor = OFF + bt.printf("\n\rRetry"); + wait_ms(50); + MPU6050 *mpu2 = new MPU6050; + wait_ms(500); + if(mpu2->testConnection() == 0) + { + reset_pin = 1; + wait_ms(50); + reset_pin = 0; + } + } + delete mpu2; //free the memory allocated to mpu2 (this is important) + }else{ + bt.printf("\n\rSetting up I2C connection..."); + reset_1 = 1; + reset_pin = 1; + wait_ms(20); + reset_pin = 0; + reset_1 = 0; + wait_ms(20); + } + reset_pin = 0; + DigitalIn not_used(PTE23); + myled = 0; //turn ON LED + return 1; +} + + +void start_dmp(MPU6050 mpu1){ //this will get the DMP ready + //initialize device + mpu1.reset(); + bt.printf("\n\rInitializing I2C devices..."); + devStatus = mpu1.dmpInitialize(); + //insert gyro offsets here// Write a calibration algorithm in the future + mpu1.setXGyroOffset(-31); //800/25=32 //-31 is the largest offset available + mpu1.setYGyroOffset(-183/25); + mpu1.setZGyroOffset(80/25); + mpu1.setXAccelOffset(0); //the accel offsets don't do anything + mpu1.setYAccelOffset(0); + mpu1.setZAccelOffset(0); + + + if(devStatus == 0){ //this means initialize was successful + //turn on DMP + bt.printf("\n\rEnabling DMP"); + mpu1.setDMPEnabled(true); + + // enable interrupt detection + bt.printf("Enabling interrupt detection (Arduino external interrupt 0)...\r\n"); + checkpin.rise(&dmpDataReady); + + mpuIntStatus = mpu1.getIntStatus(); + + //set the DMP ready flag so main loop knows when it is ok to use + bt.printf("DMP ready! Waiting for first interrupt"); + dmpReady = true; + + //get expected DMP packet size + packetSize = mpu1.dmpGetFIFOPacketSize(); + }else{ + bt.printf("\n\rDMP Initialization failed"); + bt.printf("\t%d",devStatus); + wait_ms(1000); + } +} +void update_dmp(MPU6050 mpu1){ + + if (!dmpReady) return; + //while (!mpuInterrupt && fifoCount < packetSize) { + // other program behavior stuff here + // if you are really paranoid you can frequently test in between other + // stuff to see if mpuInterrupt is true, and if so, "break;" from the + // while() loop to immediately process the MPU data + // . + //} + // reset interrupt flag and get INT_STATUS byte + //mpuInterrupt = false; //this resets the interrupt flag + mpuIntStatus = mpu1.getIntStatus(); + + //get current FIFO count; + fifoCount = mpu1.getFIFOCount(); + + //check for overflow (only happens if your code sucks) + if((mpuIntStatus & 0x10) || fifoCount == 1024){ + //reset so we can continue cleanly + mpu1.resetFIFO(); + bt.printf("\n\rFIFO overflow"); + } else if (mpuIntStatus & 0x02){ + //wait for correct available data length (should be very short) + while (fifoCount < packetSize) fifoCount = mpu1.getFIFOCount(); + + //read a packet from FIFO + mpu1.getFIFOBytes(fifoBuffer, packetSize); + + //track FIFO count here in the case there is > 1 packet available + //(allows us to immediately read more w/o waiting for interrupt) + fifoCount -= packetSize; + + mpu1.dmpGetQuaternion(&q,fifoBuffer); + mpu1.dmpGetGravity(&gravity, &q); + mpu1.dmpGetYawPitchRoll(ypr,&q,&gravity); + #ifdef PRINT_GYR + bt.printf("\n\rypr\t %f\t %f\t %f",ypr[0]*180/PI,ypr[1]*180/PI,ypr[2]*180/PI); + #endif + + mpu1.dmpGetAccel(&aa, fifoBuffer); + mpu1.dmpGetLinearAccel(&aaReal, &aa, &gravity); + #ifdef PRINT_ACC + bt.printf("\n\rareal\t%d\t%d\t%d",aaReal.x,aaReal.y,aaReal.z); + #endif + } +} \ No newline at end of file