Arduino GPS Logger Code I Wrote

Below is theΒ current version of the code I use for my GPS logger,Β which is powered by a Neo 6M GPS unit, an Arduino SD Card Reader with an 8 GB MicroSD Card, and an Arduino Nano. It logs a wide variety of information about my current location, speed of travel, and other information so I can easily look back at my trip.

 GPS Logger

/*
   GPS Logger

      SD card attached to SPI bus as follows:
    *  ** CS - pin 10
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13

*/

#include <TinyGPS++.h>
char p_buffer[100];
#define P(str) (strcpy_P(p_buffer, PSTR(str)), p_buffer)

#define HOMELAT  42.614277
#define HOMELNG -73.851662

#include <SoftwareSerial.h>

// The serial connection to the GPS module
SoftwareSerial ss(4, 3);

// The TinyGPS++ object
TinyGPSPlus gps;

// Line Buffer to Save to File
char lnBuffer[115];

// Decimal to Number Char String Buffer
char numStr[30];

// delay
uint8_t prevSecond;

// data logger
#include <SPI.h>
#include <SD.h>

const uint8_t chipSelect = 10;

// location of previous location, used
// to calculate distance traveled
float prevLat = 0;
float prevLng = 0;
float prevAlt = 0; // stored in meters
float prevSpeed = 0; // stored in meters per second
float prevTime = 0;

// keep a running total of miles since last boot
float milesSinceBoot = 0;

// filename
char fileName[13];

// don't do anything if card is bad
bool cardWorks = false;

void setup() {
  Serial.begin(115200);
  ss.begin(9600);
  for (uint8_t i = 6; i < 9; i++) {
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }


  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println(F("Card failed, or not present"));
    digitalWrite(8, HIGH); //red
    cardWorks = false;

    // don't do anything more:
    return;
  }

  cardWorks = true;
  Serial.println(F("card initialized."));
  digitalWrite(6, HIGH);  // green

  fileName[0] = '\0';
}

