Geo Logger
Geo Logger
UPDATES
Oct 17, 2013: I have published a guide on using your Android phone to accomplish a similar task by
leveraging your Android device's built in GPS and sensors.
Feb 6, 2013: Featured on GeoAwesomeness http://geoawesomeness.com/?p=3388
Nov 24, 2012: Featured on Hackaday http://goo.gl/XX9oy
Nov 21, 2012: Featured by John Boxall @ Freetronics http://goo.gl/OvnNC
Nov 20, 2012: Featured on Dangerous Prototypes http://goo.gl/ve6Eu
INTRODUCTION
I thought it would be educational to build a prototype that I can take on the road to log, geo-tag, and timestamp 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.
PROJECT SECTIONS
This guide is divided into the following sections:
1.
2.
3.
4.
5.
6.
7.
8.
9.
PROJECT OVERVIEW
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.
HOW TO USE
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 GPSvisualizer.com 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.
HARDWARE & SOFTWARE COMPONENTS
HARDWARE
** 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 Ebay.com. 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.
SOFTWARE
PIN4
PIN1(TX)
PIN0(RX)
ANALOG0
ANALOG1
ANALOG2
GND (bottom)
3.3V
ST
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
The one I find useful for this project is the RMC ($GPRMC). Here's a sample RMC sentence and an
explanation of each element:
$GPRMC,053740.000,A,2503.6319,N,12136.0099,E,2.69,79.65,100106,,,A*53
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.
THE ADXL335 GOES MOBILE
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.
POWERING THE ADXL335
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.
ADXL335 DATASHEET
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
*/
#include
#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
return;
}
else digitalWrite(LED, HIGH); // turn on LED if SD detection is OK
GPSlog = SD.open("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
return;
}
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
// HERE WE DECLARE MORE OR LESS ANALOG SENSOR VARIABLES
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
// THIS IS WHERE WE READ SENSOR VALUES
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;
// THIS IS WHERE WE WRITE SENSOR DATA TO THE SD FILE
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
GPSlog.print("\r\n");
GPSlog.flush();
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 =====================
an0, 10);
an1, 10);
an2, 10);
an0, 10);
an1, 10);
an2, 10);
*/
#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
return;
}
else digitalWrite(LED, HIGH); // turn on LED if SD detection is OK
GPSlog = SD.open("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
return;
}
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
GPSlog.print("\r\n");
GPSlog.flush();
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:
http://www.gpsvisualizer.com/map_input?form=data
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.
STEP 3: Click "Draw the map" button and watch the magic.
HOW TO READ THE MAP
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.
$GPRMC,093025.600,A,3157.8299,N,03551.5057,E,18.18,37.45,111112,,,A*6C
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 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.
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.
SOURCE: http://www.instructables.com/id/Geo-Data-Logger-ArduinoGPSSDAccelerometer-to-l/