Última atividade 1 month ago

IMU for Tracking Dish

Revisão c05cde2c03cfc128dc28412a07f1e7e39ad1948c

trackdish.ino Bruto
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
45const char magicWord[5] = "DISH";
46const char currVersion[11] = CURRENT_VERSION;
47
48struct 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
62MPU6050 mpu;
63float ypr[3];
64int mpuStatus;
65int dmpStatus;
66int dmpPacketSize;
67uint16_t fifoCount;
68uint8_t fifoBuffer[64];
69float temperature;
70Config trackConfig;
71Quaternion q;
72VectorFloat gravity;
73
74long lastSerialTime;
75bool readingSerial;
76
77#define resetDevice() wdt_enable(WDTO_30MS); while(1) {}
78
79void measureSensorsMean();
80void saveConfig();
81
82/*
83 * MPU Interrupt
84 */
85
86volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
87void dmpDataReady() {
88 mpuInterrupt = true;
89}
90
91/*
92 * Calibration
93 */
94
95int16_t ax, ay, az,gx, gy, gz;
96
97int meanAccelX,meanAccelY,meanAccelZ,meanGyroX,meanGyroY,meanGyroZ,state=0;
98int accelOffsetX,accelOffsetY,accelOffsetZ,gyroOffsetX,gyroOffsetY,gyroOffsetZ;
99
100void 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
133void 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
194void 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
227void clearEEPROM() {
228 for (int index = 0 ; index < EEPROM.length() ; index++) {
229 EEPROM[index] = 0;
230 }
231}
232
233void saveConfig() {
234 EEPROM.put(0, trackConfig);
235}
236
237void 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
274void 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
331int currentState = STATE_IDLE;
332
333void 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
367void 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}