-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathimucode_update_20191211.ino
582 lines (533 loc) · 18.7 KB
/
imucode_update_20191211.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
/******************************************************************************
SparkFun 9DoF Razor M0 Example Firmware
Jim Lindblom @ SparkFun Electronics
Original creation date: November 22, 2016
https://github.com/sparkfun/9DOF_Razor_IMU/Firmware
This example firmware for the SparkFun 9DoF Razor IMU M0
demonstrates how to grab accelerometer, gyroscope, magnetometer,
and quaternion values from the MPU-9250's digital motion processor
(DMP). It prints those values to a serial port and, if a card is
present, an SD card.
Values printed can be configured using the serial port. Settings
can be modified using the included "config.h" file.
Resources:
SparkFun MPU9250-DMP Arduino Library:
https://github.com/sparkfun/SparkFun_MPU-9250-DMP_Arduino_Library
FlashStorage Arduino Library
https://github.com/cmaglie/FlashStorage
Development environment specifics:
Firmware developed using Arduino IDE 1.6.12
Hardware:
SparkFun 9DoF Razor IMU M0 (SEN-14001)
https://www.sparkfun.com/products/14001
******************************************************************************/
// MPU-9250 Digital Motion Processing (DMP) Library
#include <SparkFunMPU9250-DMP.h>
// SD Library manages file and hardware control
#include <SD.h>
// config.h manages default logging parameters and can be used
// to adjust specific parameters of the IMU
#include "config.h"
// Flash storage (for nv storage on ATSAMD21)
#ifdef ENABLE_NVRAM_STORAGE
#include <FlashStorage.h>
#endif
MPU9250_DMP imu; // Create an instance of the MPU9250_DMP class
/////////////////////////////
// Logging Control Globals //
/////////////////////////////
// Defaults all set in config.h
bool enableSDLogging = ENABLE_SD_LOGGING;
bool enableSerialLogging = ENABLE_UART_LOGGING;
bool enableTimeLog = ENABLE_TIME_LOG;
bool enableCalculatedValues = ENABLE_CALCULATED_LOG;
bool enableAccel = ENABLE_ACCEL_LOG;
bool enableGyro = ENABLE_GYRO_LOG;
bool enableCompass = ENABLE_MAG_LOG;
bool enableQuat = ENABLE_QUAT_LOG;
bool enableEuler = ENABLE_EULER_LOG;
bool enableHeading = ENABLE_HEADING_LOG;
unsigned short accelFSR = IMU_ACCEL_FSR;
unsigned short gyroFSR = IMU_GYRO_FSR;
unsigned short fifoRate = DMP_SAMPLE_RATE;
/////////////////////
// SD Card Globals //
/////////////////////
bool sdCardPresent = false; // Keeps track of if SD card is plugged in
String logFileName; // Active logging file
String logFileBuffer; // Buffer for logged data. Max is set in config
///////////////////////
// LED Blink Control //
///////////////////////
//bool ledState = false;
uint32_t lastBlink = 0;
void blinkLED()
{
static bool ledState = false;
digitalWrite(HW_LED_PIN, ledState);
ledState = !ledState;
}
#ifdef ENABLE_NVRAM_STORAGE
///////////////////////////
// Flash Storage Globals //
///////////////////////////
// Logging parameters are all stored in non-volatile memory.
// They should maintain the previously set config value.
FlashStorage(flashEnableSDLogging, bool);
FlashStorage(flashFirstRun, bool);
FlashStorage(flashEnableSD, bool);
FlashStorage(flashEnableSerialLogging, bool);
FlashStorage(flashenableTime, bool);
FlashStorage(flashEnableCalculatedValues, bool);
FlashStorage(flashEnableAccel, bool);
FlashStorage(flashEnableGyro, bool);
FlashStorage(flashEnableCompass, bool);
FlashStorage(flashEnableQuat, bool);
FlashStorage(flashEnableEuler, bool);
FlashStorage(flashEnableHeading, bool);
FlashStorage(flashAccelFSR, unsigned short);
FlashStorage(flashGyroFSR, unsigned short);
FlashStorage(flashLogRate, unsigned short);
#endif
void setup()
{
// Initialize LED, interrupt input, and serial port.
// LED defaults to off:
initHardware();
#ifdef ENABLE_NVRAM_STORAGE
// Load previously-set logging parameters from nvram:
initLoggingParams();
#endif
// Initialize the MPU-9250. Should return true on success:
if ( !initIMU() )
{
LOG_PORT.println("Error connecting to MPU-9250");
while (1) ; // Loop forever if we fail to connect
// LED will remain off in this state.
}
// Check for the presence of an SD card, and initialize it:
if ( initSD() )
{
sdCardPresent = true;
// Get the next, available log file name
logFileName = nextLogFile();
}
}
void loop()
{
// The loop constantly checks for new serial input:
if ( LOG_PORT.available() )
{
// If new input is available on serial port
parseSerialInput(LOG_PORT.read()); // parse it
}
// Then check IMU for new data, and log it
if ( !imu.fifoAvailable() ) // If no new data is available
return; // return to the top of the loop
// Read from the digital motion processor's FIFO
if ( imu.dmpUpdateFifo() != INV_SUCCESS )
return; // If that fails (uh, oh), return to top
// If enabled, read from the compass.
if ( (enableCompass || enableHeading) && (imu.updateCompass() != INV_SUCCESS) )
return; // If compass read fails (uh, oh) return to top
// If logging (to either UART and SD card) is enabled
if ( enableSerialLogging || enableSDLogging)
logIMUData(); // Log new data
}
void logIMUData(void)
{
String imuLog = ""; // Create a fresh line to log
/*if (enableTimeLog) // If time logging is enabled
{
imuLog += String(imu.time) + ", "; // Add time to log string
}*/
if (enableAccel) // If accelerometer logging is enabled
{
if ( enableCalculatedValues ) // If in calculated mode
{
double ax = imu.calcAccel(imu.ax);
//if ( ax < 1 && ax > -1)
//{
// ax = 0;
//}
double ay = imu.calcAccel(imu.ay);
//if ( ay < 1 && ay > -1)
//{
//ay = 0;
//}
double az = imu.calcAccel(imu.az);
//if ( az < 1 && az > -1)
//{
// az = 0;
//}
imuLog += String(ax) + ", ";
imuLog += String(ay) + ", ";
imuLog += String(az) + ", ";
double acc = sqrt((sq(ax))+(sq(ay))+(sq(az))); // to find vector of acceleration
if (acc < 0)
{
acc = 1; // to find weight while stationary
}
//double lbs = 100; // entered weight
// double kg = lbs / 2.2; // to turn to kq
double newt = 1190; //weight in N
//string accel = ""; //create string to find highest accel out of
double GRF = acc * newt; // find highest GRF in N; dont need to multiply by gravity because that is found in the given weight
imuLog += String(GRF) + ",";
imuLog += String(acc) + ",";
}
else
{
imuLog += String(imu.ax) + ", ";
imuLog += String(imu.ay) + ", ";
imuLog += String(imu.az) + ", ";
}
}
/*if (enableGyro) // If gyroscope logging is enabled
{
if ( enableCalculatedValues ) // If in calculated mode
{
imuLog += String(imu.calcGyro(imu.gx)) + ", ";
imuLog += String(imu.calcGyro(imu.gy)) + ", ";
imuLog += String(imu.calcGyro(imu.gz)) + ", ";
}
else
{
imuLog += String(imu.gx) + ", ";
imuLog += String(imu.gy) + ", ";
imuLog += String(imu.gz) + ", ";
}
}
if (enableCompass) // If magnetometer logging is enabled
{
if ( enableCalculatedValues ) // If in calculated mode
{
imuLog += String(imu.calcMag(imu.mx)) + ", ";
imuLog += String(imu.calcMag(imu.my)) + ", ";
imuLog += String(imu.calcMag(imu.mz)) + ", ";
}
else
{
imuLog += String(imu.mx) + ", ";
imuLog += String(imu.my) + ", ";
imuLog += String(imu.mz) + ", ";
}
}
if (enableQuat) // If quaternion logging is enabled
{
if ( enableCalculatedValues )
{
imuLog += String(imu.calcQuat(imu.qw), 4) + ", ";
imuLog += String(imu.calcQuat(imu.qx), 4) + ", ";
imuLog += String(imu.calcQuat(imu.qy), 4) + ", ";
imuLog += String(imu.calcQuat(imu.qz), 4) + ", ";
}
else
{
imuLog += String(imu.qw) + ", ";
imuLog += String(imu.qx) + ", ";
imuLog += String(imu.qy) + ", ";
imuLog += String(imu.qz) + ", ";
}
}
if (enableEuler) // If Euler-angle logging is enabled
{
imu.computeEulerAngles();
imuLog += String(imu.pitch, 2) + ", ";
imuLog += String(imu.roll, 2) + ", ";
imuLog += String(imu.yaw, 2) + ", ";
}*/
if (enableHeading) // If heading logging is enabled
{
imuLog += String(imu.computeCompassHeading(), 2) + ", ";
}
// Remove last comma/space:
imuLog.remove(imuLog.length() - 2, 2);
imuLog += "\r\n"; // Add a new line
if (enableSerialLogging) // If serial port logging is enabled
LOG_PORT.print(imuLog); // Print log line to serial port
// If SD card logging is enabled & a card is plugged in
if ( sdCardPresent && enableSDLogging)
{
// If adding this log line will put us over the buffer length:
if (imuLog.length() + logFileBuffer.length() >=
SD_LOG_WRITE_BUFFER_SIZE)
{
sdLogString(logFileBuffer); // Log SD buffer
logFileBuffer = ""; // Clear SD log buffer
blinkLED(); // Blink LED every time a new buffer is logged to SD
}
// Add new line to SD log buffer
logFileBuffer += imuLog;
}
else
{
// Blink LED once every second (if only logging to serial port)
if ( millis() > lastBlink + UART_BLINK_RATE )
{
blinkLED();
lastBlink = millis();
}
}
}
void initHardware(void)
{
// Set up LED pin (active-high, default to off)
pinMode(HW_LED_PIN, OUTPUT);
digitalWrite(HW_LED_PIN, LOW);
// Set up MPU-9250 interrupt input (active-low)
pinMode(MPU9250_INT_PIN, INPUT_PULLUP);
// Set up serial log port
LOG_PORT.begin(SERIAL_BAUD_RATE);
}
bool initIMU(void)
{
// imu.begin() should return 0 on success. Will initialize
// I2C bus, and reset MPU-9250 to defaults.
if (imu.begin() != INV_SUCCESS)
return false;
// Set up MPU-9250 interrupt:
imu.enableInterrupt(); // Enable interrupt output
imu.setIntLevel(1); // Set interrupt to active-low
imu.setIntLatched(1); // Latch interrupt output
// Configure sensors:
// Set gyro full-scale range: options are 250, 500, 1000, or 2000:
imu.setGyroFSR(gyroFSR); //config.h set to 2000
// Set accel full-scale range: options are 2, 4, 8, or 16 g
imu.setAccelFSR(16); //accelFSR to access config.h
// Set gyro/accel LPF: options are 5, 10, 20, 42, 98, 188 Hz
imu.setLPF(IMU_AG_LPF); //config.h setto 5
// Set gyro/accel sample rate: must be between 4-1000Hz
// (note: this value will be overridden by the DMP sample rate)
imu.setSampleRate(100); // for 1/100 second
// Set compass sample rate: between 4-100Hz
imu.setCompassSampleRate(IMU_COMPASS_SAMPLE_RATE);
// Configure digital motion processor. Use the FIFO to get
// data from the DMP.
unsigned short dmpFeatureMask = 0;
if (ENABLE_GYRO_CALIBRATION)
{
// Gyro calibration re-calibrates the gyro after a set amount
// of no motion detected
dmpFeatureMask |= DMP_FEATURE_GYRO_CAL;
dmpFeatureMask |= DMP_FEATURE_SEND_CAL_GYRO;
}
else
{
// Otherwise add raw gyro readings to the DMP
dmpFeatureMask |= DMP_FEATURE_SEND_RAW_GYRO;
}
// Add accel and quaternion's to the DMP
dmpFeatureMask |= DMP_FEATURE_SEND_RAW_ACCEL;
dmpFeatureMask |= DMP_FEATURE_6X_LP_QUAT;
// Initialize the DMP, and set the FIFO's update rate:
imu.dmpBegin(dmpFeatureMask, fifoRate);
return true; // Return success
}
bool initSD(void)
{
// SD.begin should return true if a valid SD card is present
if ( !SD.begin(SD_CHIP_SELECT_PIN) )
{
return false;
}
return true;
}
// Log a string to the SD card
bool sdLogString(String toLog)
{
// Open the current file name:
File logFile = SD.open(logFileName, FILE_WRITE);
// If the file will get too big with this new string, create
// a new one, and open it.
if (logFile.size() > (SD_MAX_FILE_SIZE - toLog.length()))
{
logFileName = nextLogFile();
logFile = SD.open(logFileName, FILE_WRITE);
}
// If the log file opened properly, add the string to it.
if (logFile)
{
logFile.print(toLog);
logFile.close();
return true; // Return success
}
return false; // Return fail
}
// Find the next available log file. Or return a null string
// if we've reached the maximum file limit.
String nextLogFile(void)
{
String filename;
int logIndex = 0;
for (int i = 0; i < LOG_FILE_INDEX_MAX; i++)
{
// Construct a file with PREFIX[Index].SUFFIX
filename = String(LOG_FILE_PREFIX);
filename += String(logIndex);
filename += ".";
filename += String(LOG_FILE_SUFFIX);
// If the file name doesn't exist, return it
if (!SD.exists(filename))
{
return filename;
}
// Otherwise increment the index, and try again
logIndex++;
}
return "";
}
// Parse serial input, take action if it's a valid character
void parseSerialInput(char c)
{
unsigned short temp;
switch (c)
{
case PAUSE_LOGGING: // Pause logging on SPACE
enableSerialLogging = !enableSerialLogging;
#ifdef ENABLE_NVRAM_STORAGE
flashEnableSerialLogging.write(enableSerialLogging);
#endif
break;
case ENABLE_TIME: // Enable time (milliseconds) logging
enableTimeLog = !enableTimeLog;
#ifdef ENABLE_NVRAM_STORAGE
flashenableTime.write(enableTimeLog);
#endif
break;
case ENABLE_ACCEL: // Enable/disable accelerometer logging
enableAccel = !enableAccel;
#ifdef ENABLE_NVRAM_STORAGE
flashEnableAccel.write(enableAccel);
#endif
break;
case ENABLE_GYRO: // Enable/disable gyroscope logging
enableGyro = !enableGyro;
#ifdef ENABLE_NVRAM_STORAGE
flashEnableGyro.write(enableGyro);
#endif
break;
case ENABLE_COMPASS: // Enable/disable magnetometer logging
enableCompass = !enableCompass;
#ifdef ENABLE_NVRAM_STORAGE
flashEnableCompass.write(enableCompass);
#endif
break;
case ENABLE_CALC: // Enable/disable calculated value logging
enableCalculatedValues = !enableCalculatedValues;
#ifdef ENABLE_NVRAM_STORAGE
flashEnableCalculatedValues.write(enableCalculatedValues);
#endif
break;
case ENABLE_QUAT: // Enable/disable quaternion logging
enableQuat = !enableQuat;
#ifdef ENABLE_NVRAM_STORAGE
flashEnableQuat.write(enableQuat);
#endif
break;
case ENABLE_EULER: // Enable/disable Euler angle (roll, pitch, yaw)
enableEuler = !enableEuler;
#ifdef ENABLE_NVRAM_STORAGE
flashEnableEuler.write(enableEuler);
#endif
break;
case ENABLE_HEADING: // Enable/disable heading output
enableHeading = !enableHeading;
#ifdef ENABLE_NVRAM_STORAGE
flashEnableHeading.write(enableHeading);
#endif
break;
case SET_LOG_RATE: // Increment the log rate from 1-100Hz (10Hz increments)
temp = imu.dmpGetFifoRate(); // Get current FIFO rate
if (temp == 1) // If it's 1Hz, set it to 10Hz
temp = 10;
else
temp += 10; // Otherwise increment by 10
if (temp > 100) // If it's greater than 100Hz, reset to 1
temp = 1;
imu.dmpSetFifoRate(temp); // Send the new rate
temp = imu.dmpGetFifoRate(); // Read the updated rate
#ifdef ENABLE_NVRAM_STORAGE
flashLogRate.write(temp); // Store it in NVM and print new rate
#endif
LOG_PORT.println("IMU rate set to " + String(temp) + " Hz");
break;
case SET_ACCEL_FSR: // Increment accelerometer full-scale range
temp = imu.getAccelFSR(); // Get current FSR
if (temp == 2) temp = 4; // If it's 2, go to 4
else if (temp == 4) temp = 8; // If it's 4, go to 8
else if (temp == 8) temp = 16; // If it's 8, go to 16
else temp = 2; // Otherwise, default to 2
imu.setAccelFSR(temp); // Set the new FSR
temp = imu.getAccelFSR(); // Read it to make sure
#ifdef ENABLE_NVRAM_STORAGE
flashAccelFSR.write(temp); // Update the NVM value, and print
#endif
LOG_PORT.println("Accel FSR set to +/-" + String(temp) + " g");
break;
case SET_GYRO_FSR:// Increment gyroscope full-scale range
temp = imu.getGyroFSR(); // Get the current FSR
if (temp == 250) temp = 500; // If it's 250, set to 500
else if (temp == 500) temp = 1000; // If it's 500, set to 1000
else if (temp == 1000) temp = 2000;// If it's 1000, set to 2000
else temp = 250; // Otherwise, default to 250
imu.setGyroFSR(temp); // Set the new FSR
temp = imu.getGyroFSR(); // Read it to make sure
#ifdef ENABLE_NVRAM_STORAGE
flashGyroFSR.write(temp); // Update the NVM value, and print
#endif
LOG_PORT.println("Gyro FSR set to +/-" + String(temp) + " dps");
break;
case ENABLE_SD_LOGGING: // Enable/disable SD card logging
enableSDLogging = !enableSDLogging;
#ifdef ENABLE_NVRAM_STORAGE
flashEnableSDLogging.write(enableSDLogging);
#endif
break;
default: // If an invalid character, do nothing
break;
}
}
#ifdef ENABLE_NVRAM_STORAGE
// Read from non-volatile memory to get logging parameters
void initLoggingParams(void)
{
// Read from firstRun mem location, should default to 0 on program
if (flashFirstRun.read() == 0)
{
// If we've got a freshly programmed board, program all of the
// nvm locations:
flashEnableSDLogging.write(enableSDLogging);
flashEnableSerialLogging.write(enableSerialLogging);
flashenableTime.write(enableTimeLog);
flashEnableCalculatedValues.write(enableCalculatedValues);
flashEnableAccel.write(enableAccel);
flashEnableGyro.write(enableGyro);
flashEnableCompass.write(enableCompass);
flashEnableQuat.write(enableQuat);
flashEnableEuler.write(enableEuler);
flashEnableHeading.write(enableHeading);
flashAccelFSR.write(accelFSR);
flashGyroFSR.write(gyroFSR);
flashLogRate.write(fifoRate);
flashFirstRun.write(1); // Set the first-run boolean
}
else // If values have been previously set:
{
// Read from NVM and set the logging parameters:
enableSDLogging = flashEnableSDLogging.read();
enableSerialLogging = flashEnableSerialLogging.read();
enableTimeLog = flashenableTime.read();
enableCalculatedValues = flashEnableCalculatedValues.read();
enableAccel = flashEnableAccel.read();
enableGyro = flashEnableGyro.read();
enableCompass = flashEnableCompass.read();
enableQuat = flashEnableQuat.read();
enableEuler = flashEnableEuler.read();
enableHeading = flashEnableHeading.read();
accelFSR = flashAccelFSR.read();
gyroFSR = flashGyroFSR.read();
fifoRate = flashLogRate.read();
}
}
#endif