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

001/*
002   GPS Logger
003 
004      SD card attached to SPI bus as follows:
005    *  ** CS - pin 10
006 ** MOSI - pin 11
007 ** MISO - pin 12
008 ** CLK - pin 13
009 
010*/
011 
012#include <TinyGPS++.h>
013char p_buffer[100];
014#define P(str) (strcpy_P(p_buffer, PSTR(str)), p_buffer)
015 
016#define HOMELAT  42.614277
017#define HOMELNG -73.851662
018 
019#include <SoftwareSerial.h>
020 
021// The serial connection to the GPS module
022SoftwareSerial ss(4, 3);
023 
024// The TinyGPS++ object
025TinyGPSPlus gps;
026 
027// Line Buffer to Save to File
028char lnBuffer[115];
029 
030// Decimal to Number Char String Buffer
031char numStr[30];
032 
033// delay
034uint8_t prevSecond;
035 
036// data logger
037#include <SPI.h>
038#include <SD.h>
039 
040const uint8_t chipSelect = 10;
041 
042// location of previous location, used
043// to calculate distance traveled
044float prevLat = 0;
045float prevLng = 0;
046float prevAlt = 0; // stored in meters
047float prevSpeed = 0; // stored in meters per second
048float prevTime = 0;
049 
050// keep a running total of miles since last boot
051float milesSinceBoot = 0;
052 
053// filename
054char fileName[13];
055 
056// don't do anything if card is bad
057bool cardWorks = false;
058 
059void setup() {
060  Serial.begin(115200);
061  ss.begin(9600);
062  for (uint8_t i = 6; i < 9; i++) {
063    pinMode(i, OUTPUT);
064    digitalWrite(i, LOW);
065  }
066 
067 
068  // see if the card is present and can be initialized:
069  if (!SD.begin(chipSelect)) {
070    Serial.println(F("Card failed, or not present"));
071    digitalWrite(8, HIGH); //red
072    cardWorks = false;
073 
074    // don't do anything more:
075    return;
076  }
077 
078  cardWorks = true;
079  Serial.println(F("card initialized."));
080  digitalWrite(6, HIGH);  // green
081 
082  fileName[0] = '\0';
083}
084 
085void loop() {
086  if (!cardWorks) {
087 
088    return;
089  }
090 
091  while (ss.available() > 0) {
092    gps.encode(ss.read());
093  }
094 
095  // if no GPS blink red LED
096  if (millis() > 5000 && gps.charsProcessed() < 10 && millis() % 1000 == 0) {
097    digitalWrite(8, HIGH); //red
098  }
099  else if (millis() > 5000 && gps.charsProcessed() < 10 && millis() % 500 == 0) {
100    digitalWrite(8, LOW); // red
101  }
102 
103  // check if we have a valid location and blink yellow if invalid
104  if (gps.location.isValid()) {
105    digitalWrite(7, LOW);  // yellow
106  }
107  // next two lines will blink yellow (eye catching!)
108  else if (!gps.location.isValid() && millis() % 1000 == 0) {
109    digitalWrite(7, HIGH);  // yellow
110  }
111  else if (!gps.location.isValid() && millis() % 500 == 0) {
112    digitalWrite(7, LOW);  // yellow
113  }
114 
115  if (gps.location.isValid() && gps.time.second() != prevSecond) {
116 
117    // before we forget, log previous second
118    prevSecond = gps.time.second();
119 
120    // if no file name, create
121    if (fileName[0] == '\0') {
122      // create filename
123      // Example Filename = 03140201 (year=17, month=03, date=14, hour=02, tripnumber = 0
124      uint8_t trip = 1;
125      sprintf(fileName, P("%02d%02d%02d%02d.CSV"), gps.date.year() - 2000, gps.date.month(), gps.date.day(), trip);
126 
127      // well, if we have made 99 trips today (usually due to bad power connection) only write final trip
128      while (SD.exists(fileName) && trip < 99) {
129        trip++;
130        sprintf(fileName, P("%02d%02d%02d%02d.CSV"), gps.date.year() - 2000, gps.date.month(), gps.date.day(), trip);
131      }
132 
133      // print to serial where this data is being saved
134      Serial.print(P("Writing to ... "));
135      Serial.print(fileName);
136      Serial.print(P("\n"));
137 
138      // write header to file
139      File dataFileHead = SD.open(fileName, FILE_WRITE);
140 
141      // if not able to write, then turn LED red
142      if (!dataFileHead) {
143        digitalWrite(6, LOW);  // green
144        digitalWrite(8, HIGH); //red
145      }
146 
147      if (dataFileHead && trip != 99) {
148        dataFileHead.println(P("year,month,day,hour,minute,second,sat,latitude,longitude,elev,mph,dir,cdir,grade,accel,trip,mihm,dirhm"));
149        Serial.println( P("year,month,day,hour,minute,second,sat,latitude,longitude,elev,mph,dir,cdir,grade,accel,trip,mihm,dirhm"));
150        lnBuffer[0] = '\0';
151        dataFileHead.close();
152 
153        digitalWrite(6, HIGH);  // green
154        digitalWrite(8, LOW); //red
155      }
156 
157    }
158 
159    // dont log if no satellites found
160    if (!gps.satellites.value()) return;
161 
162    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());
163    strcat(lnBuffer, numStr);
164 
165 
166    dtostrf(gps.satellites.value(), 3, 0, numStr);
167    if (gps.satellites.isValid())
168      strcat(lnBuffer, numStr);
169    strcat(lnBuffer, P(", "));
170 
171 
172    dtostrf(gps.location.lat(), 10, 6, numStr);
173    if (gps.location.isValid())
174      strcat(lnBuffer, numStr);
175 
176    strcat(lnBuffer, P(", "));
177 
178 
179    dtostrf(gps.location.lng(), 10, 6, numStr);
180 
181    if (gps.location.isValid())
182      strcat(lnBuffer, numStr);
183 
184    strcat(lnBuffer, P(", "));
185 
186    if (gps.altitude.isValid())
187      dtostrf(gps.altitude.feet(), 5, 0, numStr);
188 
189    strcat(lnBuffer, numStr);
190 
191    // we only add the additional info if we have enough buffer space
192    // as occassionally before I was accidentially causing the buffer to
193    // overflow. In an idea world, I'd use a bigger buffer but RAM is limited
194    // e.g. if (strlen(lnBuffer) < 100)
195 
196    if (strlen(lnBuffer) < 100)
197      strcat(lnBuffer, P(", "));
198 
199    dtostrf(gps.speed.mph(), 0, 1, numStr);
200 
201    if (strlen(lnBuffer) < 100)
202      strcat(lnBuffer, numStr);
203 
204    if (strlen(lnBuffer) < 100)
205      strcat(lnBuffer, P(", "));
206 
207    dtostrf(gps.course.deg(), 0, 1, numStr);
208 
209    if (strlen(lnBuffer) < 100)
210      strcat(lnBuffer, numStr);
211 
212    if (strlen(lnBuffer) < 100)
213      strcat(lnBuffer, P(", "));
214 
215    if (strlen(lnBuffer) < 100)
216      strcat(lnBuffer, TinyGPSPlus::cardinal(gps.course.deg()));
217 
218    if (strlen(lnBuffer) < 100)
219      strcat(lnBuffer, P(", "));
220 
221    // calculate current grade -- if we have a change in altitude
222    // and we've traveled some kind of distance
223 
224    if (gps.altitude.isValid() && (gps.altitude.meters() - prevAlt) != 0 && TinyGPSPlus::distanceBetween(
225          gps.location.lat(),
226          gps.location.lng(),
227          prevLat,
228          prevLng) != 0) {
229 
230 
231      dtostrf(
232        (gps.altitude.meters() - prevAlt) /
233        TinyGPSPlus::distanceBetween(
234          gps.location.lat(),
235          gps.location.lng(),
236          prevLat,
237          prevLng)
238 
239        , 5, 2, numStr);
240 
241      if (strlen(lnBuffer) < 100)
242        strcat(lnBuffer, numStr);
243    }
244    else {
245      if (strlen(lnBuffer) < 100)
246        strcat(lnBuffer, P("0.00"));
247    }
248 
249    // acceleration
250    if (strlen(lnBuffer) < 100)
251      strcat(lnBuffer, P(", "));
252 
253    dtostrf((gps.speed.mps() - prevSpeed) / (millis() - prevTime), 7, 4, numStr);
254 
255    if (strlen(lnBuffer) < 100)
256      strcat(lnBuffer, numStr);
257 
258    if (strlen(lnBuffer) < 100)
259      strcat(lnBuffer, P(", "));
260 
261 
262 
263    // total milage of trip at this part of logging
264    // only increment when moving to minimize
265    // "idle" gps hop
266 
267    if (prevLat && gps.speed.mph() > 1) {
268      milesSinceBoot +=  TinyGPSPlus::distanceBetween(
269                           gps.location.lat(),
270                           gps.location.lng(),
271                           prevLat,
272                           prevLng) * 0.00062137112; // meters to miles
273    }
274 
275    dtostrf( milesSinceBoot, 5, 2, numStr);
276 
277    if (strlen(lnBuffer) < 100)
278      strcat(lnBuffer, numStr);
279 
280    if (strlen(lnBuffer) < 100)
281      strcat(lnBuffer, P(", "));
282 
283    // miles from home
284    dtostrf( TinyGPSPlus::distanceBetween(
285               gps.location.lat(),
286               gps.location.lng(),
287               HOMELAT, HOMELNG) * 0.00062137112, 5, 2, numStr);
288 
289    if (strlen(lnBuffer) < 105)
290      strcat(lnBuffer, numStr);
291 
292    // direction from home (for shits and giggles)
293 
294    if (strlen(lnBuffer) < 105)
295      strcat(lnBuffer, P(", "));
296 
297    if (strlen(lnBuffer) < 110)
298      strcat(lnBuffer,     TinyGPSPlus::cardinal(TinyGPSPlus::courseTo(
299               HOMELAT, HOMELNG,
300               gps.location.lat(),
301               gps.location.lng()
302             )));
303 
304 
305    // save previous lat/lng/alt
306    prevLat = gps.location.lat();
307    prevLng = gps.location.lng();
308    prevAlt = gps.altitude.meters();
309    prevSpeed = gps.speed.mps();
310    prevTime = millis();
311 
312    File dataFile = SD.open(fileName, FILE_WRITE);
313 
314    if (dataFile) {
315      dataFile.println(lnBuffer);
316      dataFile.close();
317 
318      // print to the serial port too:
319      Serial.println(lnBuffer);
320      digitalWrite(6, HIGH);  // green
321      digitalWrite(8, LOW); //red
322    }
323    // if the file isn't open, pop up an error:
324    else {
325      Serial.print(F("error opening "));
326      Serial.print(fileName);
327      Serial.print("\n");
328 
329      digitalWrite(6, LOW);  // green
330      digitalWrite(8, HIGH); //red
331 
332    }
333 
334    // clear buffer
335    lnBuffer[0] = '\0';
336 
337  }
338}

Leave a Reply

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