A class to receive data from the SparkFun 9DOF Razor IMU. It can be easily adapted to work with IMUs with different data formats.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
avbotz
Date:
Fri Nov 04 22:24:02 2011 +0000
Parent:
1:fdfa313b9cc3
Child:
3:f04d3d10d518
Commit message:
Appears to parse data correctly (centered around 512), but sometimes we get bad data.

Changed in this revision

imu.cpp Show annotated file Show diff for this revision Revisions of this file
imu.h 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imu.cpp	Fri Nov 04 22:24:02 2011 +0000
@@ -0,0 +1,174 @@
+#include "mbed.h"
+#include "imu.h"
+
+IMU::IMU(int baud, PinName tx, PinName rx, Serial* pc){
+    p_pc = pc;
+    p_pc->printf("Initializing IMU...\n");
+    p_device = new Serial(tx, rx);
+    p_device->baud(baud);
+    p_device->format(8, Serial::None, 1);
+    readable = false;
+    i_IMU = 0;
+    accX = accY = accZ = gyrX = gyrY = gyrZ = magX = magY = magZ = 0;
+    p_device->putc('6'); //Tell the IMU to start sending binary data, if it isn't already
+}
+
+IMU::~IMU() {
+    if (p_device != NULL){
+        delete p_device;    //This prevents memory leaks and keeps the port accessible for future use.
+    }
+}
+
+//Wrapper function to write a character to the IMU
+void IMU::putc(char c) {
+    p_device->putc(c);
+}
+
+
+//Wrapper function to attach a callback function to the RX interrupt of the IMU Serial object
+void IMU::attach(void (*fptr)(void)) {
+    p_pc->putc('a');
+    p_device->attach(fptr);
+}
+
+//Gets all data from the IMU read buffer. If we should parse, parse.
+void IMU::getData() {
+    readable = false;
+    //p_pc->printf("HELLO");
+    __enable_irq(); 
+    //NVIC_EnableIRQ(UART1_IRQn);
+    while (p_device->readable()) {
+        //p_pc->printf("readable");
+        // This snippet of code should be run whenever a character can be received from the IMU.
+
+        char data = p_device->getc();
+
+        // Start of a new set of data. Reset the counter to the first position in the buffer, and start throwing data in there.
+        if (data == '$') {
+            i_IMU = 0;
+            //p_pc->printf("new data\n\r");
+        }
+        // Something went wrong.
+        else if (i_IMU > 21) {
+            //p_pc->printf("\t\t\tIMU error.\n\r");
+            i_IMU = 21;
+        }
+
+        // End of the set of data. Parse the buffer
+        else if (i_IMU == 21 /*&& bufIMU[0] == '$' && bufIMU[20] == '\n' data == '\n' && i_IMU == 19*/) {
+            parse();
+        }
+
+
+        bufIMU[i_IMU] = data;
+        i_IMU++;
+        //parseNow = (buffer.at(buffer.length() - 1) == '#');
+    }
+}
+
+//So negative numbers that are transferred are in twos complement form
+// and the compiler seems to like to use things created by bitwise operators
+// in unsigned form so all of the bits are switched and we switch it back and center
+// it around 512 which we are using as out zero value
+inline void IMU::makeCorrect(short* i) {
+    if ((*i)>>15) *i = 512-(~(*i));
+    else *i = 512+*i;
+}
+
+/*
+void IMU::attach(void) {
+    p_device->attach(this->readIMU);
+}*/
+
+void IMU::parse() {
+    p_pc->printf("Parsing\n\r");
+
+    //This should be easier to understand than bitshifts. bufIMU is a pointer (arrays are pointers).
+    //We offset it to the start of the desired value. We then typecast bufIMU into a short (16 bit).
+    //This turns bufIMU into a pointer to the desired value. Now we dereference it.
+    //I'm not sure if we'll still need makeCorrect.
+    
+    //Don't use this. It doesn't work. 
+    //Kevin said this didn't work because of endianness. The Cortex M3 has a macro to reverse.
+    //See http://mbed.org/forum/helloworld/topic/1573/?page=1#comment-7818
+    /*accX = *((short*)(bufIMU + 2));
+    accY = *((short*)(bufIMU + 4));
+    accZ = *((short*)(bufIMU + 6));
+
+    gyrX = *((short*)(bufIMU + 8));
+    gyrY = *((short*)(bufIMU + 10));
+    gyrZ = *((short*)(bufIMU + 12));
+
+    magX = *((short*)(bufIMU + 14));
+    magY = *((short*)(bufIMU + 16));
+    magZ = *((short*)(bufIMU + 18));*/
+
+    //bufIMU contains binary data. Each variable sent by the IMU is a 16-bit integer
+    //broken down into two characters (in bufIMU[]). Here, we reconstitute the original integer by
+    //left-shifting the first character by 8 bits and ORing it with the second character.
+    
+    accX = (bufIMU[1]<<8 | bufIMU[2]);
+    accY = (bufIMU[3]<<8 | bufIMU[4]);
+    accZ = (bufIMU[5]<<8 | bufIMU[6]);
+
+    gyrX = (bufIMU[7]<<8 | bufIMU[8]);
+    gyrY = (bufIMU[9]<<8 | bufIMU[10]);
+    gyrZ = (bufIMU[11]<<8 | bufIMU[12]);
+
+    magX = (bufIMU[13]<<8 | bufIMU[14]);
+    magY = (bufIMU[15]<<8 | bufIMU[16]);
+    magZ = (bufIMU[17]<<8 | bufIMU[18]);
+    
+    makeCorrect(&accX);
+    makeCorrect(&accY);
+    makeCorrect(&accZ);
+
+    makeCorrect(&gyrX);
+    makeCorrect(&gyrY);
+    makeCorrect(&gyrZ);
+
+    makeCorrect(&magX);
+    makeCorrect(&magY);
+    makeCorrect(&magZ);
+
+
+    //PC.printf("Data: %d, %d, %d, %d, %d, %d, %d, %d, %d\n\r", accX, accY, accZ, gyrX, gyrY, gyrZ, magX, magY, magZ);
+
+    //accX = accY = accZ = gyrX = gyrY = gyrZ = magX = magY = magZ = 0;
+
+    /*
+    for (int i = 0; i < 21; i++) {
+        PC.printf("%d  ", bufIMU[i]);
+    }
+    PC.printf("\n\r"); 
+    */
+    //newIMUData = 1; // Update the flag
+}
+
+
+//Callback called when there is a character to be read from the IMU
+void readIMU() {
+    imu.readable = true;
+    __disable_irq();
+    //NVIC_DisableIRQ(UART1_IRQn);
+}
+
+int main() {
+    PC.format(8, Serial::None, 1);
+    PC.baud(115200);
+
+    for (int i = 0; i < 80; i++) {
+        PC.putc('-');
+    }
+    PC.printf("\n\r");
+    imu.attach(&readIMU);
+    //imu.p_device->attach(&readIMU);
+    imu.putc('6');
+    while (true){
+        if (imu.readable) {
+            //PC.printf("fun");
+            imu.getData();
+            PC.printf("Data: %d, %d, %d, %d, %d, %d, %d, %d, %d\n\r", imu.accX, imu.accY, imu.accZ, imu.gyrX, imu.gyrY, imu.gyrZ, imu.magX, imu.magY, imu.magZ);
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imu.h	Fri Nov 04 22:24:02 2011 +0000
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "mbed.h"
+
+Serial PC(USBTX, USBRX);
+
+DigitalOut myled1(LED1);
+DigitalOut myled2(LED2);
+DigitalOut myled3(LED3);
+DigitalOut myled4(LED4);
+
+class IMU{
+    public:
+        IMU(int baud, PinName tx, PinName rx, Serial* pc);
+        ~IMU();
+        
+        void getData();
+        void attach(void (*fptr)(void));
+        void putc(char c);
+        //void readIMU();
+        short accX, accY, accZ, gyrX, gyrY, gyrZ, magX, magY, magZ;
+        bool readable;
+        
+    private:
+        Serial* p_device;
+        Serial* p_pc;
+        inline void makeCorrect(short* i);
+        void parse();
+        
+        int i_IMU;
+        char bufIMU[21];
+} imu(57600, p9, p10, &PC);
+
+void readIMU();
--- a/main.cpp	Mon Oct 17 15:19:01 2011 +0000
+++ b/main.cpp	Fri Nov 04 22:24:02 2011 +0000
@@ -1,9 +1,9 @@
 /*
  * Demo to relay I/O between a computer and the IMU. Make sure to connect the GND wire on the IMU to pin 1 (GND) on the mbed so there's a return current
  * Updated to use interrupts - this will help when we intergrate this code into AVNavControl
- * 9dof razor from sparkfun
+ * 9dof razor from sparkfun, http://www.sparkfun.com/products/10736
  */
-
+/*
 #define GYRO_SCALE 14.375  // ticks per degree, http://www.sparkfun.com/datasheets/Sensors/Gyro/PS-ITG-3200-00-01.4.pdf 
 
 #include "mbed.h"
@@ -29,7 +29,10 @@
 int i_IMU;
 char bufIMU[21];
 
+AnalogOut aout(p18);
+
 int main() {
+    aout = 1.0;
     // Set up the connection. Read up about parity and stop bits if this is confusing.
     IMU.format(8, Serial::None, 1);
     PC.format(8, Serial::None, 1);
@@ -69,23 +72,41 @@
                 }
 
                 // End of the set of data. Parse the buffer
-                else if (i_IMU == 21 /*&& bufIMU[0] == '$' && bufIMU[20] == '\n' data == '\n' && i_IMU == 19*/) {
+                else if (i_IMU == 21) { && bufIMU[0] == '$' && bufIMU[20] == '\n' data == '\n' && i_IMU == 19) {
                     printf("Parsing\n\r");
                     
+                    //This should be easier to understand than bitshifts. bufIMU is a pointer (arrays are pointers).
+                    //We offset it to the start of the desired value. We then typecast bufIMU into a short (16 bit).
+                    //This turns bufIMU into a pointer to the desired value. Now we dereference it.
+                    //I'm not sure if we'll still need makeCorrect. Adit, check plz <3
+                    accX = *((short*)(bufIMU + 1));
+                    accY = *((short*)(bufIMU + 3));
+                    accZ = *((short*)(bufIMU + 5));
+                    
+                    gyrX = *((short*)(bufIMU + 7));
+                    gyrY = *((short*)(bufIMU + 9));
+                    gyrZ = *((short*)(bufIMU + 11));
+                    
+                    magX = *((short*)(bufIMU + 13));
+                    magY = *((short*)(bufIMU + 15));
+                    magZ = *((short*)(bufIMU + 17));
+                    
                     //bufIMU contains binary data. Each variable sent by the IMU is a 16-bit integer
                     //broken down into two characters (in bufIMU[]). Here, we reconstitute the original integer by
                     //left-shifting the first character by 8 bits and ORing it with the second character.
-                    accX = (bufIMU[1]<<8 | bufIMU[2]);
-                    accY = (bufIMU[3]<<8 | bufIMU[4]);
-                    accZ = (bufIMU[5]<<8 | bufIMU[6]);
+                    
+                    
+                    //accX = (bufIMU[1]<<8 | bufIMU[2]);
+                    //accY = (bufIMU[3]<<8 | bufIMU[4]);
+                    //accZ = (bufIMU[5]<<8 | bufIMU[6]);
 
-                    gyrX = (bufIMU[7]<<8 | bufIMU[8]);
-                    gyrY = (bufIMU[9]<<8 | bufIMU[10]);
-                    gyrZ = (bufIMU[11]<<8 | bufIMU[12]);
+                    //gyrX = (bufIMU[7]<<8 | bufIMU[8]);
+                    //gyrY = (bufIMU[9]<<8 | bufIMU[10]);
+                    //gyrZ = (bufIMU[11]<<8 | bufIMU[12]);
 
-                    magX = (bufIMU[13]<<8 | bufIMU[14]);
-                    magY = (bufIMU[15]<<8 | bufIMU[16]);
-                    magZ = (bufIMU[17]<<8 | bufIMU[18]);
+                    //magX = (bufIMU[13]<<8 | bufIMU[14]);
+                    //magY = (bufIMU[15]<<8 | bufIMU[16]);
+                    //magZ = (bufIMU[17]<<8 | bufIMU[18]);
                     
                     makeCorrect(&accX);
                     makeCorrect(&accY);
@@ -104,12 +125,12 @@
 
                     //accX = accY = accZ = gyrX = gyrY = gyrZ = magX = magY = magZ = 0;
 
-                    /*
-                    for (int i = 0; i < 21; i++) {
-                        PC.printf("%d  ", bufIMU[i]);
-                    }
-                    PC.printf("\n\r");
-                    */
+                    
+                    //for (int i = 0; i < 21; i++) {
+                    //    PC.printf("%d  ", bufIMU[i]);
+                    //}
+                    //PC.printf("\n\r");
+                    
                     //newIMUData = 1; // Update the flag
                 }
 
@@ -127,11 +148,11 @@
             PCreadable = false;
             myled1 = 0;
         }
-        /*if (parseNow) {
-            parse(buffer);
-            buffer.clear();
-            parseNow = false;
-        }*/
+        //if (parseNow) {
+        //    parse(buffer);
+        //    buffer.clear();
+        //    parseNow = false;
+        //}
     }
 }
 
@@ -150,10 +171,12 @@
 }
 
 
-//The bitshift performed always creates a positive integer. Sometimes, the IMU
-//values are negative. This fixes that - it centers the value around 512. That is,
-//512 is 0 for the IMU variables. Values above it are positive, and values below it are negative.
+//So negative numbers that are transferred are in twos complement form
+// and the compiler seems to like to use things created by bitwise operators
+// in unsigned form so all of the bits are switched and we switch it back and center
+// it around 512 which we are using as out zero value
 inline void makeCorrect (short* i) {
     if ((*i)>>15) *i = 512 - (~(*i));
     else *i = 512 + *i;
-}
\ No newline at end of file
+}
+*/
\ No newline at end of file