Introduction: Geo Data Logger: Arduino+GPS+SD+Accelerometer to Log, Time-stamp, and Geo-tag Sensor Data



I thought it would be educational to build a prototype that I can take on the road to log, geo-tag, and time-stamp sensor data to be analyzed later with mapping and/or data analysis applications.  So I figured why not start with a gadget that can log road conditions. This prototype, the Bump-O-Meter, measures road conditions by using an Arduino, a GPS receiver, an SD card, and an accelerometer sensor.

This prototype is a generic sensor logging/geo-tagging gadget which means the accelerometer can be replaced with any other sensor(s) to log and map anything anywhere.  

As a matter or fact my next adventure with this logger is to replace the accelerometer with a pollution sensor to visualize levels of air quality around town. 


This guide is divided into the following sections:
  1. Overview & Background
  2. Hardware & Software Components
  3. Wiring the Prototype
  4. Logging data to the LC STUDIO SD Card
  5. Geo-Tagging & Time-Stamping With the LS20031 GPS Receiver
  6. Measuring Road Condition with an ADXL335 Accelerometer
  7. PROGRAM: The Arduino Program That Pulls It All Together
  8. PROGRAM: A Plain GPS Logger To Interface With Google Earth
  9. Scrubbing & Formatting Data with a Spreadsheet
  10. Plotting and Color-coding Road Condition Data with
  11. Formatting GPS Date/time Output For Stamping Data
  12. Speed vs. Logging Accuracy


The Bump-O-Meter uses an Arduino to capture the X,Y,Z motion data generated by the ADXL335 accelerometer. In this case, we are measuring road "shakiness" as a result of road condition. Poor road conditions and uneven road surfaces generate lots of sudden acceleration in the car body up and down (z-axis). But before this data is saved to the SD card, it's tagged with location information from the LS20031 GPS receiver and also date/time stamped in real-time using the GPS satellites' atomic clock. More on this later.

We want to capture and analyze the z-axis acceleration information visually to determine which road stretches are poorer and need attention. We can repeat this and compare our data over time. The possibilities are endless. Not just for road condition scanning, but for any sort of environmental geo data logging.  


We can use this gadget by placing it in a car and driving over a given road stretch to assess its condition.  We can even attach this prototype to a bike or skateboard to identify irregular and rough stretches of tracks.

We can substitute the ADXL335 accelerometer sensor with any other sensor(s) such as temperature or pollution sensors with simple code modification.

The data on the SD card can then be imported it into a spreadsheet for scrubbing, sub-setting, reformatting, analysis, and visualizing.

We will also make use of a wonderful website to plot our data over a map using intelligent markers that change shape and color according to magnitude of road shakiness so we can visually detect road conditions in need of further inspection.

