Google Maps - DIY Real Time GPS Tracker

Instructions

You can create a real-time GPS tracker using Google Maps API. Don't worry about having a GPS device, you can emulate a garmin using GPSGate. Then later you purchase fancy gps devices and a JunxionBox.

First, install the following free software:
  1. Python (xmlrpclib, pySerial, pyGPS, Zope)
  2. GpsGate (gps simulator, 14 day trial)
  3. MySQL
  4. Get a Google Maps API key.

Get the big picture first.

1. A laptop connected to the internet continually reads the COM port, parses NMEA sentences, and sends updated GPS coordinates via XMLRPC to our Zope server.

2. The Zope server stores the incoming coordinates to a MySQL database.

3. When a visitor requests the tracking page, Zope serves up a static HTML page encoded with javascript actions.

4. The visitors browser executes the javascript and asynchronously requests more information from the Zope server and Google Maps.

5. Google Maps receives requests for pan or zoom and responds with needed map data.

6. The Zope server receives requests for the latest coordinate and responds with an XML encoding that the user's browser parses and displays on the map.

Python Code

This is a quick implementation of a GPS reader in Python using pySerial and pyGPS that passes latitude and longitude to a database via XMLRPC. We remotely call a Python script in Zope that inserts the data into a MySQL database.
import NMEA
import serial
import xmlrpclib
import urllib

ser = serial.Serial(1, 4800)

while 1:
    lat,lon=0,0
    while lat==0 and lon==0:
        line = ser.readline()
	nmea = NMEA.NMEA()
	nmea.handle_line(line[:-1])
	lat=nmea.lat
	lon=nmea.lon
	print lat,lon

    try:
	server = xmlrpclib.Server("http://conversationswithmyself.com/")
	server.maps.tracker.receiveCoords(lat,lon)
    except:
	print "Server Time Out"

Zope Code

Using Zope as our remote XMLRPC server, we use a Python script to call a ZSQLMethod that inserts the data into our database. To generate the XML file for Google Maps, we use a DTML method.
receiveCoords (Python script)
context.GmaplocsInsertMethod(lat, lon)

GmaplocsInsertMethod (ZSqlMethod)
insert into gmaptracker 
	(lat,
	lon)
	VALUES (<dtml-sqlvar lat type=float > ,
		<dtml-sqlvar lon type=float > )

data.xml (DTML Method to populate Google Maps XML data)
<?xml version="1.0" encoding="UTF-8"?>
<markers>
<dtml-in GmaplocsPkSelectLastAdded>
<marker lat="<dtml-var lat>" lng="<dtml-var lon>"/>
</dtml-in>
</markers>

MySQL Database

We have a few extra fields (category, name) for future use in the database that are being populated with dummy data at the time.
# Host: localhost
# Database: gmap
# Table: 'gmaptracker'
# 
CREATE TABLE `gmaptracker` (
  `id` int(8) NOT NULL auto_increment,
  `locName` varchar(100) NOT NULL default '',
  `category` varchar(100) NOT NULL default '',
  `lat` double(7,6) NOT NULL default '0.000000',
  `lon` double(7,6) NOT NULL default '0.000000',
  PRIMARY KEY  (`id`)
) TYPE=InnoDB; 

Javascript code

<script type="text/javascript">
    //<![CDATA[

    var status = "running";    
       
    // Map Setup
    var map = new GMap(document.getElementById("map"));
    map.centerAndZoom(new GPoint(-92.275189,  34.743682), 1);
    map.addControl(new GSmallMapControl());
    map.addControl(new GMapTypeControl());

    // Stops and starts the tracking function
    function toggleStatus()
     {
       if (status == "stopped")
    {
     status = "running";
     document.getElementById("statusLink").value="Running";       }
    else 
    {
     status = "stopped";
     document.getElementById("statusLink").value="Stopped";       
    }
      }

    // Refresh map function
    function refreshMap(map)
    {
    if (status == "stopped")
      {
       window.setTimeout(function(){ refreshMap(map)},6000);
       return;
      }

    // AJAX XML Data Download and marker placement, straight 
    // from Google API documentation
    var request = GXmlHttp.create();
    request.open("GET", "data.xml?RANDOM=”"+Math.random(), true);
    request.onreadystatechange = function() {
      if (request.readyState == 4) {
    var xmlDoc = request.responseXML;
    var markers = xmlDoc.documentElement.getElementsByTagName("marker");
    
    for (var i = 0; i < markers.length; i++) {
      var point = new GPoint(parseFloat(markers[i].getAttribute("lng")),
                 parseFloat(markers[i].getAttribute("lat")));

      // Sets a marker to the last point added in the database
      var marker = new GMarker(point);
      map.addOverlay(marker);

    }
     // Recenters map to last point added
     map.centerAtLatLng(point); 
      }
    }
    request.send(null);

    // Reloads map every 6 seconds    
    window.setTimeout(function(){ refreshMap(map)},6000);
    }

    refreshMap(map);

    //]]>

    </script>
 

Demo

Tracking Status:



About the authors

Our blogs
Brady Davis
Jeffrey Hicks

Our other GIS stuff
Google Maps: weather cam locator
Google Maps: upload tab delimited file
Worldkit: GPS Camera prototype
Keyhole: txt2kml
Google Maps: Get Lat/Lon by Click

Our del.icio.us accounts
del.icio.us/bradydavis
del.icio.us/jrhicks