diff options
Diffstat (limited to 'facetracknoir')
-rw-r--r-- | facetracknoir/clientfiles/HAT_100/HAT_100.ino | 389 | ||||
-rw-r--r-- | facetracknoir/clientfiles/HAT_100/README | 35 |
2 files changed, 424 insertions, 0 deletions
diff --git a/facetracknoir/clientfiles/HAT_100/HAT_100.ino b/facetracknoir/clientfiles/HAT_100/HAT_100.ino new file mode 100644 index 00000000..f8644ffe --- /dev/null +++ b/facetracknoir/clientfiles/HAT_100/HAT_100.ino @@ -0,0 +1,389 @@ +// Arduino sketch for MPU6050 on NanoWII using DMP MotionApps v4.1 +// HAT 14/04/2013 by FuraX49 +// +// Head Arduino Tracker for FaceTrackNoIR +// http://facetracknoir.sourceforge.net/home/default.htm +// I2C device class (I2Cdev) +// https://github.com/jrowberg/i2cdevlib + + +#include <avr/eeprom.h> +#include <Wire.h> +#include "I2Cdev.h" +#include "MPU6050_9Axis_MotionApps41.h" + + +MPU6050 mpu; + + +typedef struct { + int16_t Begin ; // 2 Debut + uint16_t Cpt ; // 2 Compteur trame or Code info or error + float gyro[3]; // 12 [Y, P, R] gyro + float acc[3]; // 12 [x, y, z] Acc + int16_t End ; // 2 Fin +} _hatire; + +typedef struct { + int16_t Begin ; // 2 Debut + uint16_t Code ; // 2 Code info + char Msg[24]; // 24 Message + int16_t End ; // 2 Fin +} _msginfo; + +typedef struct +{ + byte rate; + double gyro_offset[3] ; + double acc_offset[3] ; +} _eprom_save; + + +// MPU control/status vars +bool dmpReady = false; // set true if DMP init was successful +bool dmpLoaded = false; // set true if DMP loaded successfuly +uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU +uint8_t devStatus; // return status after each device operation (0 = success, !0 = error) +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 + +char Commande; +char Version[] = "HAT V 1.00"; + +// orientation/motion vars +Quaternion q; // [w, x, y, z] quaternion container +VectorInt16 aa; // [x, y, z] accel sensor measurements +VectorFloat gravity; // [x, y, z] gravity vector + +float Rad2Deg = (180/M_PI) ; + +// trame for message +_hatire hatire; +_msginfo msginfo; +_eprom_save eprom_save; + + +bool AskCalibrate = false; // set true when calibrating is ask +int CptCal = 0; +const int NbCal = 5; + + + + +// ================================================================ +// === INTERRUPT DETECTION ROUTINE === +// ================================================================ +volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high + +void dmpDataReady() { + mpuInterrupt = true; +} + +// ================================================================ +// === PRINT SERIAL FORMATTE === +// ================================================================ +void PrintCodeSerial(uint16_t code,char Msg[24],bool EOL ) { + msginfo.Code=code; + memset(msginfo.Msg,0x00,24); + strcpy(msginfo.Msg,Msg); + if (EOL) msginfo.Msg[23]=0x0A; + // Send HATIRE message to PC + Serial.write((byte*)&msginfo,30); +} + + +// ================================================================ +// === INITIAL SETUP === +// ================================================================ + +void setup() { + // join I2C bus (I2Cdev library doesn't do this automatically) + Wire.begin(); + + // initialize serial communication + while (!Serial); // wait for Leonardo enumeration, others continue immediately + + Serial.begin(115200); + PrintCodeSerial(2000,Version,true); + + hatire.Begin=0xAAAA; + hatire.Cpt=0; + hatire.End=0x5555; + + msginfo.Begin=0xAAAA; + msginfo.Code=0; + msginfo.End=0x5555; + + // initialize device + PrintCodeSerial(3001,"Initializing I2C",true); + mpu.initialize(); + + // verify connection + PrintCodeSerial(3002,"Testing connections",true); + + if (mpu.testConnection()){ + PrintCodeSerial(3003,"MPU6050 connection OK",true); + } else { + PrintCodeSerial(9007,"MPU6050 ERRROR CNX",true); + } + + while (Serial.available() && Serial.read()); // empty buffer + + // load and configure the DMP + PrintCodeSerial(3004,"Initializing DMP...",true); + devStatus = mpu.dmpInitialize(); + + // make sure it worked (returns 0 if so) + if (devStatus == 0) { + dmpLoaded=true; + + // Read Epprom saved params + PrintCodeSerial(3005,"Reading saved params...",true); + ReadParams(); + + // turn on the DMP, now that it's ready + PrintCodeSerial(3006,"Enabling DMP...",true); + mpu.setDMPEnabled(true); + + // enable Arduino interrupt detection + PrintCodeSerial(3007,"Enabling interrupt",true); + attachInterrupt(0, dmpDataReady, RISING); + mpuIntStatus = mpu.getIntStatus(); + + // set our DMP Ready flag so the main loop() function knows it's okay to use it + PrintCodeSerial(5000,"HAT BEGIN",true); + dmpReady = true; + // get expected DMP packet size for later comparison + packetSize = mpu.dmpGetFIFOPacketSize(); + // Empty FIFO + fifoCount = mpu.getFIFOCount(); + while (fifoCount > packetSize) { + fifoCount = mpu.getFIFOCount(); + mpu.getFIFOBytes(fifoBuffer, fifoCount); + } + } + else { + // ERROR! + // 1 = initial memory load failed + // 2 = DMP configuration updates failed + // (if it's going to break, usually the code will be 1) + dmpLoaded=false; + PrintCodeSerial(9000+devStatus,"DMP Initialization failed",true); + } +} + + +// ================================================================ +// === RAZ OFFSET === +// ================================================================ +void razoffset() { + eprom_save.gyro_offset[0] = 0; + eprom_save.gyro_offset[1] = 0; + eprom_save.gyro_offset[2] = 0; + eprom_save.acc_offset[0] = 0; + eprom_save.acc_offset[1] = 0; + eprom_save.acc_offset[2] = 0; +} + + +// ================================================================ +// === SAVE PARAMS === +// ================================================================ +void SaveParams() { + eeprom_write_block((const void*)&eprom_save, (void*) 0, sizeof(eprom_save)); +} + + + +// ================================================================ +// === READ PARAMS === +// ================================================================ +void ReadParams() { + eeprom_read_block( (void*)&eprom_save, (void*) 0, sizeof(eprom_save)); +} + + +// ================================================================ +// === Serial Command === +// ================================================================ +void serialEvent(){ + Commande = (char)Serial.read(); + switch (Commande) { + case 'S': + PrintCodeSerial(5001,"HAT START",true); + if (dmpLoaded==true) { + mpu.resetFIFO(); + hatire.Cpt=0; + attachInterrupt(0, dmpDataReady, RISING); + mpu.setDMPEnabled(true); + dmpReady = true; + } + else { + PrintCodeSerial(9011,"Error DMP not loaded",true); + } + break; + + case 's': + PrintCodeSerial(5002,"HAT STOP",true); + if (dmpReady==true) { + mpu.setDMPEnabled(false); + detachInterrupt(0); + dmpReady = false; + } + break; + + case 'R': + PrintCodeSerial(5003,"HAT RESET",true); + if (dmpLoaded==true) { + mpu.setDMPEnabled(false); + detachInterrupt(0); + mpu.resetFIFO(); + hatire.Cpt=0; + dmpReady = false; + setup(); + } + else { + PrintCodeSerial(9011,"Error DMP not loaded",true); + } + break; + + + case 'C': + CptCal=0; + razoffset(); + AskCalibrate=true; + break; + + case 'V': + PrintCodeSerial(2000,Version,true); + break; + + case 'I': + Serial.println(); + Serial.print("Version : \t"); + Serial.println(Version); + Serial.println("Gyroscopes offsets"); + for (int i=0; i <= 2; i++) { + Serial.print(i); + Serial.print(" : "); + Serial.print(eprom_save.gyro_offset[i]); + Serial.println(); + } + Serial.println("Accelerometers offsets"); + for (int i=0; i <= 2; i++) { + Serial.print(i); + Serial.print(" : "); + Serial.print(eprom_save.acc_offset[i]); + Serial.println(); + } + break; + + + default: + break; + } +} + + +// ================================================================ +// === MAIN PROGRAM LOOP === +// ================================================================ +void loop() { + // Leonardo BUG (simul Serial Event) + if(Serial.available() > 0) serialEvent(); + + + // if programming failed, don't try to do anything + if (dmpReady) { + + + while (!mpuInterrupt && fifoCount < packetSize) ; + + // reset interrupt flag and get INT_STATUS byte + mpuInterrupt = false; + mpuIntStatus = mpu.getIntStatus(); + + // get current FIFO count + fifoCount = mpu.getFIFOCount(); + + // check for overflow (this should never happen unless our code is too inefficient) + if ((mpuIntStatus & 0x10) || fifoCount == 1024) { + // reset so we can continue cleanly + mpu.resetFIFO(); + PrintCodeSerial(9010,"Overflow FIFO DMP",true); + hatire.Cpt=0; + + // otherwise, check for DMP data ready interrupt (this should happen frequently) + } + else if (mpuIntStatus & 0x02) { + // wait for correct available data length, should be a VERY short wait + while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount(); + + // read a packet from FIFO + mpu.getFIFOBytes(fifoBuffer, packetSize); + + // track FIFO count here in case there is > 1 packet available + // (this lets us immediately read more without waiting for an interrupt) + fifoCount -= packetSize; + + // Get Euler angles in degrees + mpu.dmpGetQuaternion(&q, fifoBuffer); + mpu.dmpGetGravity(&gravity, &q); + mpu.dmpGetYawPitchRoll(hatire.gyro, &q, &gravity); + + // Get real acceleration, adjusted to remove gravity + // not used in this script + // mpu.dmpGetAccel(&aa, fifoBuffer); + // mpu.dmpGetLinearAccel(&hatire.acc, &aa, &gravity); + + // Calibration sur X mesures + if (AskCalibrate) { + if ( CptCal>=NbCal) { + CptCal=0; + eprom_save.gyro_offset[0] = eprom_save.gyro_offset[0] / NbCal ; + eprom_save.gyro_offset[1] = eprom_save.gyro_offset[1] / NbCal ; + eprom_save.gyro_offset[2] = eprom_save.gyro_offset[2] / NbCal ; + AskCalibrate=false; + SaveParams(); + } + else { + eprom_save.gyro_offset[0] += (float) hatire.gyro[0]; + eprom_save.gyro_offset[1] += (float) hatire.gyro[1]; + eprom_save.gyro_offset[2] += (float) hatire.gyro[2]; + + CptCal++; + } + } + + + // Conversion angles Euler en +-180 Degr�es + for (int i=0; i <= 2; i++) { + hatire.gyro[i]= (hatire.gyro[i] - eprom_save.gyro_offset[i] ) * Rad2Deg; + if (hatire.gyro[i]>180) { + hatire.gyro[i] = hatire.gyro[i] - 360; + } + } + + if (AskCalibrate) { + hatire.gyro[0] = 0; + hatire.gyro[1] = 0; + hatire.gyro[2] = 0; + hatire.acc[0]= 0; + hatire.acc[1] = 0; + hatire.acc[2] = 0; + } + + // Send Trame to HATIRE PC + Serial.write((byte*)&hatire,30); + + hatire.Cpt++; + if (hatire.Cpt>999) { + hatire.Cpt=0; + } + } + } + delay(1); +} + + diff --git a/facetracknoir/clientfiles/HAT_100/README b/facetracknoir/clientfiles/HAT_100/README new file mode 100644 index 00000000..1e4f2926 --- /dev/null +++ b/facetracknoir/clientfiles/HAT_100/README @@ -0,0 +1,35 @@ + Frame exchange protocol fixed size of 30 bytes like this : + + typedef struct { + int16_t Begin ; // 2 Debut + uint16_t Cpt ; // 2 Compteur trame or Code + float gyro[3]; // 12 [Y, P, R] gyro + float acc[3]; // 12 [x, y, z] Acc + int16_t End ; // 2 Fin +} _hatire; +_hat hat; + + +void setup() { + Serial.begin(115200); + // header frame + hatire.Begin=0xAAAA; + // Frame Number or Error code + hat.Cpt=0; + // footer frame + hat.End=0x5555; +} + + + void loop() { + mpu.dmpGetYawPitchRoll(hatire.gyro); + mpu.dmpAccXYZ(hatire.acc); + // Send Trame to HATIRE PC + Serial.write((byte*)&hatire,30); + hatire.Cpt++; + if (hatire.Cpt>999) { + hatire.Cpt=0; + } + delay(1); +} + |