I have published a guide titled "Connect your LS20031 GPS receiver to Google Earth via PC" explaining how to configure the LS20031 GPS receiver.  You can refer to it for more details on how to use the LS20031 GPS receiver.


  • Arduino Uno or Leonardo*:  $25 (,
  • LS20031 GPS receiver: $50 (Ebay, Pololu, Adafruit, Sparkfun)
  • ADXL335 or ADXL345 Accelerometer (or any other sensor): $7 (
  • SN74AHC125 as level shifter from 5V to 3.3V**: $1 (,
  • SD reader socket. The LC STUDIO: $2.50 (
  • SD memory card.  $5 for 4GB. 
  • LED: $0.1
  • Resistor 1K Ohm: $0.1
  • Breadboard: $5
  • Jumper wires: $2
  • Male headers 2.45mm (0.1") -  straight and right angle: $1 (
  • Any battery or power source that can provide 7-12V and a minimum of 500mA.

* I have not tried this prototype with the Arduino Leonardo because of some known issues with the SD library . But according to the release notes of the  Arduino IDE 1.02 software these issues have been addressed.

** In the future, I am phasing out the SN74AHC125 level-shifter (5V to 3.3V converter) in favor of the CD4050BE HEX Non-Inverting Buffer/Converter simply because it's more readily and cheaply available on  I purchased 10 ICs for $4.0. That's $0.4 per IC. The CD4050 is not pin compatible with the SN74AHC125 but there are plenty of examples on the net.

  • Arduino IDE 1.02 
  • MiniGPS 1.4: This is a nifty utility to configure the LS20031 GPS receiver.
  • This amazing website will help us plot logged sensor data along with the GPS coordinates using color schemes to indicate road conditions.
  • MS Excel or comparable spreadsheet: We will use a spreadsheet to scrub the logged data, to remove any garbage, to make sub-selections of our logged, and to format it in a manner that can be read by other applications and websites such as and Google Earth.
  • SD Arduino library (bundled with Arduino IDE)


This is a prototype and prototypes by definition are drafts of products not finished yet. Your feedback is appreciated.

Hazim Bitar (techbitar)
techbitar at gmail dot com

Step 1: Wiring the Geo-logger


GND                   GND rail of the breadboard (usually the blue row)
5V                      To 5V VIN of the SD card
3.3V                   To the positive rail (red-lined row) of the breadboard
PIN13                 PIN5 (2A) of the SN74AHC125 IC
PIN12                 SD MISO PIN
PIN11                 PIN2 (1A) of the SN74AHC125 IC
PIN8                   LED POSITIVE
PIN4                   PIN12 (4A) of the SN74AHC125 IC
PIN1(TX)            PIN9 (3A) of the SN74AHC125 IC
PIN0(RX)            PIN TX of the LS20031 GPS Receiver
ANALOG0          PIN X of the ADXL335 (or any analog sensor output)
ANALOG1          PIN Y of the ADXL335 (or any analog sensor output)
ANALOG2          PIN Z of the ADXL335 (or any analog sensor output)
GND (bottom)    GND rail bottom of the breadboard


PIN1 (10E)          GND rail of breadboard
PIN2 (1A)            Arduino PIN11
PIN3 (1Y)            SD MOSI PIN
PIN4 (20E)         GND rail of breadboard
PIN5 (2A)            Arduino PIN13
PIN6 (2Y)            SD SCK PIN
PIN7 GND          GND rail of breadboard
PIN9 (3A)           Arduino TX PIN1
PIN8 (3Y)            GPS RX PIN
PIN10 (30E)       GND rail of breadboard
PIN12 (4A)         Arduino PIN4
PIN11 (4Y)         SD CS PIN
PIN13 (40E)      GND rail of breadboard
PIN14 (VCC)     Arduino 3.3V pin


GND                 GND rail of breadboard
3.3V                 No connection
5V                    Arduino 5V pin
CS                    PIN11 (4Y) of the SN74AHC125 IC
MOSI                PIN3 (1Y) of the SN74AHC125 IC
SCK                 PIN6 (2Y) of the SN74AHC125 IC
MISO               Arduino PIN12
GND                GND rail of breadboard


GND               GND rail of breadboard
GND               GND rail of breadboard
TX                   Arduino PIN0 (RX)
RX                  PIN8 (3Y) of the SN74AHC125 IC
VCC               3.3V rail of the breadboard


GND               GND rail of breadboard
Z                     Arduino ANALOG2
Y                     Arduino ANALOG1
X                    Arduino ANALOG0
3.3V              3.3V rail of breadboard
ST                  No connection.

Step 2: The SD Card


The SD card, or Secure Digital card, is a non-volatile solid-state flash memory. Meaning if we disconnect power, it will retain its data.  With an SD card we can expand Arduino's permanent storage by gigabytes.  This is useful for applications that store large amounts of data such as data loggers. A 4GB SD card can be had for only $5. 


The LC STUDIO SD card socket used in this project can be powered with 5V or 3.3V power sources. There is an LM1117 3.3V regulator on board which can handle 800mA of current. The Arduino can provide 3.3V directly but it's limited to 50mA. That's not enough to power the SD card. So I powered the SD card socket from the Arduino Uno's 5V pin which can handle over 500mA of current. The 5V pin on the SD card socket will pass through the LM1117 regulator and come out a 3.3V with a current ceiling of 800mAh. 

Just because this SD card socket can be powered with 5V or 3.3V, we still can't connect 5V Arduino pins to the SD card socket's pins.  We have to level-shift the Arduino's 5V signals to 3.3V before we can connect them to the SD card.

This is where the SN74AHC125 IC comes in handy. This IC can convert (level-shift) a total of 4 signals from 5V to 3.3V.  This is perfect because for this project, I only need to convert 4 Arduino pins from 5V to 3.3V: three to the SD card socket and one to the LGS20031 GPS receiver which is also a 3.3V module. 


You can replace the SN74AHC125 with the more available CD4050. I recently bought 10 of those from Ebay for about $0.40 a piece. The CD4050 is not pin compatible with the SN74AHC125 but it's easy to use. You will find many useful wiring examples for the CD4050 on the web.


The Arduino IDE comes bundled with an SD library that's easy to use.  You can include the SD library in your Arduino program by selecting from the main menu: Sketch\Import Library\SD

The library also comes with ready to use example programs to get you up and running. You can open those example programs from main menu: File\Examples\SD then pick any of the 6 example sketches. If you have the SD card socket connected and an SD card inserted, those examples will work on the spot. 

For this prototype, I am using an old XTREME MiniSD 1GB SD1 card with a standard SD adapter simply because I have one available. I did not run into any performance issues with this class and model. Most memory cards sold today are the faster SDHC variety. 


Since the SD card socket has no LED indicators, I have added a status LED wired to Arduino PIN8, via a 1K Ohms resistor in series. This LED stays on so long as the SD card is working properly. I wrote the Arduino code so that when a write or read of the SD card fails, the LED is turned off.  This way we can just look at the prototype and tell if something is wrong, along with other Arduino and GPS receiver LED indicators.


Using my Windows 7 computer I fully formatted the SD card as FAT16 once. Then, I quick format the SD card after every trial just to be on the safe side. 



I am using the LS20031 GPS receiver in this prototype to tag logged data with both geographic location and date/time stamp. The LS20031 is a bread and butter GPS receiver. It's very simple to operate. This receiver is made by LOCOSYS Technology. I have attached the LS20031 datasheet to this section for those interested in more detailed specifications. 
  • Model: LS20031
  • Chip: MediaTek MT3329
  • Voltage: 3.3V
  • Frequency: L1 1575.42MHz, C/A code
  • Channels: Support 66 channels (22 Tracking, 66 Acquisition)
  • Update rate: 1Hz default, up to 10Hz
  • Hot start: (Open Sky) < 2 seconds (typical)
  • Acquisition Time: Cold Start (Open Sky) 35 second  (typical)
  • Autonomous 3m (2D RMS)
  • Position Accuracy: SBAS 2.5m (depends on accuracy of correction data)
  • Datum: WGS-84 (default)
  • Max. Operating Altitude: < 18 Km
  • Max. Operating Velocity: < 515 m/s

When the GPS receiver is powered up, it will start transmitting information via it serial (TX) pin in the form of standardized comma-delimited text lines. These standardized text messages are called NMEA sentences containing latitude, longitude, date/time, among other useful data. 

NMEA stands for National Marine Electronics Association. This is the industry body that comes up with standardized message formats for GPS receivers to simplify using this technology. 

NMEA sentences start with GP + a three-letter identifier that tells us what sort of data is contained in this NMEA sentence being transmitted by the GPS receiver.

The LS20031 sends out the following NMEA sentences.
  • GGA Global positioning system fixed data
  • GLL Geographic position - latitude/longitude
  • GSA GNSS DOP and active satellites
  • GSV GNSS satellites in view
  • RMC Recommended minimum specific GNSS data
  • VTG Course over ground and ground speed
The one I find useful for this project is the RMC ($GPRMC). Here's a sample RMC sentence and an explanation of each element:

  • Message ID: $GPRMC RMC protocol header
  • UTC Time: 053740.000 hhmmss.sss
  • Status A: A=data valid or V=data not valid
  • Latitude: 2503.6319 ddmm.mmmm
  • N/S: Indicator N N=north or S=south
  • Longitude: 12136.0099 dddmm.mmmm
  • E/W Indicator: E E=east or W=west
  • Speed over ground: 2.69 knots True
  • Course over ground: 79.65 degrees
  • Date: 100106 ddmmyy
  • Magnetic variation: degrees
  • Variation sense: E=east or W=west (Not shown)
  • Mode A: A=autonomous, D=DGPS, E=DR
  • Checksum: *53
  • End of message termination


I mentioned earlier that I had published a guide to help configure the LS20031 GPS receiver. The LS20031 is a 3.3V module which means it's powered by a 3.3V source. This also means we cannot connect the Arduino output pins, such as the TX pin (5V), to the LS20031 RX pin (3.3V) without converting from 5V to 3.3V.

In this prototype, I use the SN74AHC125 as level-shifter from 5V to 3.3V. We should be able to take the LS20031 GPS serial output pin, the TX pin (3.3V), and wire it directly to the Arduino's serial RX receive PIN1 (5V). The Arduino's 5V pins can handle a 3.3V signal and will treat it as a logical high.


For this prototype I used MiniGPS 1.4 to configure the LS20031 GPS receiver as follow:
  • Baud rate: 4800
  • Fix Update Rate: 5/sec
  • NMEA outputs: RMC output set to 1 while all other NMEA outputs set to zero (0). At 5Hz, this means 5 RMC messages per second. 
I know this may sound confusing to some of you but please stick to my settings. Once you get your prototype up and running you can change the parameters. 


The ADXL335 is a 3-axis analog acceleration measurement sensor. That's a mouthful. Basically, this gizmo can detect speed of movement, also known as g-force, in three directions: up/down (z), forward/backward (x), and sideways (y). The axis directions change depending on how we position the sensor IC. 

The ADXL335 has a measurement range of ±3 g minimum for each axis. When you are standing still, the earth exerts a gravitation force of 1g.  This sensor outputs signals in the form of voltage changes ranging from 0 to 3.3V.  At zero gravity, the voltage value of the Z pin is right in the middle between 0V and 3.3V = 1.65V.

The accelerometer can measure the static acceleration of gravity (1g) as well as tilt-sensing applications and also dynamic acceleration resulting from motion, shock, or vibration.  Which axis of the ADXL335 reports 1g is dependent on how you position the chip.


I drive a Toyota Yaris, a good car as far as reliability and fuel economy but not known for its luxury suspension system. This is perfect for my purposes. A high-end suspension system may dampen road bumpiness possibly generating weaker and inconclusive ADXL335 sensor readings.


This particular ADXL335 breakout board must be powered by a 3.3V source. It's also configured to provide updates 50 times per second.  That's plenty of resolution for our road condition sensing device.

Since the Arduino Uno can handle reading 3.3V signals without conversion, we can wire the ADXL335's  X,Y,Z outputs pins (3.3V) to  Arduino Uno's analog input pins (5V) directly.



This program reads the LS20031 GPS receiver and saves the NMEA sentences generated by the receiver as-is to the SD card.  The program also reads the X, Y, Z pins of the ADXL335 accelerometer and saves them with each NMEA line saved.

The Arduino program I developed for this prototype uses the SD library. I am not using TinyGPS to interact with the GPS receiver or SoftwareSerial.  I did not need TinyGPS for this project since I am saving raw NMEA messages to the SD card. As for the SoftwareSerial library, after I ran into a few issues which were time consuming to resolve I decided to stick to the default Arduino serial library. 

The downside of not using SoftwareSerial in this project is that the GPS Receiver will be using the Arduino's RX/TX pins to read configuration commands and to send GPS data to the Arduino.  This means we don't have the Arduino Serial Monitor available for debugging.

More importantly, we will have to disconnect the Arduino Uno's PIN0 (RX) from the GPS receiver's TX pin before uploading an Arduino program. If we don't disconnect Arduino's PIN0 (RX) from the GPS receiver, it will most likely fail to upload the Arduino program from the PC to the Arduino because of serial conflict. I found this to be a small price for the gains in coding compactness and shortened development cycle.

The data saved by this program to the SD will look like the list below. Theoretically, five lines of GPS and sensor data will be generated per second. This log can be imported as a comma-delimited file into a host of applications such as spreadsheets or databases for scrubbing, analysis, and charting:

  • 446,425,542,GPRMC,093116.200,A,3158.0155,N,03551.5032,E,18.78,291.56,111112,,,A*54
  • 443,442,542,GPRMC,093116.400,A,3158.0159,N,03551.5020,E,18.78,291.79,111112,,,A*50
  • 444,435,523,GPRMC,093116.600,A,3158.0163,N,03551.5009,E,18.77,292.32,111112,,,A*53
  • 444,432,525,PRMC,093116.800,A,3158.0167,N,03551.4998,E,18.75,292.88,111112,,,A*5A

// ====================== START PROGRAM ==========================

PROJECT: Bump-O-Meter (Geo Data Logger for Sensors )

DEVELOPER:  Hazim Bitar (techbitar at gmail dot com)

DESCRIPTION:  This program reads the ADXL335 accelerometer sensor data (X,Y,Z)  or any
sensor data then saves   this data to an SD card along with geo-location and a date/time stamp
generated by the LS20031 GPS receiver

LICENSE:      I am placing this code in the public domain

DATE:         NOV 16, 2012


#define LED 8           // status LED for SD operations
#define BUFF_MAX 100   // size of GPS & SD buffers

File GPSlog;

void setup()
  Serial.begin(4800); // The LS20031 GPS receiver must be set to 4800 for program to work

  // You can use the statements below to send configuration commands to the LS20031 GPS.
  // But for this to work, the baud rate must be set on the LS20031 GPS receiver to 4800.
  // You can use the MiniGPS 1.4 utility to configure or query the LS20031 GPS receiver.
  // LS20031 COMMANDS:
  // Serial.print("$PMTK251,4800*27\r\n");  // Set GPS baud rate
  // Serial.print("$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*2C\r\n"); // Set RMC to 5 fixes/second. 
  // Serial.print("$PMTK220,200*2C\r\n");  // GPS update rate at 5Hz
  pinMode(10, OUTPUT);   // Per SD library notes, pin 10 must be set to output
  pinMode(LED, OUTPUT);

  if (!SD.begin(4)) {        // SD card detected?
    digitalWrite(LED,LOW);   // turn off status LED if SD detection fails
  else   digitalWrite(LED, HIGH); // turn on LED if SD detection is OK

  GPSlog ="GPS.log", O_CREAT | O_WRITE);  // open/append to a file GPS.log
  if (!GPSlog) {               // test if file can be opened
    digitalWrite(LED,LOW);     // turn off status LED if file open fails
  else digitalWrite(LED, HIGH);  // turn on status LED if file open is OK

void loop()
  char inBuffer[BUFF_MAX];    // buffer used to read NMEA lines from GPS
  byte outBuffer[BUFF_MAX];   // buffer used to write NMEA lines to SD card
  int sizeBuffer = 0;        // counter of how many chars per line

  char an0[4], an1[4], an2[4];  // char variables to store analog pin values. Total 6 pins from 0-5

  while (Serial.available()>0)  // if serial data available from GPS
    sizeBuffer = Serial.readBytesUntil('\n', inBuffer, BUFF_MAX);  // read one NMEA line from GPS until end of line

    itoa (analogRead(A0),  an0, 10);    // X read and convert numeric analog pin to char
    itoa (analogRead(A1),  an1, 10);    // Y  ..
    itoa (analogRead(A2),  an2, 10);    // Z  ..
    for (int i = 0; i < BUFF_MAX; i++) outBuffer[i] = inBuffer[i];   // create CSV file on SD 
    int j = 0;

    if (GPSlog) {
      GPSlog.print(an0);    // write ANALOG0 (X) to SD
      GPSlog.print(" , ");      
      GPSlog.print(an1);    // write ANALOG1 (Y) to SD     
      GPSlog.print(" , ");      
      GPSlog.print(an2);    // write ANALOG2 (Z) to SD
      GPSlog.print(" , ");     
      // If you only want NMEA output logged, comment out all above GPSlog.print statements
      GPSlog.write(outBuffer, sizeBuffer);  // write GPS NMEA output to SD
      digitalWrite(LED, HIGH);  // Keep LED on so long as SD logging is working.
    else {
      // if the file didn't open, turn LED off
      digitalWrite(LED, LOW);  // turn LED off if writing to file fails
// ================ END PROGRAM =====================


This program will read up to 6 analog sensors and save their values to the SD card. There are two places in the program where you need to make changes to suit your needs:


In the declaration section, we create text variables that will hold the converted numeric values of the sensors before we write them to the SD card.  Here, we are declaring for a maximum of 6 analog sensors. Reduce as needed. 

char an0[4], an1[4], an2[4]; an3[4]; an4[4]; an5[4];


In this part of the program, we convert the numeric sensor readings to text before we write them to the SD card. Change the next code segment in the program to add/remove sensors as needed. You can have up to 6 analog sensors read in this program:

    itoa (analogRead(A0),  an0, 10);   
    itoa (analogRead(A1),  an1, 10);  
    itoa (analogRead(A2),  an2, 10); 
    itoa (analogRead(A3),  an0, 10);  
    itoa (analogRead(A4),  an1, 10); 
    itoa (analogRead(A5),  an2, 10);


After we read the sensor(s) above, we write their text values to the SD card. In the code segment below, we are adding a comma between each sensor value written to the SD card so we can separate them. This makes it easier to import them into a spreadsheet program as comma-delimited  text:

      GPSlog.print(an0);    // write ANALOG0 to SD card
      GPSlog.print(" , ");    
      GPSlog.print(an1);    // write ANALOG1 to SD card
      GPSlog.print(" , ");    
      GPSlog.print(an2);    // write ANALOG2 to SD card
      GPSlog.print(" , ");
      GPSlog.print(an0);    // write ANALOG3 to SD card
      GPSlog.print(" , ");   
      GPSlog.print(an1);    // write ANALOG4 to SD card
      GPSlog.print(" , ");   
      GPSlog.print(an2);    // write ANALOG5 to SD card
      GPSlog.print(" , ");


For those who want to use this prototype as a generic GPS logger, to track your path, just upload the Arduino code below. This program will generate raw NMEA RMC sentences to file GPS.LOG on the SD card without any sensor data.

We can then Import the GPS.LOG file into Google Earth and generate maps overlaid with your logged track points.  Please refer to my LS20031 GPS tutorial on how to import a raw GPS NMEA log files into Google Earth. 

You can also import this NMEA log file into Excel as a comma-delimited text file and reformat it for to draw maps with track points and more.  More on this in the next sections. 

// ================ START PROGRAM =====================


PROJECT: A Plain GPS Logger

DEVELOPER:  Hazim Bitar (techbitar at gmail dot com)

DESCRIPTION:  This program logs GPS location information wherever you go and saves to the SD card as raw NMEA data to be imported into Google Earth. 

LICENSE:      I am placing this code in the public domain

DATE:         NOV 17, 2012

#include <SD.h>
#define LED 8           // status LED for SD operations
#define BUFF_MAX 100    // size of GPS & SD buffers

File GPSlog;

void setup()
  Serial.begin(4800); // The LS20031 GPS receiver must be set to 4800 for program to work

  pinMode(10, OUTPUT);   // Per SD library notes, pin 10 must be set to output
  pinMode(LED, OUTPUT);

  if (!SD.begin(4)) {        // SD card detected?
    digitalWrite(LED,LOW);   // turn off staus LED if SD detection fails
  else   digitalWrite(LED, HIGH); // turn on LED if SD detection is OK

  GPSlog ="GPS.log", O_CREAT | O_WRITE);  // open/append to a file GPS.log
  if (!GPSlog) {               // test if file can be opened
    digitalWrite(LED,LOW);     // turn off status LED if file open fails
  else digitalWrite(LED, HIGH);  // turn on status LED if file open is OK

void loop()
  char inBuffer[BUFF_MAX];    // buffer used to read NMEA lines from GPS
  byte outBuffer[BUFF_MAX];   // buffer used to write NMEA lines to SD card
  int sizeBuffer = 0;        // counter of how many chars per line

  while (Serial.available()>0)  // if serial data available from GPS
    sizeBuffer = Serial.readBytesUntil('\n', inBuffer, BUFF_MAX);  // read one NMEA line from GPS until end of line
    for (int i = 0; i < BUFF_MAX; i++) outBuffer[i] = inBuffer[i];   // create CSV file on SD
    int j = 0;
    if (GPSlog) {
      GPSlog.write(outBuffer, sizeBuffer);  // write GPS NMEA output to SD
      digitalWrite(LED, HIGH);  // Keep LED on so long as SD logging is working.
    else {
      // if the file didn't open, turn LED off
      digitalWrite(LED, LOW);  // turn LED off if writing to file fails
// ================ END PROGRAM =====================


With enough road data captured on the SD card, we now start the data scrubbing and re-formatting in preparation for analysis and visualization in Excel, GPSvisualizer, or our favorite data analysis and charting tool. 

Remove the SD card from the socket and insert into PC SD card reader. Copy the GPS.log file to your PC and Run Excel (or your favorite spreadsheet application). The steps below are for Excel 2007
  • STEP 1: From Excel, File/Open and select GPS.log. Make sure you select File Type All Files (*.*) else you will not see the file GPS.log listed. Open file. This will launch the Text Import Wizard.
  • STEP 2: Select Delimited radio button. Click Next.
  • STEP 3: Select Comma check box only. Cick Next.
  • SETP 4: Excel will import the GPS.log file into columns and rows. The columns are ordered  in this manner: X, Y, Z, NMEA output type, UTC Time, Status A: A=data valid or V=data not valid, Latitude, N/S: Indicator N N=north or S=south, Longitude, E/W Indicator: E E=east or W=west, Speed over ground, Course over ground, Date, Magnetic variation, Variation sense: E=east or W=west, Mode A: A=autonomous, D=DGPS, E=DR, Checksum.
  • STEP 5,6: In column 'F' you will see one letter either A or V. A means valid fix. V means invalid data. So delete all rows that are invalid.
  • STEP 7: Also, delete jumbled lines. 
  • STEP 8: Keep columns C (z-axis), G (Latitude), and I (Longitude) but hide other imported columns. 
  • STEP 9: Add header labels to the top of the remaining three columns: N, Latitude,  Longitude.
  • STEP 10: Now select and copy to clipboard the range of rows you wish to map in GPSvisualizer and don't forget to also copy the columns header labels. 
With the selected data in the clipboard, we are ready to paste it into GPSvisualizer so we can map and analyze our logged data.


First, let's open GPSvisualizer and open the "Plot data points" page:

STEP 1: Find the scroll box titled "Or paste your data here" and delete everything in it then paste the data you have copied from Excel into it. You should get a clean three column content with the headers N Latitude Longitude. Make sure you don't change the headers in any way after you paste them and don't add commas or tabs in between. Just a straight paste from Excel.  

STEP 2:  You can skip this step for now or you can make changes to "Data point options" to follow my settings as shown in the figure. 

: Click "Draw the map" button and watch the magic. 


A Google Map will be displayed and overlaid with the route points captured by our geo data logger. In my case, I have selected stars as the icons for the data points. The larger and more blueish the data point or the smaller the more reddish the bigger the road bump or pothole. 

By clicking on a star, a balloon will pop up with the z-axis value read by the ADXL335 accelerometer.

Long road stretches of comparable greenish colors and values (typically 520 in my case) mean the road is smoother.

We can change the icon shapes, their minimum and maximum sizes, and other parameters from the "Data point options" section.


I have simplified this part so almost no math will be needed to assess road conditions using the data generated by the ADXL335 sensor.  So there will be no translation from raw accelerometer sensor outputs to g values.

The whole trick wrests in road condition profiling and sensor data comparison. 


Different geo data loggers may produce different readings than mine for various reasons having to do with sensor type if a different accelerometer is used, suspension system differences from one car to another, orientation of the geo data logger, etc. So we need to profile normal road conditions and abnormal road condition before we can make sense of our data using your geo data logger in your particular environment.

Profiling road conditions is simple. We record senor data generated by the ADXL335 sensor while  we drive over a good road stretch then do the same with sensor data generated when we drive over a rough road stretch such a bump or pothole.

In my case, I get an average of 520 for the z-axis on a good road stretch. I can use this as a frame of reference so if I get sample data of 520 plus or minus a few notches (you decide what's the acceptable range) then this is a good road. So 520 +/- some value of your choosing is the profile of a good road condition. But if I drive over a bump or pothole, I get sensor z-axis readings that hover around 500 on the low end and 535 on the high end. This will be my profile of a rough road.

The basic assumption here is that I am using the same car, with the sensor placed in the same spot in the car, and driving at the same speed every time I profile the road with my geo data logger.

In the "Data point options" by assigning the "Min" color field my my lower z-axis number and "Max" field my high z-axis number, now I can use to determine visually, by color or size of marker, where to find poor road stretches, potholes, and bumps.


When it comes to analyzing the sensor data, sometimes bumps my look like potholes and vice versa. It's possible to log what seems like a pothole condition when in reality we are just dropping back to normal street level right after a road bump.  It's also possible to get a sensor reading the resembles that of a bump when the car starts climbing out of the pothole.

We look for small or large z-axis readings, based on the min/max values withing the range of captured data,  to identify abnormal road conditions. But classifying these road conditions might require more analysis. We can always play around with GPSvisualizer settings until we get the visual representation we need.

The important thing is to record presence of a road condition in need of attention or to avoid it next time you are on the same road.


Since time-stamping logged data is important for many projects, I will explain how to extract and format the GPS generated time/date data.

In this project, we hid all data columns in Excel except columns containing z-axis data, latitude, and longitude. If we wish to keep a date/time stamp to map and visualize along with the rest of the retained sensor and GPS data columns, we simply don't hide column E (time) and column M (date). 

The LS20031 GPS receiver, as with other GPS receivers of its class, updates its internal clock to sync with the GPS satellites' internal atomic clock which is accurate to 1 billionth of a second. 

The GPS receiver sends date/time stamped location fixes via a variety of NMEA text sentences.  We have chosen the RMC NMEA message for this project.  This is how an RMC sentence looks like. 


The boldfaced number from the left end of the NMEA sentence is the UTC Time. It's interpreted according to this format string: hhmmss.sss. So 093025.600 can be displayed as: 09:30:25. 

The second boldfaced number from the left is the date. It's interpreted according to this format string: ddmmyy. So 111112 can be displayed as 11-November-2012

UTC Time (Zulu) is Coordinated Universal Time. You can calculate your local time as needed by adding or subtracting hours and minutes before or after UTC time.


NOTE: I have oversimplified the concepts in this section to keep this guide short and accessible.  For those who are interested in a more detailed explanation, there are many helpful references on the web. 

The accuracy and resolution of the geo data logger will depend on many facors such as:
  • The speed by which we are moving with the geo data logger.
  • The frequency by which sensors can generate fresh readings.
  • The frequency by which the GPS receiver can generate location fixes to tag sensor data with.
  • The SD card read/write performance. 
  • The speed of the microcontroller, for number crunching and formatting. 
As for our Bump-O-Meter, we have the following specs to work with:
  • The LS20031 GPS receiver can report a location "fix" 5 times a second (datasheet says 10Hz but field experience shows 5Hz is reliable)
  • The ADXL335 Accelerometer generates motion data at a rate 50 times per second.
  • SD cards have an average latency of 100 ms even though the specs allow for 200 ms. Some old SD cards can handle 150KB/Sec to 200KB/Sec. More than enough for our data logger. 
  • The ATmega328p runs at a cool 16Mhz. 
MATH FOR FUN (No such thing)

So the bottleneck for our Bump-O-Meter will be the GPS receiver, at 5 updates per second (5Hz). Let's assume we are driving at 60 Km/h and the GPS is reporting 5 location fixes per second.
  • 60 kilometers per hour = 1 Km per minute. 
  • 1 kilometer per minute = 16.6 meters per second. 
  • Since the LS20031 GPS receiver provides 5 fixes per second that's a fix every 3.3 meters. Keep in mind this GPS receiver is accurate within 2.5 meters. 
At 30 kilometers per hour, we can double the accuracy of our logger and so on. At 15...and so forth. 

The key thing is to record a road bump or pothole even if we don't have its exact location. Because so long as we capture the bump's existence on our logger, we can find it if we go searching for it within +/- 2.5 meters (GPS accuracy) of the location reported by the logger.  

For smoother data such as the ones generated by outdoors temperature and humidity sensors, we can make use of fairly simple techniques for guessing in-between data, such as interpolation. 


Interpolation is a method of guessing a mid data point within two recorded sensor data points.  For examples, if we drive down the highway while logging temperatures, if our geo data logger is capturing temperature readings every 100 meters, it might be possible to interpolate (guess) the in-between temperature every 50 meters. The change in outdoors weather temperature within 100 meters is not typically abrupt but tend to be gradual. So if we log 32 degrees F at 0 meters and 33 degrees F at 100 meters. We can make a reasonable guess that at 50 meters or somewhere in between the temperature can be 32.5 degrees F. This is the simplified version of data interpolation. 

Some interpolation might be possible and meaningful between two logged temperature points over a certain distance. Interpolating road conditions, on the other hand, may not be as simple.

Potholes and road bumps don't lend themselves to interpolation. Unlike the gradual change in many environmental conditions, potholes tend to be sudden.  Potholes are not typically preceded by increasingly larger potholes. And they are not followed by increasingly smaller pot holes. For detecting pot holes, we have to drive slower to give our geo data logger time to catch those (<15 Km/h).  Also, we can slow down when we see an approaching pothole or a road bump to make sure our geo data logger catches it.  In real world situations, we tend to slow down anyway as we approach a bump or pothole so that works well for our purposes. 

Happy geo data logging. 


Raknco28 made it!(author)2017-04-03


FarisK2 made it!(author)2016-10-20

Hi im just wondering whether it will able to track the location like within a room because i want to implement this in a lego track for detecting faulty track.

Can you assist me with this?

123moose made it!(author)2015-09-08

Can anyone help please? I am new
to this, and been trying to put together the project. So far I have everything
assembled as instructed. However, as soon as I try to verify the code, I get
this error:

Arduino: 1.6.5 (Windows 7), Board: "Arduino/Genuino

C:\Program Files
(x86)\Arduino\libraries\SD\src\utility\Sd2Card.cpp:26:17: fatal error: SPI.h:
No such file or directory



compilation terminated.

Error compiling.

What do I need to do to fix this?

J%C4%81nisK6 made it!(author)2015-10-16

Newer versions of Arduino IDE can't find the SPI library, so you need to add them by adding the following line at the start of sketch:
#include <SPI.h>

brinesharks made it!(author)2015-09-29

I'm no expert but had this same problem on another project. All of the files (including the additional libraries) need to be in the right folder. The Arduino IDE seems to be a bit picky about this (on Linux at least).

VinodN3 made it!(author)2015-08-27

can i have the code for storing Accelerometer ADXL335 data into SD card with time staps (say every 5 min interbal)

and how can name the stored file as a YYYYMMDDHHSS format

KennethL1 made it!(author)2015-03-26

could not get code to compile

crogshockey made it!(author)2015-03-26

I made an equivalent tool in python that print real time data from ADXL345 accelerometer.

ANtonL1 made it!(author)2015-02-08


mba7 made it!(author)2014-09-21

I made an equivalent tool in python that print real time data from ADXL345 accelerometer.

may be it will be helpful for someone

mba7 made it!(author)2014-09-21

I made an equivalent tool in python that print real time data from ADXL345 accelerometer.

may be it will be helpful for someone

prettyboypk made it!(author)2014-09-09

I need create a file GPS.log in SD card before do this work ? Or the file GPS.log will be created by code?

Kennethhackneyr97 made it!(author)2014-06-12

You can read the accelerometer more often than the GPS, so there should be no need to interpolate the accelerometer reading.

jiffymanager made it!(author)2014-04-25


calmlunch made it!(author)2014-04-20


clickyummy made it!(author)2014-03-08


bearblue made it!(author)2014-02-25


cdragos+george made it!(author)2014-01-23

In this tutorial I find what I need to start interfacing the gps sensor with an Arduino. And because I want to help many more hobbyists to start building robots, I share this tutorial on my post Thank you!

chimplost made it!(author)2014-01-21

Hello techbitar - I'm thinking of building an adaption of your project but am considering changing the SD card adapter to the microSD card shield from Sparkfun:

regaltaxlaw made it!(author)2013-12-18

True but not all sensors (temperature, humid, etc.) possibly used by others will be as fast as the accelerometer I am using in my project.

zmilosavljevic made it!(author)2012-11-29

Hello techbitar,

I just ordered all the hardware for this project, and I should be beginning it some time next week. I just had a question. Obviously all of these components would need to be powered up whilst in car data collecting while driving, so would one of these do the job: . Also, I got this for the 'in-home' programming and construction of the actual project: ..... Do you think that'll be good as well? I would assume so.

techbitar made it!(author)2012-11-30

The Arduino Uno specs are as follows:
Input Voltage (recommended) 7-12V
Input Voltage (limits) 6-20V

As for current, I have tested my Bump-O-Meter with a USB connection which provides 5V and up to 0.5A. I did not run into any issues but I did not perform any exhaustive tests.

While driving around in my car, I powered the Arduino Uno via the DC plug using a battery brick made of 6 X 1.2V (NiMh) = 7.2V @ 2A. That voltage is close to the minimum recommended voltage. It worked but of course the moment the battery dropped to 6V and below I am sure I would have ran into all sorts of issues.

If I go production with this, I would use a 3S LiPo for a cool 11.1 Volts and 1.5A or 2A current for safety margin in case I need to add additional power hungry gizmos to the bump-o-meter.

Check you choices of power supplies against the min/max voltage specs and add a comfortable margin to the current with an eye on your future plans. then decide what fits your requirements best.

lmcwill made it!(author)2013-09-23

I was riding my bike recently and remarked to another rider that it would be useful to quantify just how bad our roads are. My thinking is to first breadboard components as you have laid them out, and then substitute an Arduino Micro and micro SD card reader for compactness. While I like LiOn batteries, a 3S 11.1V 2 amp battery is fairly large (and heavy and needs a requisite charger). Do you have an idea for a compact battery with a 3-hour runtime?

scottwal made it!(author)2013-06-05

Hello techbitar - I'm thinking of building an adaption of your project but am considering changing the SD card adapter to the microSD card shield from Sparkfun:

Do you see any obvious problems with this change, and would it break the code you've written? Cheers

techbitar made it!(author)2013-09-16

I have not tried it but if it Sparkfun's SD adapter does not work out of the box you may need to tweak my circuit and/or code.

clickworried made it!(author)2013-08-27

You can read the accelerometer more often than the GPS, so there should be no need to interpolate the accelerometer reading.

techbitar made it!(author)2013-09-16

True but not all sensors (temperature, humid, etc.) possibly used by others will be as fast as the accelerometer I am using in my project.

My+Diet+Area made it!(author)2013-08-03

awesome and super useful..

3dotter made it!(author)2013-06-21

SUPER Tutorial and explanation!! Thanks.

zmilosavljevic made it!(author)2013-04-20

Does anyone know why I am getting this: , and not what the instructable shows? Any help would be much appreciated, especially seeing how far I've gotten.

0xKD made it!(author)2012-12-10

"We have to level-shift the Arduino's 5V signals to 3.3V before we can connect them to the SD card."  Why?

Can I power the SD card via a 3.3V output of the SN74AHC125? I just have the SD socket and have got all components except the LM1117 to build a circuit like the LC STUDIO.

techbitar made it!(author)2012-12-11

Wikipedia says "The power consumption of microSD cards varies by manufacturer, but is in the range of 66–330 mW (20–100 mA)"

lmsalgado made it!(author)2013-02-27

"Just because this SD card socket can be powered with 5V or 3.3V, we still can't connect 5V Arduino pins to the SD card socket's pins".

Also ask why? If the arduino's 5V socket can hold 500mA shouldn't I be able to connect this socket to the shield's 5V socket directly?

moguraj made it!(author)2013-02-18

Hw to make this data logger into real time to upload the SD card contents after formatting into any GPS visulaizing website automatically !!
Can any one help me !!!

danang1 made it!(author)2012-12-26

everything is well

tolstoyan made it!(author)2012-12-05

does the GPS data logger always have to be connected to the internet or all it needs is a power source? i need an urgent reply coz im about to start making it please help me hehe tnx in advanced

techbitar made it!(author)2012-12-07

there's no need to connect the gadget to the internet.

tolstoyan made it!(author)2012-12-07

oh i get it thank you very much

skrubol made it!(author)2012-12-04

You can read the accelerometer more often than the GPS, so there should be no need to interpolate the accelerometer reading. Either you would interpolate the position reading (write 10 accelerometer readings for every GPS reading and do the interpolation in post processing,) or characterize the 10 accelerometer readings (likely take RMS or peak) and record once per GPS reading.

tolstoyan made it!(author)2012-11-28

actually this is my 2nd time to use the arduino and im a student, most of the materials that you use is available in the Philippines but they differ on the look and sizes but the function remain the same

SN74AHCT1G32DCKR 2 input OR Gate tsop-5 <--- is this IC are allowed to use? i find it hard to find the IC SN74AHC125 as level shifter from 5V to 3.3V
or do you have any alternatives?

techbitar made it!(author)2012-11-29

Google it and see if others have used it and what are their impressions. then check the datasheet and see if the specs meet your requirements

tolstoyan made it!(author)2012-12-02

ok tnx for the reply

psycho4m1947 made it!(author)2012-12-02

awesome and super useful....keep going :)

tolstoyan made it!(author)2012-11-27

this is a LOT better than your previous version, i am planning to build it, i am from the Philippines, is it okay if i present it to my school? anyway i hope you can help me out if i encounter trouble in making this prototype :D
GOD bless thank you :)

techbitar made it!(author)2012-11-27

Hi tolstoyan, by all means you can do whatever you want with the design. But if this is your first Arduino project, may I suggest that you start with something more basic (so many nice Arduino projects on before you start with the geo data logger. I have provided point to point wiring diagrams both visually and textually so you can implement this with little need for intervention from anyone. if you use the same parts and wire them according to my instructions, the accompanying software will also work as-is. I would love to see some videos of your final project. Best of luck and keep me posted please.

Scubamatt made it!(author)2012-11-27

Hello, this looks pretty awesome. I am learning to fly a Powered Paraglider and would live to have some type of instrumentation that gives similar results to what you have here. Just a simple GPS or Variometer seems like minimal information. Thanks for the post ill keep up with you to see how things progress. If you ever need an aviation instrument tester let me know!

techbitar made it!(author)2012-11-27

Thanks, Scubamatt. I am not sure I will be flying things with my gadget any time soon :) but I think the nice folks at have great guides and tools for what you have in mind. Check this out:

borogoves made it!(author)2012-11-27

Air quality depends a lot on time of day. This seems like a good way to measure that variation on a local level over many, many trips through the same area at different times of day.

techbitar made it!(author)2012-11-27

good point.

borogoves made it!(author)2012-11-27

I would like to use something like this to log mileage driven in my informal two-household car-sharing program, for the purpose of sharing expenses. We determined that we don't need to know where the car has been, but would like to know just the amount of time it is driven + time it is away from the garage, for each user. So I think it's three sensor inputs needed to log three pieces of info:
1. am i away from the garage?
2. if so, am i moving?
3. if moving, who is driving me?
And the rest can be worked out offline. Any ideas?

About This Instructable




Bio: Did I unplug the solder iron?
More by techbitar:IR Remote Control Station for Android - TURN THE TV DOWNSensoDuino: Turn Your Android Phone into a Wireless Sensors Hub for ArduinoModify The HC-05 Bluetooth Module Defaults Using AT Commands
Add instructable to: