summaryrefslogtreecommitdiff
path: root/obdlogger/obdlogger.ino
diff options
context:
space:
mode:
Diffstat (limited to 'obdlogger/obdlogger.ino')
-rw-r--r--obdlogger/obdlogger.ino560
1 files changed, 320 insertions, 240 deletions
diff --git a/obdlogger/obdlogger.ino b/obdlogger/obdlogger.ino
index 1f6bd2b..0366600 100644
--- a/obdlogger/obdlogger.ino
+++ b/obdlogger/obdlogger.ino
@@ -1,5 +1,5 @@
/*************************************************************************
-* Arduino OBD-II Data Logger
+* Arduino GPS/OBD-II/G-Force Data Logger
* Distributed under GPL v2.0
* Copyright (c) 2013 Stanley Huang <stanleyhuangyc@gmail.com>
* All rights reserved.
@@ -14,314 +14,408 @@
#include "MPU6050.h"
//#define SD_CS_PIN 4 // ethernet shield with SD
-//#define SD_CS_PIN 7 // microduino
-#define SD_CS_PIN 10 // SD breakout
+#define SD_CS_PIN 7 // microduino
+//#define SD_CS_PIN 10 // SD breakout
-#define GPS_BAUDRATE 4800 /* bps */
+#define GPS_BAUDRATE 38400 /* bps */
-// addition PIDs (non-OBD)
+#define STATE_SD_READY 0x1
+#define STATE_OBD_READY 0x2
+#define STATE_GPS_CONNECTED 0x4
+#define STATE_GPS_READY 0x8
+#define STATE_ACC_READY 0x10
+
+// additional PIDs (non-OBD)
#define PID_GPS_DATETIME 0xF01
#define PID_GPS_COORDINATE 0xF02
#define PID_GPS_ALTITUDE 0xF03
#define PID_GPS_SPEED 0xF04
-#define DATASET_INTERVAL 250 /* ms */
+#define DATASET_INTERVAL 100 /* ms */
+#define FILE_NAME_FORMAT "OBD%05d.CSV"
-// GPS logging can only be enabled when there is additional serial UART
-#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega644P__)
-#define ENABLE_GPS
+// GPS logging can only be enabled when there is additional hardware serial UART
+#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
+#define GPSUART Serial3
+#elif defined(__AVR_ATmega644P__)
+#define GPSUART Serial1
#endif
-// GPS
-#ifdef ENABLE_GPS
+#ifdef GPSUART
TinyGPS gps;
-#endif
+#endif // GPSUART
// SD card
Sd2Card card;
SdVolume volume;
File sdfile;
-// LCD
+// enable one LCD
LCD_OLED lcd; /* for I2C OLED module */
//LCD_PCD8544 lcd; /* for LCD4884 shield or Nokia 5100 screen module */
//LCD_1602 lcd; /* for LCD1602 shield */
-static uint32_t filesize = 0;
-static uint32_t datacount = 0;
-
-void ProcessGPSData(char c);
+static uint32_t fileSize = 0;
+static uint32_t lastFileSize = 0;
+static uint32_t lastDataTime;
+static int startDistance = 0;
+static uint16_t fileIndex = 0;
-class COBD2 : public COBD
+class CLogger : public COBD
{
public:
- void DataTimeout()
+ void InitIdleLoop()
{
-#ifdef ENABLE_GPS
+ // called while initializing
+#ifdef GPSUART
// detect GPS signal
- while (Serial1.available()) {
- if (gps.encode(Serial1.read())) {
- if (datacount == 0) {
- lcd.setCursor(9, 3);
- lcd.print("GPS:Yes");
- }
+ if (GPSUART.available()) {
+ if (gps.encode(GPSUART.read())) {
+ state |= STATE_SD_READY;
}
}
+ if (state & STATE_ACC_READY) {
+ accel_t_gyro_union data;
+ MPU6050_readout(&data);
+ char buf[8];
+ sprintf(buf, "X:%4d", data.value.x_accel / 190);
+ lcd.setCursor(9, 1);
+ lcd.print(buf);
+ sprintf(buf, "Y:%4d", data.value.y_accel / 190);
+ lcd.setCursor(9, 2);
+ lcd.print(buf);
+ sprintf(buf, "Z:%4d", data.value.z_accel / 190);
+ lcd.setCursor(9, 3);
+ lcd.print(buf);
+ delay(50);
+ }
#endif
}
-};
-
-COBD2 obd;
-
-bool ShowCardInfo()
-{
- if (card.init(SPI_HALF_SPEED, SD_CS_PIN)) {
- const char* type;
- char buf[20];
-
- switch(card.type()) {
- case SD_CARD_TYPE_SD1:
- type = "SD1";
- break;
- case SD_CARD_TYPE_SD2:
- type = "SD2";
- break;
- case SD_CARD_TYPE_SDHC:
- type = "SDHC";
- break;
- default:
- type = "N/A";
- }
-
- sprintf(buf, "SD Type: %s", type);
- lcd.setCursor(0, 0);
- lcd.print(buf);
- if (!volume.init(card)) {
- lcd.setCursor(0, 1);
- lcd.print("No FAT!");
- return false;
- }
-
- uint32_t volumesize = volume.blocksPerCluster();
- volumesize >>= 1; // 512 bytes per block
- volumesize *= volume.clusterCount();
- volumesize >>= 10;
-
- sprintf(buf, "SD Size: %dMB", (int)volumesize);
- lcd.setCursor(0, 1);
- lcd.print(buf);
- return true;
- } else {
+ void DataIdleLoop()
+ {
+ // called while waiting for OBD-II response
+#ifdef GPSUART
+ if (GPSUART.available())
+ ProcessGPS();
+#endif
+ }
+ void ShowStates()
+ {
lcd.setCursor(0, 1);
- lcd.print("No SD Card ");
- return false;
- }
-}
+ lcd.print("OBD:");
+ lcd.print((state & STATE_OBD_READY) ? "Yes" : "No");
+ lcd.setCursor(0, 2);
+ lcd.print("GPS:");
+ if (state & STATE_GPS_READY)
+ lcd.print("Yes");
+ else if (state & STATE_GPS_CONNECTED)
+ lcd.print("--");
+ else
+ lcd.print("No");
+
+ lcd.setCursor(0, 3);
+ lcd.print("ACC:");
+ lcd.print((state & STATE_ACC_READY) ? "Yes" : "No");
+ }
+ void Setup()
+ {
+ state = 0;
-static uint32_t lastTime;
-static int startDistance = 0;
+ lcd.clear();
-static void CheckSD()
-{
- uint16_t fileidx = 0;
- char filename[13];
- for (;;) {
- if (!ShowCardInfo()) {
- delay(1000);
- continue;
- }
+ // init SD card
+ if (CheckSD()) state |= STATE_SD_READY;
+ ShowStates();
- delay(1000);
- SD.begin(SD_CS_PIN);
+ if (MPU6050_init() == 0) state |= STATE_ACC_READY;
+ ShowStates();
- // determine file name
- for (uint16_t index = 1; index < 65535; index++) {
- sprintf(filename, "OBD%05d.CSV", index);
- if (!SD.exists(filename)) {
- fileidx = index;
+#ifdef GPSUART
+ unsigned long t = millis();
+ do {
+ if (GPSUART.available()) {
+ state |= STATE_GPS_CONNECTED;
break;
}
- }
- if (fileidx) break;
- lcd.setCursor(0, 2);
- lcd.print("SD error ");
- }
+ } while (millis() - t <= 1000);
+#endif
- lcd.clearLine(2);
- lcd.setCursor(0, 2);
- lcd.print(filename);
+ do {
+ ShowStates();
+ } while (!Init());
- filesize = 0;
- sdfile = SD.open(filename, FILE_WRITE);
- if (sdfile) {
- return;
- }
+ state |= STATE_OBD_READY;
+ ReadSensor(PID_DISTANCE, startDistance);
- lcd.setCursor(0, 2);
- lcd.print("File error");
-}
+ ShowStates();
+ delay(1000);
-void InitScreen()
-{
- byte n = lcd.getLines() <= 2 ? 6 : 9;
- lcd.clear();
- lcd.backlight(true);
- lcd.setCursor(n, 0);
- lcd.print("kph");
- lcd.setCursor(n, 1);
- lcd.print("rpm");
-}
+ // open file for logging
+ if (!(state & STATE_SD_READY)) {
+ do {
+ delay(1000);
+ } while (!CheckSD());
+ state |= STATE_SD_READY;
+ ShowStates();
+ }
-void setup()
-{
- lcd.begin();
- lcd.clear();
- lcd.backlight(true);
- lcd.print("OBD/GPS Logger");
- lcd.setCursor(0, 1);
- lcd.print("Initializing...");
- delay(2000);
+ fileSize = 0;
+ for (;;) {
+ char filename[13];
+ sprintf(filename, FILE_NAME_FORMAT, fileIndex);
+ sdfile = SD.open(filename, FILE_WRITE);
+ if (sdfile) break;
+ lcd.setCursor(0, 2);
+ lcd.print("SD Error");
+ delay(1000);
+ CheckSD();
+ }
- // start serial communication at the adapter defined baudrate
- OBDUART.begin(OBD_SERIAL_BAUDRATE);
+ InitScreen();
+ lastDataTime = millis();
+ }
+ void LogData(byte pid)
+ {
+ uint32_t start = millis();
- // init SD card
- pinMode(SS, OUTPUT);
- CheckSD();
+ // send a query to OBD adapter for specified OBD-II pid
+ int value;
+ if (ReadSensor(pid, value)) {
+ ProcessOBD(pid, value);
+ }
- // initiate OBD-II connection until success
- lcd.clearLine(3);
- lcd.setCursor(0, 3);
- lcd.print("OBD:No");
+ // flush SD data every 1KB
+ if (fileSize - lastFileSize >= 1024) {
+ sdfile.flush();
+ // display logged data size
+ char buf[7];
+ sprintf(buf, "%4uKB", (int)(fileSize >> 10));
+ lcd.setCursor(10, 3);
+ lcd.print(buf);
+ lastFileSize = fileSize;
+ }
-#ifdef ENABLE_GPS
- Serial1.begin(GPS_BAUDRATE);
- unsigned long t = millis();
- do {
- if (Serial1.available()) {
- lcd.setCursor(9, 3);
- lcd.print("GPS:No");
- break;
+ if (state & STATE_ACC_READY) {
+ ProcessAccelerometer();
}
- } while (millis() - t <= 1000);
+
+ // if OBD response is very fast, go on processing GPS data for a while
+ while (millis() - start < DATASET_INTERVAL) {
+#ifdef GPSUART
+ if (GPSUART.available())
+ ProcessGPS();
#endif
+ }
+ }
+ void Reconnect()
+ {
+ sdfile.close();
+ lcd.clear();
+ lcd.print("Reconnecting");
+ state = 0;
+ digitalWrite(SD_CS_PIN, LOW);
+ for (int i = 0; !Init(); i++) {
+ if (i == 10) lcd.clear();
+ }
+ Setup();
+ }
+private:
+ bool CheckSD()
+ {
+ lcd.setCursor(0, 0);
+ if (card.init(SPI_HALF_SPEED, SD_CS_PIN)) {
+ const char* type;
+ char buf[20];
- while (!obd.Init());
+ switch(card.type()) {
+ case SD_CARD_TYPE_SD1:
+ type = "SD1";
+ break;
+ case SD_CARD_TYPE_SD2:
+ type = "SD2";
+ break;
+ case SD_CARD_TYPE_SDHC:
+ type = "SDHC";
+ break;
+ default:
+ type = "SDx";
+ }
- obd.ReadSensor(PID_DISTANCE, startDistance);
+ lcd.print(type);
+ lcd.write(' ');
+ if (!volume.init(card)) {
+ lcd.print("No FAT!");
+ return false;
+ }
- lcd.setCursor(0, 3);
- lcd.setCursor(4, 3);
- lcd.print("Yes");
- delay(1000);
+ uint32_t volumesize = volume.blocksPerCluster();
+ volumesize >>= 1; // 512 bytes per block
+ volumesize *= volume.clusterCount();
+ volumesize >>= 10;
- InitScreen();
- lastTime = millis();
-}
+ sprintf(buf, "%dG", (int)(volumesize + 511) >> 10);
+ lcd.print(buf);
+ } else {
+ lcd.print("No SD Card ");
+ return false;
+ }
-static char databuf[32];
-static int len = 0;
-static int value = 0;
+ if (!SD.begin(SD_CS_PIN)) {
+ lcd.setCursor(8, 0);
+ lcd.print("Bad SD");
+ return false;
+ }
-#ifdef ENABLE_GPS
-void ProcessGPSData(char c)
-{
- if (!gps.encode(c))
- return;
+ char filename[13];
+ // now determine log file name
+ for (fileIndex = 1; fileIndex; fileIndex++) {
+ sprintf(filename, FILE_NAME_FORMAT, fileIndex);
+ if (!SD.exists(filename)) {
+ break;
+ }
+ }
+ if (!fileIndex) {
+ lcd.setCursor(8, 8);
+ lcd.print("Bad File");
+ return false;
+ }
- // parsed GPS data is ready
- uint32_t curTime = millis();
- unsigned long fix_age;
+ filename[8] = 0;
+ lcd.setCursor(11, 0);
+ lcd.print(filename + 3);
+ return true;
+ }
+ void InitScreen()
{
+ lcd.clear();
+ lcd.backlight(true);
+ lcd.setCursor(lcd.getLines() <= 2 ? 4 : 7, 0);
+ lcd.print("kph");
+ lcd.setCursor(5, 1);
+ lcd.print("rpm");
+ lcd.setCursor(9, 1);
+ lcd.print("THR: %");
+ }
+ void ProcessGPS()
+ {
+ char buf[32];
+ // process GPS data
+ char c = GPSUART.read();
+ if (!gps.encode(c)) return;
+
+ // parsed GPS data is ready
+ uint32_t dataTime = millis();
+ uint16_t elapsed = (uint16_t)(dataTime - lastDataTime);
+ unsigned long fix_age;
+ int len;
+
unsigned long date, time;
gps.get_datetime(&date, &time, &fix_age);
- len = sprintf(databuf, "%d,F01,%ld %ld\n", (int)(curTime - lastTime), date, time);
- sdfile.write((uint8_t*)databuf, len);
- }
+ len = sprintf(buf, "%u,F01,%ld %ld\n", elapsed, date, time);
+ sdfile.write((uint8_t*)buf, len);
- {
long lat, lon;
gps.get_position(&lat, &lon, &fix_age);
- len = sprintf(databuf, "%d,F02,%ld %ld\n", (int)(curTime - lastTime), lat, lon);
- sdfile.write((uint8_t*)databuf, len);
+ len = sprintf(buf, "%u,F02,%ld %ld\n", elapsed, lat, lon);
+ sdfile.write((uint8_t*)buf, len);
+
// display LAT/LON if screen is big enough
if (lcd.getLines() > 3) {
- sprintf(databuf, "%3d.%ld", (int)(lat / 100000), lat % 100000);
+ if (((unsigned int)dataTime / 1000) & 1)
+ sprintf(buf, "LAT: %d.%ld ", (int)(lat / 100000), lat % 100000);
+ else
+ sprintf(buf, "LON: %d.%ld ", (int)(lon / 100000), lon % 100000);
lcd.setCursor(0, 2);
- lcd.print(databuf);
- sprintf(databuf, "%3d.%ld", (int)(lon / 100000), lon % 100000);
- lcd.setCursor(0, 3);
- lcd.print(databuf);
+ lcd.print(buf);
}
- }
- len = sprintf(databuf, "%d,F03,%ld %ld\n", (int)(curTime - lastTime), gps.speed() * 1852 / 100);
- sdfile.write((uint8_t*)databuf, len);
- len = sprintf(databuf, "%d,F04,%ld %ld\n", (int)(curTime - lastTime), gps.altitude());
- sdfile.write((uint8_t*)databuf, len);
- lastTime = curTime;
-}
-#endif
-
-void RetrieveData(byte pid)
-{
- // issue a query for OBD
- obd.Query(pid);
+ len = sprintf(buf, "%u,F03,%ld\n", elapsed, gps.speed() * 1852 / 100);
+ sdfile.write((uint8_t*)buf, len);
- // flush data in the buffer
- if (len > 0) {
- sdfile.write((uint8_t*)databuf, len);
+ len = sprintf(buf, "%u,F04,%ld\n", elapsed, gps.altitude());
+ sdfile.write((uint8_t*)buf, len);
+ lastDataTime = dataTime;
+ }
- char* buf = databuf; // data in buffer saved, free for other use
- if (datacount % 100 == 99) {
- sdfile.flush();
- sprintf(buf, "%4uKB", (int)(filesize >> 10));
- lcd.setCursor(10, 3);
- lcd.print(buf);
- }
+ void ProcessAccelerometer()
+ {
+ accel_t_gyro_union data;
+ MPU6050_readout(&data);
+ char buf[20];
+ sprintf(buf, "%d %d %d ", data.value.x_accel / 190, data.value.y_accel / 190, data.value.z_accel / 190);
+ lcd.setCursor(0, 2);
+ lcd.print(buf);
+ }
+ void ProcessOBD(byte pid, int value)
+ {
+ char buf[32];
+ uint32_t dataTime = millis();
+ uint16_t elapsed = (uint16_t)(dataTime - lastDataTime);
+ byte len = sprintf(buf, "%u,%X,%d\n", elapsed, pid, value);
+ // log OBD data
+ sdfile.write((uint8_t*)buf, len);
+ fileSize += len;
+
+ // display OBD data
switch (pid) {
case PID_RPM:
sprintf(buf, "%4u", (unsigned int)value % 10000);
- lcd.setCursor(0, 0);
- lcd.printLarge(buf);
+ lcd.setCursor(0, 1);
+ lcd.print(buf);
break;
case PID_SPEED:
sprintf(buf, "%3u", (unsigned int)value % 1000);
- lcd.setCursor(2, 1);
+ lcd.setCursor(0, 0);
lcd.printLarge(buf);
break;
+ case PID_THROTTLE:
+ sprintf(buf, "%2d", value % 100);
+ lcd.setCursor(13, 1);
+ lcd.print(buf);
+ break;
case PID_DISTANCE:
if (value >= startDistance) {
- sprintf(buf, "%4dkm", value - startDistance);
- lcd.setCursor(10, 2);
+ sprintf(buf, "%4ukm", ((uint16_t)value - startDistance) % 1000);
+ lcd.setCursor(10, 0);
lcd.print(buf);
}
break;
}
+ lastDataTime = dataTime;
}
+ byte state;
+};
-#ifdef ENABLE_GPS
- while (Serial1.available()) {
- ProcessGPSData(Serial1.read());
- }
+CLogger logger;
+
+void setup()
+{
+ lcd.begin();
+ lcd.clear();
+ lcd.backlight(true);
+ lcd.print("OBD/GPS Logger");
+ lcd.setCursor(0, 1);
+ lcd.print("Initializing...");
+
+ Wire.begin();
+
+ // start serial communication at the adapter defined baudrate
+ OBDUART.begin(OBD_SERIAL_BAUDRATE);
+#ifdef GPSUART
+ GPSUART.begin(GPS_BAUDRATE);
#endif
- if (obd.GetResponse(pid, value)) {
- uint32_t curTime = millis();
- len = sprintf(databuf, "%d,%X,%d\n", (int)(curTime - lastTime), pid, value);
- filesize += len;
- datacount++;
- lastTime = curTime;
- return;
- }
- len = 0;
+ pinMode(SS, OUTPUT);
+ delay(1000);
+
+ logger.Setup();
}
void loop()
{
- static char count = 0;
+ static byte count = 0;
unsigned long t = millis();
switch (count++) {
@@ -329,37 +423,23 @@ void loop()
case 64:
case 128:
case 192:
- RetrieveData(PID_DISTANCE);
+ logger.LogData(PID_DISTANCE);
break;
case 4:
- RetrieveData(PID_COOLANT_TEMP);
+ logger.LogData(PID_COOLANT_TEMP);
break;
case 20:
- RetrieveData(PID_INTAKE_TEMP);
+ logger.LogData(PID_INTAKE_TEMP);
break;
}
- RetrieveData(PID_RPM);
- RetrieveData(PID_SPEED);
- //RetrieveData(PID_THROTTLE);
- //RetrieveData(PID_ABS_ENGINE_LOAD);
+ logger.LogData(PID_RPM);
+ logger.LogData(PID_SPEED);
+ logger.LogData(PID_THROTTLE);
+ //LogData(PID_ABS_ENGINE_LOAD);
- if (obd.errors >= 5) {
- sdfile.close();
- lcd.clear();
- lcd.print("Reconnecting...");
- digitalWrite(SD_CS_PIN, LOW);
- for (int i = 0; !obd.Init(); i++) {
- if (i == 10) lcd.clear();
- }
- digitalWrite(SD_CS_PIN, HIGH);
- CheckSD();
- delay(1000);
- InitScreen();
+ if (logger.errors >= 5) {
+ logger.Reconnect();
count = 0;
- return;
}
-
- t = millis() - t;
- if (t < DATASET_INTERVAL) delay(DATASET_INTERVAL - t);
}