Skip navigation.

Talking the GPS for a drive

Ok, time to go for a walk and a drive...

I checked out my last lot of GPS code from the SWASC subversion repository and uploaded it to the MARK I mini-ITX PC. I then went for a walk around the park at the back of the house. The PC and GPS where running from a common 12V 7A Sealed Lead Acid (SLA), battery. The first walk lasted 1 hour 40 minutes. I noted the voltage drop over this period:

13:40 12.28V (on load)

14:00 12.14V

14:40 11.96V

15:00 11.88V

15:05 12.00V (no load)

After dumping the data file and loading a freshly charged battery I set out to walk the block and leave the GPS to record a fixed point (SW corner of my garden shed), for 20 minutes. This way I could try and work out the average Lat/Long of that point. As a bonus, I ended up driving my son to work and ended up driving the long way around 'the block'. This gave me some nice data.

The battery voltage recordings from that 1hr 50min run where:

15:30 13.08V (no load)

15:31 12.84V (load)

16:18 12.39V

17:18 12.03V

17:21 12.21V (no load)

I then downloaded the new data NMEA file and ran both of the data through my shell script that pulled out just the Lat/Long, and converted the data from a 115 minutes 18.342 seconds to a pure decimal format: 115.30647.

Upon importing the data file into MapWindow using the CSV import plugin, I noticed that whilst the smaller first walk GIS plot looked ok, the second walk and drive didn't display well. There where lines of data points all over the map. Hmmm.