void loop() {
  if (!cardWorks) {

    return;
  }

  while (ss.available() > 0) {
    gps.encode(ss.read());
  }

  // if no GPS blink red LED
  if (millis() > 5000 && gps.charsProcessed() < 10 && millis() % 1000 == 0) {
    digitalWrite(8, HIGH); //red
  }
  else if (millis() > 5000 && gps.charsProcessed() < 10 && millis() % 500 == 0) {
    digitalWrite(8, LOW); // red
  }

  // check if we have a valid location and blink yellow if invalid
  if (gps.location.isValid()) {
    digitalWrite(7, LOW);  // yellow
  }
  // next two lines will blink yellow (eye catching!)
  else if (!gps.location.isValid() && millis() % 1000 == 0) {
    digitalWrite(7, HIGH);  // yellow
  }
  else if (!gps.location.isValid() && millis() % 500 == 0) {
    digitalWrite(7, LOW);  // yellow
  }

  if (gps.location.isValid() && gps.time.second() != prevSecond) {

    // before we forget, log previous second
    prevSecond = gps.time.second();

    // if no file name, create
    if (fileName[0] == '\0') {
      // create filename
      // Example Filename = 03140201 (year=17, month=03, date=14, hour=02, tripnumber = 0
      uint8_t trip = 1;
      sprintf(fileName, P("%02d%02d%02d%02d.CSV"), gps.date.year() - 2000, gps.date.month(), gps.date.day(), trip);

      // well, if we have made 99 trips today (usually due to bad power connection) only write final trip
      while (SD.exists(fileName) && trip < 99) {
        trip++;
        sprintf(fileName, P("%02d%02d%02d%02d.CSV"), gps.date.year() - 2000, gps.date.month(), gps.date.day(), trip);
      }

      // print to serial where this data is being saved
      Serial.print(P("Writing to ... "));
      Serial.print(fileName);
      Serial.print(P("\n"));

      // write header to file
      File dataFileHead = SD.open(fileName, FILE_WRITE);

      // if not able to write, then turn LED red
      if (!dataFileHead) {
        digitalWrite(6, LOW);  // green
        digitalWrite(8, HIGH); //red
      }

      if (dataFileHead && trip != 99) {
        dataFileHead.println(P("year,month,day,hour,minute,second,sat,latitude,longitude,elev,mph,dir,cdir,grade,accel,trip,mihm,dirhm"));
        Serial.println( P("year,month,day,hour,minute,second,sat,latitude,longitude,elev,mph,dir,cdir,grade,accel,trip,mihm,dirhm"));
        lnBuffer[0] = '\0';
        dataFileHead.close();

        digitalWrite(6, HIGH);  // green
        digitalWrite(8, LOW); //red
      }

    }

    // dont log if no satellites found
    if (!gps.satellites.value()) return;

    sprintf(numStr, P("%04d,%02d,%02d,%02d,%02d,%02d, "), gps.date.year(), gps.date.month(), gps.date.day(), gps.time.hour(), gps.time.minute(), gps.time.second());
    strcat(lnBuffer, numStr);


    dtostrf(gps.satellites.value(), 3, 0, numStr);
    if (gps.satellites.isValid())
      strcat(lnBuffer, numStr);
    strcat(lnBuffer, P(", "));


    dtostrf(gps.location.lat(), 10, 6, numStr);
    if (gps.location.isValid())
      strcat(lnBuffer, numStr);

    strcat(lnBuffer, P(", "));


    dtostrf(gps.location.lng(), 10, 6, numStr);

    if (gps.location.isValid())
      strcat(lnBuffer, numStr);

    strcat(lnBuffer, P(", "));

    if (gps.altitude.isValid())
      dtostrf(gps.altitude.feet(), 5, 0, numStr);

    strcat(lnBuffer, numStr);

    // we only add the additional info if we have enough buffer space
    // as occassionally before I was accidentially causing the buffer to
    // overflow. In an idea world, I'd use a bigger buffer but RAM is limited
    // e.g. if (strlen(lnBuffer) < 100)

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, P(", "));

    dtostrf(gps.speed.mph(), 0, 1, numStr);

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, numStr);

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, P(", "));

    dtostrf(gps.course.deg(), 0, 1, numStr);

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, numStr);

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, P(", "));

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, TinyGPSPlus::cardinal(gps.course.deg()));

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, P(", "));

    // calculate current grade -- if we have a change in altitude
    // and we've traveled some kind of distance

    if (gps.altitude.isValid() && (gps.altitude.meters() - prevAlt) != 0 && TinyGPSPlus::distanceBetween(
          gps.location.lat(),
          gps.location.lng(),
          prevLat,
          prevLng) != 0) {


      dtostrf(
        (gps.altitude.meters() - prevAlt) /
        TinyGPSPlus::distanceBetween(
          gps.location.lat(),
          gps.location.lng(),
          prevLat,
          prevLng)

        , 5, 2, numStr);

      if (strlen(lnBuffer) < 100)
        strcat(lnBuffer, numStr);
    }
    else {
      if (strlen(lnBuffer) < 100)
        strcat(lnBuffer, P("0.00"));
    }

    // acceleration
    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, P(", "));

    dtostrf((gps.speed.mps() - prevSpeed) / (millis() - prevTime), 7, 4, numStr);

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, numStr);

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, P(", "));



    // total milage of trip at this part of logging
    // only increment when moving to minimize
    // "idle" gps hop

    if (prevLat && gps.speed.mph() > 1) {
      milesSinceBoot +=  TinyGPSPlus::distanceBetween(
                           gps.location.lat(),
                           gps.location.lng(),
                           prevLat,
                           prevLng) * 0.00062137112; // meters to miles
    }

    dtostrf( milesSinceBoot, 5, 2, numStr);

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, numStr);

    if (strlen(lnBuffer) < 100)
      strcat(lnBuffer, P(", "));

    // miles from home
    dtostrf( TinyGPSPlus::distanceBetween(
               gps.location.lat(),
               gps.location.lng(),
               HOMELAT, HOMELNG) * 0.00062137112, 5, 2, numStr);

    if (strlen(lnBuffer) < 105)
      strcat(lnBuffer, numStr);

    // direction from home (for shits and giggles)

    if (strlen(lnBuffer) < 105)
      strcat(lnBuffer, P(", "));

    if (strlen(lnBuffer) < 110)
      strcat(lnBuffer,     TinyGPSPlus::cardinal(TinyGPSPlus::courseTo(
               HOMELAT, HOMELNG,
               gps.location.lat(),
               gps.location.lng()
             )));


    // save previous lat/lng/alt
    prevLat = gps.location.lat();
    prevLng = gps.location.lng();
    prevAlt = gps.altitude.meters();
    prevSpeed = gps.speed.mps();
    prevTime = millis();

    File dataFile = SD.open(fileName, FILE_WRITE);

    if (dataFile) {
      dataFile.println(lnBuffer);
      dataFile.close();

      // print to the serial port too:
      Serial.println(lnBuffer);
      digitalWrite(6, HIGH);  // green
      digitalWrite(8, LOW); //red
    }
    // if the file isn't open, pop up an error:
    else {
      Serial.print(F("error opening "));
      Serial.print(fileName);
      Serial.print("\n");

      digitalWrite(6, LOW);  // green
      digitalWrite(8, HIGH); //red

    }

    // clear buffer
    lnBuffer[0] = '\0';

  }
}

Leave a Reply

Your email address will not be published. Required fields are marked *