Introduction: Solar Powered GPS Hiking Logger
The concept here is simple, I want to be able to log where I go on my walks so that after my walk I can see where I have been. In the past I have used GPS on my phone, but when going on an all day (8 hour) hike, by the end of the day my phone is flat and I cannot even make phone calls.
I have been given a neat 5W 5V (so 1A) solar panels, so I was thinking that I could power a little Arduino with a standard GPS module.
Step 1: The Arduino and Code
I have a CAN-BUS shield (from when my car was having engine problems and I tried to do my own diagnostics) and noticed it has a EM-406 socket to plug in a standard GPS module. I ordered a GPS module from ebay (all GPS modules EM-406 socket seem to be the same) and plugged in a micro SD card into the SD socket on the shield.
To make the GPS logging easy I found a most excellent library called TinyGPS++ which means I don't need to spend my time understanding the packets sent from the GPS module!
Using linux tools such as GPS babel or online tools such as GPS Visualizer the data can be converted between most standard formats, so I thought I would stick with CSV so that I could open it up excel or matlab, but can still easy convert to kml to view in Google Earth.
I have included the source code I used below, I have left the serial dumping stuff in for debugging purposes (so you can see your location from your laptop immediately).
The LED's built into the shield are used to indicate when the board is logging, and the other for when the GPS is locked.
#include <SPI.h> #include <SD.h> #include <TinyGPS++.h> #include <SoftwareSerial.h> const int LED1 = 7; const int LED2 = 8; const int chipSelect = 9; const int RXPin = 4; const int TXPin = 5; int GPSBaud = 4800; TinyGPSPlus gps; SoftwareSerial gpsSerial(RXPin, TXPin); void setup() { Serial.begin(9600); gpsSerial.begin(GPSBaud); pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(chipSelect, OUTPUT); if (!SD.begin(chipSelect)) digitalWrite(LED1, LOW); else { Serial.println("SD Card Setup"); digitalWrite(LED1, HIGH); } } void loop() { while (gpsSerial.available() > 0) { if (gps.encode(gpsSerial.read())) { if (gps.location.isValid() && gps.time.isValid() && gps.date.isValid()) digitalWrite(LED2, HIGH); else digitalWrite(LED2, LOW); logInfo(); displayInfo(); } } } void logInfo() { if (gps.location.isValid() && gps.time.isValid() && gps.date.isValid()) { File dataFile = SD.open("gpslog.txt", FILE_WRITE); if (dataFile) { digitalWrite(LED1, HIGH); dataFile.print(gps.date.day()); dataFile.print(F("/")); dataFile.print(gps.date.month()); dataFile.print(F("/")); dataFile.print(gps.date.year()); dataFile.print(F(",")); if (gps.time.hour() < 10) dataFile.print(F("0")); dataFile.print(gps.time.hour()); dataFile.print(F(":")); if (gps.time.minute() < 10) dataFile.print(F("0")); dataFile.print(gps.time.minute()); dataFile.print(F(":")); if (gps.time.second() < 10) dataFile.print(F("0")); dataFile.print(gps.time.second()); dataFile.print(F(".")); if (gps.time.centisecond() < 10) dataFile.print(F("0")); dataFile.print(gps.time.centisecond()); dataFile.print(F(",")); dataFile.print(gps.location.lat(), 6); dataFile.print(F(",")); dataFile.print(gps.location.lng(), 6); dataFile.println(); dataFile.close(); } // if the file isn't open, pop up an error: else { digitalWrite(LED1, HIGH); Serial.println("error opening datalog.txt"); } } } void displayInfo() { Serial.print(F("Location: ")); if (gps.location.isValid()) { Serial.print(gps.location.lat(), 6); Serial.print(F(",")); Serial.print(gps.location.lng(), 6); } else { Serial.print(F("INVALID")); } Serial.print(F(" Date/Time: ")); if (gps.date.isValid()) { Serial.print(gps.date.day()); Serial.print(F("/")); Serial.print(gps.date.month()); Serial.print(F("/")); Serial.print(gps.date.year()); } else { Serial.print(F("INVALID")); } Serial.print(F(" ")); if (gps.time.isValid()) { if (gps.time.hour() < 10) Serial.print(F("0")); Serial.print(gps.time.hour()); Serial.print(F(":")); if (gps.time.minute() < 10) Serial.print(F("0")); Serial.print(gps.time.minute()); Serial.print(F(":")); if (gps.time.second() < 10) Serial.print(F("0")); Serial.print(gps.time.second()); Serial.print(F(".")); if (gps.time.centisecond() < 10) Serial.print(F("0")); Serial.print(gps.time.centisecond()); } else { Serial.print(F("INVALID")); } Serial.println(); }
Step 2: Testing
Now, because I am a bit of a night owl, there is not much daylight in my hackspace, so for testing I connected the solar panel up using a standard USB connector and held a light over the panel so that I can at least power up the Arduino. It just about worked but would probably be best during daylight hours.
Step 3: Mounting to the Bag
I have a 5.11 tactical Rush 24 rucksack that I use typically when I am going on my hikes, and fortunately it has a mounting standard called MOLLE for attaching their pouches. Essentially this means the backpack is covered in 1 inch loops which you can thread things through without damaging the bag. So, to attach the solar panel I used some cable ties which means they are semi permanently attached without damaging my bag.
Step 4: Hiding the Electronics
The bag has a camera pouch as the top next to the handle, which has a nice felt lining to protect the camera, so it would work well to protect the Arduino electronics. I mounted the USB connector towards the top of the bag so that the cable run was very short and neat (no cables to tidy away).
Step 5: The Finished Bag
So, here it is, only a small blue USB cable which can be plugged in and unplugged whenever it is needed or not needed. The panel is very secure, and I have even tweeked it some more with a set of reusable/resealable cable ties so that I can take the whole panel on/off when I don't need to log.