Since I wanted to drive out to a piece of bush that I frequent and I wanted to extract more than just the Lat/Long from the NMEA GPS data. It was time to upgrade the shell script to something a bit more powerful. After battling writing an AWK script for an hour or so, I gave up (I haven't written in AWK for 7 years, and was a wee bit rusty), and wrote it in PHP. Here is the basic core of it:

 

#! /usr/local/bin/php
<?php
/*
This will translate the GPS data file into a format ready to be imported into MapWindows and a shapefile

Paul Hamilton 26th August 2007


*/

// Local Variables
$DATADIR="/root/bin/work/test";
$FILEDATE=date("YmdHis", time());
$GPSDATAFILE="$DATADIR/gps-20070825-2.txt"; // input file
$MYGPSFILE="$DATADIR/mygps"; // output file. The data and time of the last NMEA entry will be appended to this file name


// ok, lets run through the data file and extract the field we need
$i=0;
$LINES=file($GPSDATAFILE);
foreach ($LINES as $line_num => $LINE) {
$LINEEXPLODED=explode(",", $LINE);
if ($LINEEXPLODED[0]=='$GPGGA') {
/* ok, so this is a GGA line, we need to extract the following info
UTC
LAT
LONG
DATA Type (GPS Fix = 1)
Number of Satellites used for the fix
Horizontal dilution of position
Meters above Sea Level
*/
$GGAUTC=$LINEEXPLODED[1];
$GGALAT=$LINEEXPLODED[2];
$GGALONG=$LINEEXPLODED[4];
$GGAFIXTYPE=$LINEEXPLODED[6];
$GGANUMSAT=$LINEEXPLODED[7];
$GGAHORERROR=$LINEEXPLODED[8];
$GGAHEIGHT=$LINEEXPLODED[9];
} // end of GPGGA
if ($LINEEXPLODED[0]== '$GPVTG') {
/* ok, so this is a VTG line, so we need to collect the following info:
True track made good - in degrees
Magnetic track - in degrees
Ground speed in kilometers per hour
*/
if (rtrim($LINEEXPLODED[9]) != 'N*2C') {
// first make sure this is valid data
$VTGTRUETRACK=$LINEEXPLODED[1];
$VTGMAGTRACK=$LINEEXPLODED[3];
$VTGKPH=$LINEEXPLODED[7];
$FLAG=1;
} // end of IF
} // end of GPVTG
if ($LINEEXPLODED[0]=='$GPZDA') {
/* ok, so this is a ZDA line, so we need to collect the following info:
UTC time in hhmmss
Day
Month
year
*/
$ZDAUTC=$LINEEXPLODED[1];
$ZDADAY=$LINEEXPLODED[2];
$ZDAMONTH=$LINEEXPLODED[3];
$ZDAYEAR=$LINEEXPLODED[4];
} // end of GPZDA

if ($FLAG=="1") {
/* ok, we now have collected data from each of the three lines in this order: GGA, VTG, ZDA
so we can now write out the data to cvs file ready for importing into MapWindows.
*/
// ok, now lets add on the WST timezone offset onto the GPS UTC time:
$GPSHOUR=substr($ZDAUTC,0,2);
$GPSMIN=substr($ZDAUTC,2,2);
$GPSSEC=substr($ZDAUTC,4,2);
$WSTTIMESTAMP=gmmktime($GPSHOUR,$GPSMIN,$GPSSEC,$ZDAMONTH,$ZDADAY,$ZDAYEAR);
$ZDAWST=date("His",$WSTTIMESTAMP);
$ZDADATE=date("Ymd",$WSTTIMESTAMP);

/*
Lat: -33 39 37.78 --> -33+(39/60)+(37.78/3600)= -33.66038333

Long: 115 18 24.91 --> 115+(18/60)+(24.91/3600)= 115.3069194
*/
// ok, now convert Lat/Long into digital Lat/Log
$LATMIN=substr($GGALAT,0,2);
$LATSEC=substr($GGALAT,2);
$GGALAT=($LATMIN+($LATSEC/60))*-1;

$LONGMIN=substr($GGALONG,0,3);
$LONGSEC=substr($GGALONG,3);
$GGALONG=$LONGMIN+($LONGSEC/60);

$GPSDATA[$i] = $GGALAT.",".$GGALONG.",".$GGAFIXTYPE.",".$GGANUMSAT.",".$GGAHORERROR.",".$GGAHEIGHT.",";
$GPSDATA[$i] = $GPSDATA[$i].$ZDAWST.",".$ZDADATE.",";
$GPSDATA[$i] = $GPSDATA[$i].$VTGTRUETRACK.",".$VTGMAGTRACK.",".$VTGKPH."\n";
print ($GPSDATA[$i]); // display the line on the screen
$i++;
$FLAG=0;
} // end of the FLAG if statement
} // end of the For loop - move onto the next data line

// open a file handle to prep for writing the data out
$MYGPSFILE = $MYGPSFILE."_".$ZDADATE."-".$ZDAWST.".csv";
if (!$handle = fopen($MYGPSFILE, 'w')) {
echo "Cannot open file ($MYGPSFILE)";
exit;
}

// Write the cleansed NMEA data to our opened file.
print ("Writeing Data to file: $MYGPSFILE \n");
for ($j=0; $j<=$i; $j++) {
if (fwrite($handle, $GPSDATA[$j]) === FALSE) {
echo "Cannot write to file ($MYGPSFILE)";
exit;
}
} // end of FOR loop

fclose($handle); // close the output data file.
print (" Done!\n")
?>



 

The above code will take the raw NMEA file and extract the data I need and dump it into a new csv file that I can then import into MapWindows. Yes, I realise that the code will only work within a limited range, but it does the job for the moemnt. I found this URL handy in decoding the NMEA sentance structure: http://www.gpsinformation.org/dale/nmea.htm

Here is the salient parts that I needed:

VTG - Velocity made good. The gps receiver may use the LC prefix instead of GP if it is emulating Loran output.

  $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*33

where:
VTG Track made good and ground speed
054.7,T True track made good (degrees)
034.4,M Magnetic track made good
005.5,N Ground speed, knots
010.2,K Ground speed, Kilometres per hour

GGA - essential fix data which provide 3D location and accuracy data.

 $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
Where:
GGA Global Positioning System Fix Data
123519 Fix taken at 12:35:19 UTC
4807.038,N Latitude 48 deg 07.038' N
01131.000,E Longitude 11 deg 31.000' E
1 Fix quality: 0 = invalid
1 = GPS fix (SPS)
2 = DGPS fix
3 = PPS fix
4 = Real Time Kinematic
5 = Float RTK
6 = estimated (dead reckoning) (2.3 feature)
7 = Manual input mode
8 = Simulation mode
08 Number of satellites being tracked
0.9 Horizontal dilution of position
545.4,M Altitude, Meters, above mean sea level
46.9,M Height of geoid (mean sea level) above WGS84
ellipsoid
(empty field) time in seconds since last DGPS update
(empty field) DGPS station ID number
*47 the checksum data, always begins with *

ZDA - Data and Time


$GPZDA,hhmmss.ss,dd,mm,yyyy,xx,yy*CC
$GPZDA,201530.00,04,07,2002,00,00*6E

where:
hhmmss HrMinSec(UTC)
dd,mm,yyy Day,Month,Year
xx local zone hours -13..13
yy local zone minutes 0..59
*CC checksum

The data look cool in MapWindow, but I couldn't find a way to display the extra attribute data like: height, speed, number of satellites etc. With a bit more hunting around I stumbled across a JAVA GIS application called JUMP. This little beauty allows you to select the attribute you want to map, and then colourise the data to suit the data range. Here is an example showing the land height on my walk (small ciruit) and drive (large circuit):

I haven't figured out how to display a Legend, so I used GIMP to add one in. In case above, Brown is low and ranges through to light brown/blue to 33m height with dark blue. Busselton is very flat! Note these are the height data from the GPS, which is not all that accurate, but it does look nice Cool

Here is a my speed data:

Above, Brown is slow, and purple is fast. Most of the top line would be at 70Km/Hr, and the bottom is at 110Km/Hr. The small circuit in the upper right hand quadrant, was me walking around the small block.