4180 final project

Dependencies:   LSM9DS0 USBDevice mbed

Files at this revision

API Documentation at this revision

Comitter:
jlee887
Date:
Sat Dec 05 18:39:33 2015 +0000
Commit message:
d

Changed in this revision

LSM9DS0.lib Show annotated file Show diff for this revision Revisions of this file
Quaternion/Quaternion.cpp Show annotated file Show diff for this revision Revisions of this file
Quaternion/Quaternion.h Show annotated file Show diff for this revision Revisions of this file
USBDevice.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LSM9DS0.lib	Sat Dec 05 18:39:33 2015 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/aswild/code/LSM9DS0/#5556e6fb99f5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Quaternion/Quaternion.cpp	Sat Dec 05 18:39:33 2015 +0000
@@ -0,0 +1,302 @@
+
+#include "Quaternion.h"
+#include "mbed.h"
+#define M_PI 3.14159265
+
+Timer t;
+/**
+* Default constructor. 
+**/
+Quaternion::Quaternion() {
+    q0 = 1.0f;
+    q1 = 0.0f;
+    q2 = 0.0f;
+    q3 = 0.0f;
+    twoKp = twoKpDef;
+    twoKi = twoKiDef;
+    sampleFreq = 0.0f;
+    lastUpdate = 0L;
+    now = 0L;
+    integralFBx = 0.0f;
+    integralFBy = 0.0f;
+    integralFBz = 0.0f;
+    t.start();
+}
+
+/**
+* Updates the sample frequency based on the elapsed time. 
+**/
+void Quaternion::updateSampleFrequency() {
+    now = t.read();
+    sampleFreq = 1.0 / ((now - lastUpdate));
+    lastUpdate = now;
+}
+/**
+* Returns the quaternion representation of the orientation. 
+**/
+void Quaternion::getQ(float * q) {
+    q[0] = q0;
+    q[1] = q1;
+    q[2] = q2;
+    q[3] = q3;
+}
+
+/**
+* Gets the linear acceleration by estimating gravity and then subtracting it. All accelerations
+* need to be scaled to 1 g. So if at 1 g your accelerometer reads 245, divide it by 245 before passing it 
+* to this function. 
+* @param *linearAccel, pointer to float array for linear accelerations,
+* @param ax, the scaled acceleration in the x direction. 
+* @param ay, the scaled acceleration in the y direction.
+* @param az, the scaled acceleration in the z direction.
+**/
+void Quaternion::getLinearAcceleration(float * linearAccel, float ax, float ay, float az) {
+    
+    float gravity[3];
+    getGravity(gravity);
+    
+
+    
+    float xwog = ax - gravity[0];
+    float ywog = ay - gravity[1];
+    float zwog = az - gravity[2];
+
+    linearAccel[0] = xwog * 9.8;
+    linearAccel[1] =  ywog * 9.8;
+    linearAccel[2] = zwog * 9.8;
+}
+
+/**
+* Returns the euler angles psi, theta and phi. 
+**/
+void Quaternion::getEulerAngles(float * angles) {
+    angles[0] = atan2(2 * q1 * q2- 2 * q0 * q3, 2 * q0*q0 + 2 * q1 * q1 - 1) * 180/M_PI; // psi
+    angles[1] = -asin(2 * q1 * q3 + 2 * q0 * q2) * 180/M_PI; // theta
+    angles[2] = atan2(2 * q2 * q3 - 2 * q0 * q1, 2 * q0 * q0 + 2 * q3 * q3 - 1) * 180/M_PI; // phi
+}
+
+/**
+* Returns the yaw pitch and roll of the device. 
+**/
+void Quaternion::getYawPitchRoll(double * ypr) {
+
+    ypr[0] =  atan2(double(2*q1*q2 + 2*q0*q3), double(q0*q0 + q1*q1 - q2*q2 - q3*q3)) * 180/M_PI; //yaw
+    ypr[1] = -asin(2*q0*q2 - 2*q1*q3)  * 180/M_PI; // pitch
+    ypr[2]  = -atan2(2*q2*q3 + 2*q0*q1, -q0*q0 + q1*q1 + q2*q2 - q3*q3)  * 180/M_PI; //roll
+
+}
+/**
+* Gets an estimation of gravity based on quaternion orientation representation. 
+**/
+void Quaternion::getGravity(float * gravity) {
+    float q[4];
+    getQ(q);
+    gravity[0] = 2 * (q[1] * q[3] - q[0] *q[2]);
+    gravity[1] = 2 * (q[0] * q[1] + q[2] * q[3]);
+    gravity[2] = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
+}
+
+/**
+* Calculates the quaternion representation based on a 6DOF sensor. 
+* @param gx, the rotation about the x axis in rad/sec
+* @param gy, the rotation about the y axis in rad/sec 
+* @param gz, the rotation about the z axis in rad/sec
+* @param ax, the raw acceleration in the x direction.
+* @param ay, the raw acceleration in the y direction.
+* @param az, the raw acceleration in the z direction. 
+**/
+void Quaternion::update6DOF(float gx, float gy, float gz, float ax, float ay, float az) {
+    updateSampleFrequency();
+    float recipNorm;
+    float halfvx, halfvy, halfvz;
+    float halfex, halfey, halfez;
+    float qa, qb, qc;
+
+    // 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 and vector perpendicular to magnetic flux
+        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 / sampleFreq);    // integral error scaled by Ki
+            integralFBy += twoKi * halfey * (1.0f / sampleFreq);
+            integralFBz += twoKi * halfez * (1.0f / sampleFreq);
+            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 / sampleFreq));     // pre-multiply common factors
+    gy *= (0.5f * (1.0f / sampleFreq));
+    gz *= (0.5f * (1.0f / sampleFreq));
+    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;
+    
+}
+
+/**
+* Calculates the quaternion representation based on a 9DOF sensor. 
+* @param gx, the rotation about the x axis in rad/sec
+* @param gy, the rotation about the y axis in rad/sec 
+* @param gz, the rotation about the z axis in rad/sec
+* @param ax, the raw acceleration in the x direction.
+* @param ay, the raw acceleration in the y direction.
+* @param az, the raw acceleration in the z direction. 
+* @param mx, the raw magnometer heading in the x direction. 
+* @param my, the raw magnometer heading in the y direction. 
+* @param mz, the raw magnometer heading in the z direction. 
+**/
+void Quaternion::update9DOF(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) {
+    //update the frequency first. 
+    updateSampleFrequency();
+    float recipNorm;
+    float q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3;  
+    float hx, hy, bx, bz;
+    float halfvx, halfvy, halfvz, halfwx, halfwy, halfwz;
+    float halfex, halfey, halfez;
+    float qa, qb, qc;
+
+    // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation)
+    if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) {
+        update6DOF(gx, gy, gz, ax, ay, az);
+        return;
+    }
+
+    // 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;     
+
+        // Normalise magnetometer measurement
+        recipNorm = invSqrt(mx * mx + my * my + mz * mz);
+        mx *= recipNorm;
+        my *= recipNorm;
+        mz *= recipNorm;   
+
+        // Auxiliary variables to avoid repeated arithmetic
+        q0q0 = q0 * q0;
+        q0q1 = q0 * q1;
+        q0q2 = q0 * q2;
+        q0q3 = q0 * q3;
+        q1q1 = q1 * q1;
+        q1q2 = q1 * q2;
+        q1q3 = q1 * q3;
+        q2q2 = q2 * q2;
+        q2q3 = q2 * q3;
+        q3q3 = q3 * q3;   
+
+        // Reference direction of Earth's magnetic field
+        hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2));
+        hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1));
+        bx = sqrt(hx * hx + hy * hy);
+        bz = 2.0f * (mx * (q1q3 - q0q2) + my * (q2q3 + q0q1) + mz * (0.5f - q1q1 - q2q2));
+
+        // Estimated direction of gravity and magnetic field
+        halfvx = q1q3 - q0q2;
+        halfvy = q0q1 + q2q3;
+        halfvz = q0q0 - 0.5f + q3q3;
+        halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2);
+        halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3);
+        halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2);  
+    
+        // Error is sum of cross product between estimated direction and measured direction of field vectors
+        halfex = (ay * halfvz - az * halfvy) + (my * halfwz - mz * halfwy);
+        halfey = (az * halfvx - ax * halfvz) + (mz * halfwx - mx * halfwz);
+        halfez = (ax * halfvy - ay * halfvx) + (mx * halfwy - my * halfwx);
+
+        // Compute and apply integral feedback if enabled
+        if(twoKi > 0.0f) {
+            integralFBx += twoKi * halfex * (1.0f / sampleFreq);    // integral error scaled by Ki
+            integralFBy += twoKi * halfey * (1.0f / sampleFreq);
+            integralFBz += twoKi * halfez * (1.0f / sampleFreq);
+            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 / sampleFreq));     // pre-multiply common factors
+    gy *= (0.5f * (1.0f / sampleFreq));
+    gz *= (0.5f * (1.0f / sampleFreq));
+    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;
+}
+
+/**
+* Super fast inverted square root. 
+**/ 
+float Quaternion::invSqrt(float x) {
+    float halfx = 0.5f * x;
+    float y = x;
+    long i = *(long*)&y;
+    i = 0x5f3759df - (i>>1);
+    y = *(float*)&i;
+    y = y * (1.5f - (halfx * y * y));
+    return y;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Quaternion/Quaternion.h	Sat Dec 05 18:39:33 2015 +0000
@@ -0,0 +1,32 @@
+#ifndef Quaternion_h
+#define Quaternion_h
+#include "mbed.h"
+
+
+#define twoKpDef    (2.0f * 0.5f)   // 2 * proportional gain
+#define twoKiDef    (2.0f * 0.0f)   // 2 * integral gain
+
+class Quaternion {
+
+    public:
+        Quaternion();
+        void update6DOF(float gx, float gy, float gz, float ax, float ay, float az);
+        void update9DOF(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz);
+        void getQ(float * q);
+        void getEulerAngles(float * angles);
+        void getYawPitchRoll(double * ypr);
+        void getGravity(float * gravity);
+        void getLinearAcceleration(float * linearAccel, float ax, float ay, float az);
+    
+    private:
+        float invSqrt(float x);
+        volatile float q0, q1, q2, q3;
+        volatile float twoKp;   // 2 * proportional gain (Kp)
+        volatile float twoKi;   // 2 * integral gain (Ki)
+        volatile float integralFBx,  integralFBy, integralFBz;
+        unsigned long lastUpdate, now;
+        float sampleFreq;
+        void updateSampleFrequency();
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice.lib	Sat Dec 05 18:39:33 2015 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/jlee887/code/USBDevice/#d29ac157bf32
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Dec 05 18:39:33 2015 +0000
@@ -0,0 +1,125 @@
+#include "mbed.h"
+#include "Quaternion.h"
+#include "LSM9DS0.h"
+#include "USBKeyboard.h"
+
+Serial pc(USBTX, USBRX);
+//IMU
+// SDO_XM and SDO_G are pulled up, so our addresses are:
+#define LSM9DS0_XM_ADDR  0x1D // Would be 0x1E if SDO_XM is LOW
+#define LSM9DS0_G_ADDR   0x6B // Would be 0x6A if SDO_G is LOW
+LSM9DS0 imu(p9, p10, LSM9DS0_G_ADDR, LSM9DS0_XM_ADDR);
+Quaternion q;
+#define M_PI 3.14159265
+
+float accLin[3]; // linear accelerations 
+double ypr[3]; //yaw pitch roll
+
+USBKeyboard keyboard;
+USBKeyboard keyboard2;
+
+DigitalIn left(p15);
+DigitalIn right(p16);
+
+int main() {
+    
+    //IMU
+    uint16_t status = imu.begin();
+    double test;
+    //Make sure communication is working
+    pc.printf("LSM9DS0 WHO_AM_I's returned: 0x%X\n", status);
+    pc.printf("Should be 0x49D4\n\n");
+    float xjump = 9; // threshold for jump
+    float yjump = 1.15; // g threshold
+    float zright = .4; // move right z acc threshold
+    float zleft = -.2; // move left z acc threshold
+    float rollRight = -120; // be less than this to move right
+    float rollLeft = -80; // be greater than this to move left
+
+    q = Quaternion();
+    while(1) {
+    imu.readAccel();
+    imu.readGyro();
+    imu.readMag();
+    //t2.start();
+    //pc.printf("ax= %f, ay = %f, az = %f \n", imu.ax,imu.ay,imu.az);
+    //pc.printf("gx= %f, gy = %f, gz = %f \n", imu.gx,imu.gy,imu.gz);
+    
+    q.update9DOF(imu.gx*M_PI/180, imu.gy*M_PI/180, imu.gz*M_PI/180, imu.ax, imu.ay, imu.az, imu.mx, imu.my, imu.mz);
+    q.getLinearAcceleration(accLin, imu.ax,imu.ay,imu.az);
+    q.getYawPitchRoll(ypr);
+    
+    //pc.printf("xl= %f, yl= %f, zl= %f \n \n",accLin[0],accLin[1],accLin[2]);
+    //pc.printf("y= %f, p= %f, r= %f \n \n",ypr[0],ypr[1],ypr[2]);
+    /*
+    pc.printf("p = %f  ", ypr[1]);
+    pc.printf("r = %f   ",ypr[2]);
+    pc.printf("a = %f   ",accLin[1]);
+    pc. printf("ax = %f   ", accLin[0]);
+    pc.printf("imuax = %f   ", imu.ax);
+    pc.printf("imuay = %f   ", imu.ay);  
+    pc.printf("imuaz = %f \n", imu.az);
+    */
+    pc.printf("%f,%f \n",ypr[2],imu.az);
+    
+    
+    /*
+    
+    if (ypr[2] > rollLeft | left)
+    {
+        keyboard.keyCode(LEFT_ARROW);
+
+        }
+    else if (ypr[2] < rollRight)
+    {
+        keyboard.keyCode(RIGHT_ARROW);
+        }
+    else
+    {
+        keyboard.keyCodeOff(LEFT_ARROW);
+        }
+        */
+        
+    if (imu.az > zright)
+    {keyboard.keyCode(RIGHT_ARROW);}
+    else if (imu.az < zleft)
+    {keyboard.keyCode(LEFT_ARROW);}
+    else
+    {keyboard.keyCodeOff(LEFT_ARROW);}
+    if(imu.ay > yjump)
+    {
+        for(int i =0; i < 100; i++)
+        {keyboard.keyCode(UP_ARROW);}
+        keyboard.keyCodeOff(UP_ARROW);
+        }
+
+    
+    /*
+    if (ypr[2] < rollLeft | left)
+    {
+        keyboard.keyCodeOff(LEFT_ARROW);
+        }
+
+    if (ypr[2] < rollRight | right)
+    {
+        keyboard2.keyCode(RIGHT_ARROW);
+        }
+    if (ypr[2] > rollRight | right)
+    {
+        keyboard2.keyCodeOff(RIGHT_ARROW);
+      
+        } */
+/*
+    if (accLin[1] > yjump)
+    {
+        keyboard.keyCode(UP_ARROW);
+        pc.printf("here3");
+        }
+  */
+    //keyboard.keyCode(RIGHT_ARROW);
+    
+    //wait(1.0);
+
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat Dec 05 18:39:33 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/165afa46840b
\ No newline at end of file