trackdish.ino
· 11 KiB · Arduino
Ham
#include <EEPROM.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
#include <avr/wdt.h>
// Amount of readings used to average, make it higher to get more precision
// but sketch will be slower (default:1000)
#define CALIB_BUFFER_SIZE 1000
// Acelerometer error allowed, make it lower to get more precision,
// but sketch may not converge (default:8)
#define CALIB_ACCEL_DEADZONE 8
// Giro error allowed, make it lower to get
// more precision, but sketch may not converge (default:1)
#define CALIB_GYRO_DEADZONE 1
#define INTERRUPT_PIN 2
#define LED_PIN 13
#define CURRENT_VERSION "v1.0.0"
#define CONFIG_VERSION 0
#define SERIAL_TIMEOUT 100
#define DMP_WARMUP_TIME 10000
#define STATE_IDLE 0
#define STATE_CALIBRATION 1
#define STATE_SET_MOTORS 2
#define STATE_STOP_MOTORS 3
#define VER_MTR_PWR_PIN 4
#define HOR_MTR_PWR_PIN 5
#define VER_MTR_DIR_PIN 6
#define HOR_MTR_DIR_PIN 7
#define MTR_CTRL_VERPWRBIT 1
#define MTR_CTRL_HORPWRBIT 2
#define MTR_CTRL_VERDIRBIT 4
#define MTR_CTRL_HORDIRBIT 8
#define CMD_CALIBRATE 'c'
#define CMD_STOP_MOTOR 's'
#define CMD_SET_MOTOR 'w'
const char magicWord[5] = "DISH";
const char currVersion[11] = CURRENT_VERSION;
struct Config {
char magic[4];
char version[10];
char configVersion;
char firstSetup;
int16_t gyroOffsetX;
int16_t gyroOffsetY;
int16_t gyroOffsetZ;
int16_t accelOffsetX;
int16_t accelOffsetY;
int16_t accelOffsetZ;
};
MPU6050 mpu;
float ypr[3];
int mpuStatus;
int dmpStatus;
int dmpPacketSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
float temperature;
Config trackConfig;
Quaternion q;
VectorFloat gravity;
long lastSerialTime;
bool readingSerial;
#define resetDevice() wdt_enable(WDTO_30MS); while(1) {}
void measureSensorsMean();
void saveConfig();
/*
* MPU Interrupt
*/
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
/*
* Calibration
*/
int16_t ax, ay, az,gx, gy, gz;
int meanAccelX,meanAccelY,meanAccelZ,meanGyroX,meanGyroY,meanGyroZ,state=0;
int accelOffsetX,accelOffsetY,accelOffsetZ,gyroOffsetX,gyroOffsetY,gyroOffsetZ;
void calibrate() {
Serial.println("|0|Reseting offsets.;");
mpu.setXGyroOffset(0);
mpu.setYGyroOffset(0);
mpu.setZGyroOffset(0);
mpu.setXAccelOffset(0);
mpu.setYAccelOffset(0);
mpu.setZAccelOffset(0);
Serial.println("|0|Reading sensor means.;");
measureSensorsMean();
Serial.println("|0|Calculating offsets.;");
calculateOffsets();
Serial.println("|0|New offsets calculated.;");
trackConfig.gyroOffsetX = gyroOffsetX;
trackConfig.gyroOffsetY = gyroOffsetY;
trackConfig.gyroOffsetZ = gyroOffsetZ;
trackConfig.accelOffsetX = accelOffsetX;
trackConfig.accelOffsetY = accelOffsetY;
trackConfig.accelOffsetZ = accelOffsetZ;
trackConfig.firstSetup = false;
Serial.println("|0|Saving configurations.;");
saveConfig();
Serial.println("|0|Resetting device.;");
delay(100);
resetDevice();
}
void calculateOffsets() {
accelOffsetX=-meanAccelX/8;
accelOffsetY=-meanAccelY/8;
accelOffsetZ=(16384-meanAccelZ)/8;
gyroOffsetX=-meanGyroX/4;
gyroOffsetY=-meanGyroY/4;
gyroOffsetZ=-meanGyroZ/4;
while (1) { // TODO: Limit iterations
int ready=0;
mpu.setXAccelOffset(accelOffsetX);
mpu.setYAccelOffset(accelOffsetY);
mpu.setZAccelOffset(accelOffsetZ);
mpu.setXGyroOffset(gyroOffsetX);
mpu.setYGyroOffset(gyroOffsetY);
mpu.setZGyroOffset(gyroOffsetZ);
measureSensorsMean();
if (abs(meanAccelX)<=CALIB_ACCEL_DEADZONE) {
ready++;
} else {
accelOffsetX=accelOffsetX-meanAccelX/CALIB_ACCEL_DEADZONE;
}
if (abs(meanAccelY)<=CALIB_ACCEL_DEADZONE) {
ready++;
} else {
accelOffsetY=accelOffsetY-meanAccelY/CALIB_ACCEL_DEADZONE;
}
if (abs(16384-meanAccelZ)<=CALIB_ACCEL_DEADZONE) {
ready++;
} else {
accelOffsetZ=accelOffsetZ+(16384-meanAccelZ)/CALIB_ACCEL_DEADZONE;
}
if (abs(meanGyroX)<=CALIB_GYRO_DEADZONE) {
ready++;
} else {
gyroOffsetX=gyroOffsetX-meanGyroX/(CALIB_GYRO_DEADZONE+1);
}
if (abs(meanGyroY)<=CALIB_GYRO_DEADZONE) {
ready++;
} else {
gyroOffsetY=gyroOffsetY-meanGyroY/(CALIB_GYRO_DEADZONE+1);
}
if (abs(meanGyroZ)<=CALIB_GYRO_DEADZONE) {
ready++;
} else {
gyroOffsetZ=gyroOffsetZ-meanGyroZ/(CALIB_GYRO_DEADZONE+1);
}
if (ready==6) break;
}
}
void measureSensorsMean() {
long i=0,buff_ax=0,buff_ay=0,buff_az=0,buff_gx=0,buff_gy=0,buff_gz=0;
while (i<(CALIB_BUFFER_SIZE+101)){
// read raw accel/gyro measurements from device
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
if (i>100 && i<=(CALIB_BUFFER_SIZE+100)){ //First 100 measures are discarded
buff_ax=buff_ax+ax;
buff_ay=buff_ay+ay;
buff_az=buff_az+az;
buff_gx=buff_gx+gx;
buff_gy=buff_gy+gy;
buff_gz=buff_gz+gz;
}
if (i==(CALIB_BUFFER_SIZE+100)){
meanAccelX=buff_ax/CALIB_BUFFER_SIZE;
meanAccelY=buff_ay/CALIB_BUFFER_SIZE;
meanAccelZ=buff_az/CALIB_BUFFER_SIZE;
meanGyroX=buff_gx/CALIB_BUFFER_SIZE;
meanGyroY=buff_gy/CALIB_BUFFER_SIZE;
meanGyroZ=buff_gz/CALIB_BUFFER_SIZE;
}
i++;
delay(2); //Needed so we don't get repeated measures
}
}
/*
* EEPROM Manipulation
*/
void clearEEPROM() {
for (int index = 0 ; index < EEPROM.length() ; index++) {
EEPROM[index] = 0;
}
}
void saveConfig() {
EEPROM.put(0, trackConfig);
}
void loadConfig() {
EEPROM.get(0, trackConfig);
bool magicOk = true;
for (int i=0; i<4; i++) {
if (magicWord[i] != trackConfig.magic[i]) {
magicOk = false;
}
}
if (!magicOk) {
Serial.println("|0|First setup. Cleaning EEPROM.;");
clearEEPROM();
for (int i=0; i<4; i++) {
trackConfig.magic[i] = magicWord[i];
}
for (int i=0; i<10; i++) {
trackConfig.version[i] = currVersion[i];
}
trackConfig.configVersion = CONFIG_VERSION;
trackConfig.gyroOffsetX = 0;
trackConfig.gyroOffsetY = 0;
trackConfig.gyroOffsetZ = 0;
trackConfig.accelOffsetX = 0;
trackConfig.accelOffsetY = 0;
trackConfig.accelOffsetZ = 0;
trackConfig.firstSetup = true;
saveConfig();
}
}
/*
* Main Code
*/
void setup() {
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
MCUSR = 0;
Serial.begin(115200);
Serial.println("|0|Initializing devices.;");
mpu.initialize();
Serial.print("|1|MPUStatus|");
Serial.print(mpu.testConnection());
Serial.println(";");
Serial.println("|0|Initializing DMP.;");
dmpStatus = mpu.dmpInitialize();
Serial.println("|0|Loading configuration.;");
loadConfig();
if (dmpStatus == 0) {
dmpStatus = 1;
Serial.println("|0|DMP Initialized.;");
} else {
dmpStatus = 0;
Serial.println("|0|Failed to initialize DMP.;");
}
if (trackConfig.firstSetup) {
Serial.println("|1|CALIBRATION|Requires Calibration;");
} else {
Serial.println("|0|Loading Accel / Gyro Calibration;");
mpu.setXGyroOffset(trackConfig.gyroOffsetX);
mpu.setYGyroOffset(trackConfig.gyroOffsetY);
mpu.setZGyroOffset(trackConfig.gyroOffsetZ);
mpu.setXAccelOffset(trackConfig.accelOffsetX);
mpu.setYAccelOffset(trackConfig.accelOffsetY);
mpu.setZAccelOffset(trackConfig.accelOffsetZ);
mpu.setDMPEnabled(true);
attachInterrupt(0, dmpDataReady, RISING);
dmpPacketSize = mpu.dmpGetFIFOPacketSize();
Serial.println("|0|Waiting for DMP warmup.;");
lastSerialTime = millis();
while (lastSerialTime + DMP_WARMUP_TIME > millis()); // Wait for warmpup
Serial.println("|0|DMP Ready.;");
}
lastSerialTime = 0;
readingSerial = false;
}
int currentState = STATE_IDLE;
void machineStateProcess() {
char d;
switch (currentState) {
case STATE_IDLE: // Do Nothing
break;
case STATE_CALIBRATION:
Serial.println("|0|Entering Calibration State. This can take some time;");
calibrate();
currentState = STATE_IDLE;
break;
case STATE_SET_MOTORS:
d = Serial.read();
Serial.print("|0|Setting motors to ");
Serial.print(d & MTR_CTRL_VERDIRBIT > 0 ? "UP " : "DOWN ");
Serial.print(d & MTR_CTRL_VERPWRBIT > 0 ? "ON " : "OFF ");
Serial.print(d & MTR_CTRL_HORDIRBIT > 0 ? "LEFT " : "RIGHT ");
Serial.println(d & MTR_CTRL_HORPWRBIT > 0 ? "ON;" : "OFF;");
digitalWrite(VER_MTR_DIR_PIN, d & MTR_CTRL_VERDIRBIT);
digitalWrite(HOR_MTR_DIR_PIN, d & MTR_CTRL_HORDIRBIT);
digitalWrite(VER_MTR_PWR_PIN, d & MTR_CTRL_VERPWRBIT);
digitalWrite(HOR_MTR_PWR_PIN, d & MTR_CTRL_HORPWRBIT);
currentState = STATE_IDLE;
break;
case STATE_STOP_MOTORS:
Serial.println("|0|Stopping Motors.;");
digitalWrite(VER_MTR_PWR_PIN, LOW);
digitalWrite(HOR_MTR_PWR_PIN, LOW);
currentState = STATE_IDLE;
break;
}
}
void loop() {
// Process MPU
if (dmpStatus) {
if (mpuInterrupt || fifoCount >= dmpPacketSize) {
mpuInterrupt = false;
mpuStatus = mpu.getIntStatus();
if ((mpuStatus & 0x10) || fifoCount == 1024) {
mpu.resetFIFO();
Serial.println("|0|MPU FIFO Overflow!;");
} else if (mpuStatus & 0x02) {
while (fifoCount < dmpPacketSize) {
fifoCount = mpu.getFIFOCount();
}
mpu.getFIFOBytes(fifoBuffer, dmpPacketSize);
fifoCount -= dmpPacketSize;
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
temperature = mpu.getTemperature() /340.00 + 36.53;
Serial.print("|2|");
Serial.print(ypr[0] * 180/M_PI);
Serial.print("|");
Serial.print(ypr[1] * 180/M_PI);
Serial.print("|");
Serial.print(ypr[2] * 180/M_PI);
Serial.println(";");
Serial.print("|3|");
Serial.print(temperature);
Serial.println(";");
}
}
}
// Process Serial Data
if (Serial.available() > 0) {
char cmd = Serial.read();
switch (cmd) {
case CMD_CALIBRATE: currentState = STATE_CALIBRATION; break;
case CMD_STOP_MOTOR: currentState = STATE_STOP_MOTORS; break;
case CMD_SET_MOTOR: currentState = STATE_SET_MOTORS; break;
default:
Serial.print("|0|Unknown command ");
Serial.print(cmd);
Serial.println(";");
}
} else if (lastSerialTime + SERIAL_TIMEOUT < millis() && readingSerial) {
// Timeout
Serial.println("|0|Serial Command Timeout;");
readingSerial = false;
}
machineStateProcess();
}
#define CMD_CALIBRATE 'c'
#define CMD_STOP_MOTOR 's'
#define CMD_SET_MOTOR 'w'
| 1 | #include <EEPROM.h> |
| 2 | #include "I2Cdev.h" |
| 3 | #include "MPU6050_6Axis_MotionApps20.h" |
| 4 | #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE |
| 5 | #include "Wire.h" |
| 6 | #endif |
| 7 | #include <avr/wdt.h> |
| 8 | |
| 9 | // Amount of readings used to average, make it higher to get more precision |
| 10 | // but sketch will be slower (default:1000) |
| 11 | #define CALIB_BUFFER_SIZE 1000 |
| 12 | // Acelerometer error allowed, make it lower to get more precision, |
| 13 | // but sketch may not converge (default:8) |
| 14 | #define CALIB_ACCEL_DEADZONE 8 |
| 15 | // Giro error allowed, make it lower to get |
| 16 | // more precision, but sketch may not converge (default:1) |
| 17 | #define CALIB_GYRO_DEADZONE 1 |
| 18 | |
| 19 | #define INTERRUPT_PIN 2 |
| 20 | #define LED_PIN 13 |
| 21 | #define CURRENT_VERSION "v1.0.0" |
| 22 | #define CONFIG_VERSION 0 |
| 23 | #define SERIAL_TIMEOUT 100 |
| 24 | #define DMP_WARMUP_TIME 10000 |
| 25 | |
| 26 | #define STATE_IDLE 0 |
| 27 | #define STATE_CALIBRATION 1 |
| 28 | #define STATE_SET_MOTORS 2 |
| 29 | #define STATE_STOP_MOTORS 3 |
| 30 | |
| 31 | #define VER_MTR_PWR_PIN 4 |
| 32 | #define HOR_MTR_PWR_PIN 5 |
| 33 | #define VER_MTR_DIR_PIN 6 |
| 34 | #define HOR_MTR_DIR_PIN 7 |
| 35 | |
| 36 | #define MTR_CTRL_VERPWRBIT 1 |
| 37 | #define MTR_CTRL_HORPWRBIT 2 |
| 38 | #define MTR_CTRL_VERDIRBIT 4 |
| 39 | #define MTR_CTRL_HORDIRBIT 8 |
| 40 | |
| 41 | #define CMD_CALIBRATE 'c' |
| 42 | #define CMD_STOP_MOTOR 's' |
| 43 | #define CMD_SET_MOTOR 'w' |
| 44 | |
| 45 | const char magicWord[5] = "DISH"; |
| 46 | const char currVersion[11] = CURRENT_VERSION; |
| 47 | |
| 48 | struct Config { |
| 49 | char magic[4]; |
| 50 | char version[10]; |
| 51 | char configVersion; |
| 52 | char firstSetup; |
| 53 | int16_t gyroOffsetX; |
| 54 | int16_t gyroOffsetY; |
| 55 | int16_t gyroOffsetZ; |
| 56 | int16_t accelOffsetX; |
| 57 | int16_t accelOffsetY; |
| 58 | int16_t accelOffsetZ; |
| 59 | }; |
| 60 | |
| 61 | |
| 62 | MPU6050 mpu; |
| 63 | float ypr[3]; |
| 64 | int mpuStatus; |
| 65 | int dmpStatus; |
| 66 | int dmpPacketSize; |
| 67 | uint16_t fifoCount; |
| 68 | uint8_t fifoBuffer[64]; |
| 69 | float temperature; |
| 70 | Config trackConfig; |
| 71 | Quaternion q; |
| 72 | VectorFloat gravity; |
| 73 | |
| 74 | long lastSerialTime; |
| 75 | bool readingSerial; |
| 76 | |
| 77 | #define resetDevice() wdt_enable(WDTO_30MS); while(1) {} |
| 78 | |
| 79 | void measureSensorsMean(); |
| 80 | void saveConfig(); |
| 81 | |
| 82 | /* |
| 83 | * MPU Interrupt |
| 84 | */ |
| 85 | |
| 86 | volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high |
| 87 | void dmpDataReady() { |
| 88 | mpuInterrupt = true; |
| 89 | } |
| 90 | |
| 91 | /* |
| 92 | * Calibration |
| 93 | */ |
| 94 | |
| 95 | int16_t ax, ay, az,gx, gy, gz; |
| 96 | |
| 97 | int meanAccelX,meanAccelY,meanAccelZ,meanGyroX,meanGyroY,meanGyroZ,state=0; |
| 98 | int accelOffsetX,accelOffsetY,accelOffsetZ,gyroOffsetX,gyroOffsetY,gyroOffsetZ; |
| 99 | |
| 100 | void calibrate() { |
| 101 | Serial.println("|0|Reseting offsets.;"); |
| 102 | mpu.setXGyroOffset(0); |
| 103 | mpu.setYGyroOffset(0); |
| 104 | mpu.setZGyroOffset(0); |
| 105 | mpu.setXAccelOffset(0); |
| 106 | mpu.setYAccelOffset(0); |
| 107 | mpu.setZAccelOffset(0); |
| 108 | |
| 109 | Serial.println("|0|Reading sensor means.;"); |
| 110 | measureSensorsMean(); |
| 111 | |
| 112 | Serial.println("|0|Calculating offsets.;"); |
| 113 | calculateOffsets(); |
| 114 | |
| 115 | Serial.println("|0|New offsets calculated.;"); |
| 116 | trackConfig.gyroOffsetX = gyroOffsetX; |
| 117 | trackConfig.gyroOffsetY = gyroOffsetY; |
| 118 | trackConfig.gyroOffsetZ = gyroOffsetZ; |
| 119 | |
| 120 | trackConfig.accelOffsetX = accelOffsetX; |
| 121 | trackConfig.accelOffsetY = accelOffsetY; |
| 122 | trackConfig.accelOffsetZ = accelOffsetZ; |
| 123 | |
| 124 | trackConfig.firstSetup = false; |
| 125 | |
| 126 | Serial.println("|0|Saving configurations.;"); |
| 127 | saveConfig(); |
| 128 | Serial.println("|0|Resetting device.;"); |
| 129 | delay(100); |
| 130 | resetDevice(); |
| 131 | } |
| 132 | |
| 133 | void calculateOffsets() { |
| 134 | accelOffsetX=-meanAccelX/8; |
| 135 | accelOffsetY=-meanAccelY/8; |
| 136 | accelOffsetZ=(16384-meanAccelZ)/8; |
| 137 | |
| 138 | gyroOffsetX=-meanGyroX/4; |
| 139 | gyroOffsetY=-meanGyroY/4; |
| 140 | gyroOffsetZ=-meanGyroZ/4; |
| 141 | |
| 142 | while (1) { // TODO: Limit iterations |
| 143 | int ready=0; |
| 144 | mpu.setXAccelOffset(accelOffsetX); |
| 145 | mpu.setYAccelOffset(accelOffsetY); |
| 146 | mpu.setZAccelOffset(accelOffsetZ); |
| 147 | |
| 148 | mpu.setXGyroOffset(gyroOffsetX); |
| 149 | mpu.setYGyroOffset(gyroOffsetY); |
| 150 | mpu.setZGyroOffset(gyroOffsetZ); |
| 151 | |
| 152 | measureSensorsMean(); |
| 153 | |
| 154 | if (abs(meanAccelX)<=CALIB_ACCEL_DEADZONE) { |
| 155 | ready++; |
| 156 | } else { |
| 157 | accelOffsetX=accelOffsetX-meanAccelX/CALIB_ACCEL_DEADZONE; |
| 158 | } |
| 159 | |
| 160 | if (abs(meanAccelY)<=CALIB_ACCEL_DEADZONE) { |
| 161 | ready++; |
| 162 | } else { |
| 163 | accelOffsetY=accelOffsetY-meanAccelY/CALIB_ACCEL_DEADZONE; |
| 164 | } |
| 165 | |
| 166 | if (abs(16384-meanAccelZ)<=CALIB_ACCEL_DEADZONE) { |
| 167 | ready++; |
| 168 | } else { |
| 169 | accelOffsetZ=accelOffsetZ+(16384-meanAccelZ)/CALIB_ACCEL_DEADZONE; |
| 170 | } |
| 171 | |
| 172 | if (abs(meanGyroX)<=CALIB_GYRO_DEADZONE) { |
| 173 | ready++; |
| 174 | } else { |
| 175 | gyroOffsetX=gyroOffsetX-meanGyroX/(CALIB_GYRO_DEADZONE+1); |
| 176 | } |
| 177 | |
| 178 | if (abs(meanGyroY)<=CALIB_GYRO_DEADZONE) { |
| 179 | ready++; |
| 180 | } else { |
| 181 | gyroOffsetY=gyroOffsetY-meanGyroY/(CALIB_GYRO_DEADZONE+1); |
| 182 | } |
| 183 | |
| 184 | if (abs(meanGyroZ)<=CALIB_GYRO_DEADZONE) { |
| 185 | ready++; |
| 186 | } else { |
| 187 | gyroOffsetZ=gyroOffsetZ-meanGyroZ/(CALIB_GYRO_DEADZONE+1); |
| 188 | } |
| 189 | |
| 190 | if (ready==6) break; |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | void measureSensorsMean() { |
| 195 | long i=0,buff_ax=0,buff_ay=0,buff_az=0,buff_gx=0,buff_gy=0,buff_gz=0; |
| 196 | |
| 197 | while (i<(CALIB_BUFFER_SIZE+101)){ |
| 198 | // read raw accel/gyro measurements from device |
| 199 | mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); |
| 200 | |
| 201 | if (i>100 && i<=(CALIB_BUFFER_SIZE+100)){ //First 100 measures are discarded |
| 202 | buff_ax=buff_ax+ax; |
| 203 | buff_ay=buff_ay+ay; |
| 204 | buff_az=buff_az+az; |
| 205 | buff_gx=buff_gx+gx; |
| 206 | buff_gy=buff_gy+gy; |
| 207 | buff_gz=buff_gz+gz; |
| 208 | } |
| 209 | if (i==(CALIB_BUFFER_SIZE+100)){ |
| 210 | meanAccelX=buff_ax/CALIB_BUFFER_SIZE; |
| 211 | meanAccelY=buff_ay/CALIB_BUFFER_SIZE; |
| 212 | meanAccelZ=buff_az/CALIB_BUFFER_SIZE; |
| 213 | meanGyroX=buff_gx/CALIB_BUFFER_SIZE; |
| 214 | meanGyroY=buff_gy/CALIB_BUFFER_SIZE; |
| 215 | meanGyroZ=buff_gz/CALIB_BUFFER_SIZE; |
| 216 | } |
| 217 | i++; |
| 218 | delay(2); //Needed so we don't get repeated measures |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | |
| 223 | /* |
| 224 | * EEPROM Manipulation |
| 225 | */ |
| 226 | |
| 227 | void clearEEPROM() { |
| 228 | for (int index = 0 ; index < EEPROM.length() ; index++) { |
| 229 | EEPROM[index] = 0; |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | void saveConfig() { |
| 234 | EEPROM.put(0, trackConfig); |
| 235 | } |
| 236 | |
| 237 | void loadConfig() { |
| 238 | EEPROM.get(0, trackConfig); |
| 239 | bool magicOk = true; |
| 240 | for (int i=0; i<4; i++) { |
| 241 | if (magicWord[i] != trackConfig.magic[i]) { |
| 242 | magicOk = false; |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | if (!magicOk) { |
| 247 | Serial.println("|0|First setup. Cleaning EEPROM.;"); |
| 248 | clearEEPROM(); |
| 249 | |
| 250 | for (int i=0; i<4; i++) { |
| 251 | trackConfig.magic[i] = magicWord[i]; |
| 252 | } |
| 253 | |
| 254 | for (int i=0; i<10; i++) { |
| 255 | trackConfig.version[i] = currVersion[i]; |
| 256 | } |
| 257 | |
| 258 | trackConfig.configVersion = CONFIG_VERSION; |
| 259 | trackConfig.gyroOffsetX = 0; |
| 260 | trackConfig.gyroOffsetY = 0; |
| 261 | trackConfig.gyroOffsetZ = 0; |
| 262 | trackConfig.accelOffsetX = 0; |
| 263 | trackConfig.accelOffsetY = 0; |
| 264 | trackConfig.accelOffsetZ = 0; |
| 265 | trackConfig.firstSetup = true; |
| 266 | saveConfig(); |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | /* |
| 271 | * Main Code |
| 272 | */ |
| 273 | |
| 274 | void setup() { |
| 275 | #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE |
| 276 | Wire.begin(); |
| 277 | TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz) |
| 278 | #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE |
| 279 | Fastwire::setup(400, true); |
| 280 | #endif |
| 281 | |
| 282 | MCUSR = 0; |
| 283 | |
| 284 | Serial.begin(115200); |
| 285 | Serial.println("|0|Initializing devices.;"); |
| 286 | mpu.initialize(); |
| 287 | |
| 288 | Serial.print("|1|MPUStatus|"); |
| 289 | Serial.print(mpu.testConnection()); |
| 290 | Serial.println(";"); |
| 291 | |
| 292 | Serial.println("|0|Initializing DMP.;"); |
| 293 | dmpStatus = mpu.dmpInitialize(); |
| 294 | |
| 295 | Serial.println("|0|Loading configuration.;"); |
| 296 | loadConfig(); |
| 297 | |
| 298 | if (dmpStatus == 0) { |
| 299 | dmpStatus = 1; |
| 300 | Serial.println("|0|DMP Initialized.;"); |
| 301 | } else { |
| 302 | dmpStatus = 0; |
| 303 | Serial.println("|0|Failed to initialize DMP.;"); |
| 304 | } |
| 305 | |
| 306 | if (trackConfig.firstSetup) { |
| 307 | Serial.println("|1|CALIBRATION|Requires Calibration;"); |
| 308 | } else { |
| 309 | Serial.println("|0|Loading Accel / Gyro Calibration;"); |
| 310 | mpu.setXGyroOffset(trackConfig.gyroOffsetX); |
| 311 | mpu.setYGyroOffset(trackConfig.gyroOffsetY); |
| 312 | mpu.setZGyroOffset(trackConfig.gyroOffsetZ); |
| 313 | mpu.setXAccelOffset(trackConfig.accelOffsetX); |
| 314 | mpu.setYAccelOffset(trackConfig.accelOffsetY); |
| 315 | mpu.setZAccelOffset(trackConfig.accelOffsetZ); |
| 316 | |
| 317 | mpu.setDMPEnabled(true); |
| 318 | |
| 319 | attachInterrupt(0, dmpDataReady, RISING); |
| 320 | dmpPacketSize = mpu.dmpGetFIFOPacketSize(); |
| 321 | Serial.println("|0|Waiting for DMP warmup.;"); |
| 322 | lastSerialTime = millis(); |
| 323 | while (lastSerialTime + DMP_WARMUP_TIME > millis()); // Wait for warmpup |
| 324 | Serial.println("|0|DMP Ready.;"); |
| 325 | } |
| 326 | |
| 327 | lastSerialTime = 0; |
| 328 | readingSerial = false; |
| 329 | } |
| 330 | |
| 331 | int currentState = STATE_IDLE; |
| 332 | |
| 333 | void machineStateProcess() { |
| 334 | char d; |
| 335 | switch (currentState) { |
| 336 | case STATE_IDLE: // Do Nothing |
| 337 | break; |
| 338 | case STATE_CALIBRATION: |
| 339 | Serial.println("|0|Entering Calibration State. This can take some time;"); |
| 340 | calibrate(); |
| 341 | currentState = STATE_IDLE; |
| 342 | break; |
| 343 | case STATE_SET_MOTORS: |
| 344 | d = Serial.read(); |
| 345 | |
| 346 | Serial.print("|0|Setting motors to "); |
| 347 | Serial.print(d & MTR_CTRL_VERDIRBIT > 0 ? "UP " : "DOWN "); |
| 348 | Serial.print(d & MTR_CTRL_VERPWRBIT > 0 ? "ON " : "OFF "); |
| 349 | Serial.print(d & MTR_CTRL_HORDIRBIT > 0 ? "LEFT " : "RIGHT "); |
| 350 | Serial.println(d & MTR_CTRL_HORPWRBIT > 0 ? "ON;" : "OFF;"); |
| 351 | |
| 352 | digitalWrite(VER_MTR_DIR_PIN, d & MTR_CTRL_VERDIRBIT); |
| 353 | digitalWrite(HOR_MTR_DIR_PIN, d & MTR_CTRL_HORDIRBIT); |
| 354 | digitalWrite(VER_MTR_PWR_PIN, d & MTR_CTRL_VERPWRBIT); |
| 355 | digitalWrite(HOR_MTR_PWR_PIN, d & MTR_CTRL_HORPWRBIT); |
| 356 | currentState = STATE_IDLE; |
| 357 | break; |
| 358 | case STATE_STOP_MOTORS: |
| 359 | Serial.println("|0|Stopping Motors.;"); |
| 360 | digitalWrite(VER_MTR_PWR_PIN, LOW); |
| 361 | digitalWrite(HOR_MTR_PWR_PIN, LOW); |
| 362 | currentState = STATE_IDLE; |
| 363 | break; |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | void loop() { |
| 368 | // Process MPU |
| 369 | if (dmpStatus) { |
| 370 | if (mpuInterrupt || fifoCount >= dmpPacketSize) { |
| 371 | mpuInterrupt = false; |
| 372 | mpuStatus = mpu.getIntStatus(); |
| 373 | |
| 374 | if ((mpuStatus & 0x10) || fifoCount == 1024) { |
| 375 | mpu.resetFIFO(); |
| 376 | Serial.println("|0|MPU FIFO Overflow!;"); |
| 377 | } else if (mpuStatus & 0x02) { |
| 378 | while (fifoCount < dmpPacketSize) { |
| 379 | fifoCount = mpu.getFIFOCount(); |
| 380 | } |
| 381 | |
| 382 | mpu.getFIFOBytes(fifoBuffer, dmpPacketSize); |
| 383 | fifoCount -= dmpPacketSize; |
| 384 | |
| 385 | mpu.dmpGetQuaternion(&q, fifoBuffer); |
| 386 | mpu.dmpGetGravity(&gravity, &q); |
| 387 | mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); |
| 388 | temperature = mpu.getTemperature() /340.00 + 36.53; |
| 389 | |
| 390 | Serial.print("|2|"); |
| 391 | Serial.print(ypr[0] * 180/M_PI); |
| 392 | Serial.print("|"); |
| 393 | Serial.print(ypr[1] * 180/M_PI); |
| 394 | Serial.print("|"); |
| 395 | Serial.print(ypr[2] * 180/M_PI); |
| 396 | Serial.println(";"); |
| 397 | |
| 398 | Serial.print("|3|"); |
| 399 | Serial.print(temperature); |
| 400 | Serial.println(";"); |
| 401 | } |
| 402 | } |
| 403 | } |
| 404 | // Process Serial Data |
| 405 | if (Serial.available() > 0) { |
| 406 | char cmd = Serial.read(); |
| 407 | switch (cmd) { |
| 408 | case CMD_CALIBRATE: currentState = STATE_CALIBRATION; break; |
| 409 | case CMD_STOP_MOTOR: currentState = STATE_STOP_MOTORS; break; |
| 410 | case CMD_SET_MOTOR: currentState = STATE_SET_MOTORS; break; |
| 411 | default: |
| 412 | Serial.print("|0|Unknown command "); |
| 413 | Serial.print(cmd); |
| 414 | Serial.println(";"); |
| 415 | } |
| 416 | } else if (lastSerialTime + SERIAL_TIMEOUT < millis() && readingSerial) { |
| 417 | // Timeout |
| 418 | Serial.println("|0|Serial Command Timeout;"); |
| 419 | |
| 420 | readingSerial = false; |
| 421 | } |
| 422 | |
| 423 | machineStateProcess(); |
| 424 | } |
| 425 | |
| 426 | #define CMD_CALIBRATE 'c' |
| 427 | #define CMD_STOP_MOTOR 's' |
| 428 | #define CMD_SET_MOTOR 'w' |