MPU6050 FreeIMU library

Dependents:   FreeIMU FreeIMU_external_magnetometer

Fork of MPU6050_tmp by Aloïs Wolff

Async MPU6050 library

My port of the MPU6050 library samples the chip at 500Hz using Timer. Async I2C is achieved using a custom I2C library, which supports I2C calls from interrupts. Link given below:

Import libraryMODI2C

Improvements to Olieman's MODI2C library. Supports calls from IRQ.

Difference between this port and the Arduino MPU6050 library

The getMotion6 function only returns a copy of the last obtained readings, which is sampled at a frequency of 500Hz (adjustable). Hence it can be called at any frequency without taxing the I2C.

Files at this revision

API Documentation at this revision

Comitter:
pommzorz
Date:
Sat Jun 22 11:23:45 2013 +0000
Parent:
5:bdb6ad020352
Child:
7:95e74f827c08
Commit message:
Commit;

Changed in this revision

GurvIMU.cpp Show annotated file Show diff for this revision Revisions of this file
GurvIMU.h Show annotated file Show diff for this revision Revisions of this file
MPU6050.cpp Show annotated file Show diff for this revision Revisions of this file
MPU6050.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GurvIMU.cpp	Sat Jun 22 11:23:45 2013 +0000
@@ -0,0 +1,187 @@
+#include "GurvIMU.h"
+#include "MPU6050.h"
+#include "mbed.h"
+
+#define  M_PI 3.1415926535897932384626433832795
+
+#define twoKpDef    (2.0f * 2.0f)   // 2 * proportional gain
+#define twoKiDef    (2.0f * 0.5f)   // 2 * integral gain
+
+
+GurvIMU::GurvIMU()
+{
+    //MPU
+    mpu = MPU6050(0x69); //0x69 = MPU6050 I2C ADDRESS
+
+    // Variable definitions
+    q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f;  // quaternion of sensor frame relative to auxiliary frame
+    twoKp = twoKpDef;                                            // 2 * proportional gain (Kp)
+    twoKi = twoKiDef;                                            // 2 * integral gain (Ki)
+    integralFBx = 0.0f,  integralFBy = 0.0f, integralFBz = 0.0f; // integral error terms scaled by Ki
+    cycle_nb = 0;
+    timer_us.start();    
+}
+
+//Function definitions
+
+void GurvIMU::getValues(float * values)
+{
+    int16_t accgyroval[6];
+    mpu.getMotion6(&accgyroval[0], &accgyroval[1], &accgyroval[2], &accgyroval[3], &accgyroval[4], &accgyroval[5]);
+    for(int i = 0; i<3; i++) values[i] = (float) accgyroval[i];
+    for(int i = 3; i<6; i++) values[i] = (accgyroval[i]-offset[i]) * (M_PI / 180) / 16.4f;
+}
+
+void GurvIMU::getVerticalAcceleration(float av)
+{
+    float values[6];
+    float q[4]; // quaternion
+    float g_x, g_y, g_z; // estimated gravity direction
+    getQ(q);
+  
+    g_x = 2 * (q[1]*q[3] - q[0]*q[2]);
+    g_y = 2 * (q[0]*q[1] + q[2]*q[3]);
+    g_z = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];   
+    
+    getValues(values);
+    av = g_x*values[0]+g_y*values[1]+g_z*values[2]-offset[2];
+}
+     
+
+void GurvIMU::getOffset(void)
+{
+    int sample_nb = 50;
+    float values[6];
+    for(int i=0; i<6 ; i++) offset[i] = 0;
+    for(int i=0; i<sample_nb; i++) {
+        getValues(values);
+        for(int j=0; j<6; j++) offset[j]+=values[j];        
+    }     
+    for(int j=0; j<6; j++) offset[j]/=sample_nb;
+}
+
+
+void GurvIMU::AHRS_update(float gx, float gy, float gz, float ax, float ay, float az)
+{
+    float recipNorm;
+    float halfvx, halfvy, halfvz;
+    float halfex, halfey, halfez;
+    float qa, qb, qc;
+    
+    dt_us=timer_us.read_us();
+    sample_freq = 1.0 / ((dt_us) / 1000000.0);
+    timer_us.reset();
+    
+    // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
+    if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
+
+        // Normalise accelerometer measurement
+        recipNorm = invSqrt(ax * ax + ay * ay + az * az);
+        ax *= recipNorm;
+        ay *= recipNorm;
+        az *= recipNorm;        
+
+        // Estimated direction of gravity
+        halfvx = q1 * q3 - q0 * q2;
+        halfvy = q0 * q1 + q2 * q3;
+        halfvz = q0 * q0 - 0.5f + q3 * q3;
+    
+        // Error is sum of cross product between estimated and measured direction of gravity
+        halfex = (ay * halfvz - az * halfvy);
+        halfey = (az * halfvx - ax * halfvz);
+        halfez = (ax * halfvy - ay * halfvx);
+
+        // Compute and apply integral feedback if enabled
+        if(twoKi > 0.0f) {
+            integralFBx += twoKi * halfex * (1.0f / sample_freq);    // integral error scaled by Ki
+            integralFBy += twoKi * halfey * (1.0f / sample_freq);
+            integralFBz += twoKi * halfez * (1.0f / sample_freq);
+            gx += integralFBx;  // apply integral feedback
+            gy += integralFBy;
+            gz += integralFBz;
+        }
+        else {
+            integralFBx = 0.0f; // prevent integral windup
+            integralFBy = 0.0f;
+            integralFBz = 0.0f;
+        }
+
+        // Apply proportional feedback
+        gx += twoKp * halfex;
+        gy += twoKp * halfey;
+        gz += twoKp * halfez;
+    }
+    
+    // Integrate rate of change of quaternion
+    gx *= (0.5f * (1.0f / sample_freq));     // pre-multiply common factors
+    gy *= (0.5f * (1.0f / sample_freq));
+    gz *= (0.5f * (1.0f / sample_freq));
+    qa = q0;
+    qb = q1;
+    qc = q2;
+    q0 += (-qb * gx - qc * gy - q3 * gz);
+    q1 += (qa * gx + qc * gz - q3 * gy);
+    q2 += (qa * gy - qb * gz + q3 * gx);
+    q3 += (qa * gz + qb * gy - qc * gx); 
+    
+    // Normalise quaternion
+    recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
+    q0 *= recipNorm;
+    q1 *= recipNorm;
+    q2 *= recipNorm;
+    q3 *= recipNorm;
+}
+
+void GurvIMU::getQ(float * q) {
+  float val[6];
+  getValues(val);
+  //while(cycle_nb < 1000){
+    AHRS_update(val[3], val[4], val[5], val[0], val[1], val[2]);
+  //cycle_nb++;}
+
+  q[0] = q0;
+  q[1] = q1;
+  q[2] = q2;
+  q[3] = q3;
+  
+}
+
+void GurvIMU::getYawPitchRollRad(float * ypr) {
+  float q[4]; // quaternion
+  float g_x, g_y, g_z; // estimated gravity direction
+  getQ(q);
+  
+  g_x = 2 * (q[1]*q[3] - q[0]*q[2]);
+  g_y = 2 * (q[0]*q[1] + q[2]*q[3]);
+  g_z = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];
+  
+  ypr[0] = atan2(2 * q[1] * q[2] - 2 * q[0] * q[3], 2 * q[0]*q[0] + 2 * q[1] * q[1] - 1);
+  ypr[1] = atan(g_x * invSqrt(g_y*g_y + g_z*g_z));
+  ypr[2] = atan(g_y * invSqrt(g_x*g_x + g_z*g_z));
+}
+
+void GurvIMU::init()
+{
+    mpu.initialize();
+    mpu.setI2CMasterModeEnabled(0);
+    mpu.setI2CBypassEnabled(1);
+    mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_2000);
+    getOffset();
+    wait(0.005);
+}
+
+
+float invSqrt(float number)
+{
+    volatile long i;
+    volatile float x, y;
+    volatile const float f = 1.5F;
+
+    x = number * 0.5F;
+    y = number;
+    i = * ( long * ) &y;
+    i = 0x5f375a86 - ( i >> 1 );
+    y = * ( float * ) &i;
+    y = y * ( f - ( x * y * y ) );
+    return y;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GurvIMU.h	Sat Jun 22 11:23:45 2013 +0000
@@ -0,0 +1,40 @@
+#ifndef _GURVIMU_H_
+#define _GURVIMU_H_
+
+#include "mbed.h"
+#include "MPU6050.h"
+
+class GurvIMU {
+    private:
+        //Variables
+        MPU6050 mpu;
+        float twoKp;            // 2 * proportional gain (Kp)
+        float twoKi;            // 2 * integral gain (Ki)
+        float integralFBx, integralFBy, integralFBz; // integral error terms scaled by Ki
+        float q0, q1, q2, q3;   // quaternion of sensor frame relative to auxiliary frame
+        float ax, ay, az, gx, gy, gz;
+        float sample_freq;
+        float offset[6];
+        Timer timer_us;
+        float dt_us;
+        float cycle_nb;
+        
+        
+        //Functions
+        void getOffset();
+        void getValues(float * values);
+        void AHRS_update(float gx, float gy, float gz, float ax, float ay, float az);
+        void getQ(float * q);
+
+    public:
+        GurvIMU();
+        void init();
+        void getYawPitchRollRad(float * ypr);
+        void getVerticalAcceleration(float * av);
+        
+};
+
+//Fast Inverse Square Root
+float invSqrt(float number);
+
+#endif /* _GURVIMU_H_ */
\ No newline at end of file
--- a/MPU6050.cpp	Wed Feb 20 18:29:30 2013 +0000
+++ b/MPU6050.cpp	Sat Jun 22 11:23:45 2013 +0000
@@ -80,8 +80,6 @@
 
     debugSerial.baud(921600); //uses max serial speed
 #ifdef useDebugSerial
-
-    debugSerial.baud(921600);
     debugSerial.printf("MPU6050::initialize start\n");
 #endif
     setClockSource(MPU6050_CLOCK_PLL_XGYRO);
@@ -172,6 +170,7 @@
     i2Cdev.writeByte(devAddr, MPU6050_RA_SMPLRT_DIV, rate);
 }
 
+
 // CONFIG register
 
 /** Get external FSYNC configuration.
--- a/MPU6050.h	Wed Feb 20 18:29:30 2013 +0000
+++ b/MPU6050.h	Sat Jun 22 11:23:45 2013 +0000
@@ -420,6 +420,7 @@
         // SMPLRT_DIV register
         uint8_t getRate();
         void setRate(uint8_t rate);
+        
 
         // CONFIG register
         uint8_t getExternalFrameSync();