Hack 39. Track Your Every Move with Google Earth

Ever wanted to have your own spy in the sky watching your every move, tracking you wherever you go?

Google Earth, formerly known as Keyhole, is the desktop-based big brother to Google Maps, offering 3D overviews of major cities, mountains, and other terrain, as well as local businesses and information, driving directions, and maps. Its features are far too numerous to mention here, but you can find out more and download a free version at http://earth.google.com/. Tragically, although it's based on the OpenGL standard, Google Earth is, as of this writing, supported on Windows only.

One of Google Earth's most interesting features is the ability to bookmark a particular view of a place or places, and then export that view to other Google Earth users via the Keyhole Markup Language (KML) format. The XMLbased KML format is good for adding static content to Google Earth (e.g., bridges, monuments, or buildings), but how do we map things that move?

Fortunately, Google Earth has something called a Network Link, which we'll look at a bit more in a second. The upshot is that we can use it to read in a .kml file that holds our position every few seconds. We also have a GPS system that updates our position every few seconds. The hack we're going to attempt is to constantly get the values from the GPS system into the .kml file. This is surprisingly easy to do on Linux, but we're running Google Earth on Windows, where things are slightly more, er, entertaining.

First, the tools we're going to use: Google Earth (and its Network Link feature), Firefox, one Garmin GPS receiver with a serial cable, a copy of Garnix for MS-DOS, two .bat files, ping, possibly some sticky tape, string, and a bit of luck. We'll talk about the other bits of software, like GPSBabel, but even if you don't have all this stuffi.e., you have a different brand of GPS receiverthere should still be enough here to get you hacking around any problems.

4.12.1. Peering into the Keyhole

Let's have a closer look at the .kml file we're going to be creating. Start up Google Earth, zoom into someplace near home, and press Ctrl-N to add a new Placemark. Call it something useful like "Me" and click OK. The Placemark will appear on the map, as well as in the Places section over on the left. Rightclick on the Placemark and select Save As. Save it as me.kml (not .kmz) into somewhere really easy to get to, as we'll be writing DOS .bat files in a while, so somewhere close to the root drive with a short name is preferable. I made a folder called c:geo and used that.

If you open your .kml file in Notepad, or any other text editor, you'll something along the lines of the following:

Me -2.189175686596352 53.0420501867381 769.3231615683798 -8.237346562804484e-011 -0.002462111503350637 root://styleMaps#default+nicon=0x307+hicon=0x317 -2.19004490258348,53.04134242507396,0

The values we're primarily concerned with are the , and elements. These should match each other, as the place we are looking at and the point we're at should be the same. I normally set the tilt and heading values to be 0 when I generate .kml files with code.

Back to Google Earth, right-click the Placemark, and then delete itback to square one. We're doing this because it's just no rock-n-roll fun as a "normal" Placemark: we'll make ours far more dynamic, by loading it in as a Network Link!

From the top menu bar, pick Add Network Link. Once more, pick a useful name, e.g., "Me, and then hit the Browse button and locate the me.kml file we just saved. At the moment, it's still acting as a normal Placemark, so change the time-based Refresh When option to Periodically and make the period every 10 seconds. Finally (for fun) tick the Fly to View on Refresh checkbox, then press OK.

What do we have? Google Earth loading in the same KML file over and over again, every 10 seconds, going to the same location over and over again. The next step is fairly obvious: we want to update the values in that .kml file every few seconds from some gnarly code we've thrown together. If you're so inclined and outfitted, try firing up your favorite development environment and having it spit random values into the KML fileand then sit back and watch as Google Earth tries to fly all over the place!

4.12.2. Back Down to Earth

Of course, we want your location, not some random one. We'll be using your Garmin GPS receiver to get your position and the cable you probably felt you were paying far too much money for (unless it came with your receiver or you built it yourself, in which case, good for you) to connect it to your PC.

We also need some software that'll fetch your longitude and latitude from the GPS device. You would think that would be a simple task, but unless my search engine fu is failing me badly, I couldn't find anything that just got our location from the device. Lots of applications for downloading waypoints and tracklogs, loads of neat scripts for Linux, but Windows programs for lat and long in an easy to use format? No such luck.

The closest I could find was the MS-DOS binary version of Garnix from http://homepage.ntlworld.com/anton.helm/garnix.html. Download it and unzip it into your c:geo folder, or where ever you decided to put your .kml file. You'll need to edit the GARNIX.CFG file in Notepad to read as follows:

port: "com4"; deg_min_sec; datum: "WGS84"; ;grid: "UTM"; ;zone: "33"; ; ;See datum.cfg for datum names ;See grid.cfg for grid and zone names

Replace com4 with whatever com port your GPS device connects onusually somewhere from com1 through com4and make sure the semicolon is removed from the front of the deg_min_sec line. If you don't know what com port your GPS uses, and you own Google Earth Plus, connect your GPS, turn it on and then pick Tools GPS Device, which will probably figure out which port its connected on. Alternatively, you can experiment with EasyGPS from http://www.easygps.com.

With your GPS system connected to your PC, go outside until you get a GPS reading locked in and have your lat/long position. If you can't go outside, try hanging the GPS unit out the window, maybe attach it to a stick or polethis is where the sticky tape and string comes in! (And you thought we were kidding about that?) If none of those options are possible, then there's a slightly less exciting one: most GPS units have a demo mode, hidden somewhere in the settings menu. If you turn that on, it'll start making up positions for you.

Open up a command window by clicking Start images/U2192.jpg border=0> Run and then type in cmd, and click OK. Then change to the correct directory and test out Garnix as follows:

c:>; cd c:geo c:geo> garnix -x

With luck you'll get a response along the lines of:

Device ID: eTrex Software Version 2.14 Device Time: 17:06:31-2005/07/23 Current Position (WGS84): Latitude 53deg 6min 2.43sec Longitude -2deg 11min 55.59sec

Different devices may give slightly different results. We'll have to deal with this later on, but it only takes a little tinkering.

If you can't get connected with Garnix, all is not lost. As long as your GPS system is cofnnected on com ports 1 to 4 you can se G7To(W) from http://www.gpsinformation.org/ronh/#g7to. The command line you'll need to use is:

c:geo> G7tow n i G45P  

n is the serial port your unit is attached to. The output is different from Garnix, so you'll need to hack the JavaScript shown later. Alternatively, you can try using GPSBabel, as described later on in the hack.

Now we have the information, but not in a useful format. There are a few options; for example, you could download the source code and hack it around to output the numbers in decimal format, or even take it a step further and write out the whole .kml file. (Please email us if you do this!) You could probably throw together some regular expressions in Perl to perform mysterious voodoo coding to automagically convert the output or, as we're going to do now, turn to Firefox and code up a quick solution in JavaScript.

Before we do that, back to the command line once more, to do this:

c:geo> garnix x > results.txt

This writes the information into a text file, which we can use for testing. You can return indoors now or pull the GPS back through the window and switch it off; we'll not be needing it for a while.

4.12.3. The Code

Next, we need to turn the output from Garnix into something Google Earth can use. To keep things simple(ish) we're going to use JavaScript and open the page in Firefox to run it. In the same folder as everything else, create an index.html file and copy the code below into it. Alternatively, you can download the code from http://googlemapshacks.com/projects/gmaps/tracking/.

 

http-equiv="refresh" content="10">geo convert

The onLoad attribute of the body element below starts the whole thing off. The remainder of the HTML is just layout and formatting.

 

Input Text Map Results
Output Text
Save Results

 

We have Google Earth loading in the .kml file every 10 seconds and the JavaScript page reading in the results.txt file and writing out the me.kml file every 10 seconds. There's just one thing left to do, which is to grab the data from the GPS unit every few seconds. Time to go back outside or put the unit into demo mode! What we want to do is call the command garnix x > results.txt once every few seconds. We could, for example, write a .bat file called go.bat and put the following in it:

garnix -x > results.txt go

 

That'll run the command and then call itself again. However, that'll really mess us up: CPU usage will rocket up and, most of the time, the file will be in an open, deleted, or being-created state. As a result, our JavaScript will never get a look inside. We need to be able to pause the running for a short while.

Sadly, Microsoft didn't ship MS-DOS with a pause or wait command. There is a file called sleep.exe that's part of a 12MB resource kit, but I for one don't want to download 12MB worth of files just for one small application. It's cheeky, but here's what we'll do: we'll create a new file called wait.bat and enter this into it:

@ping 127.0.0.1 -n 11 -w 1000 > nul go

 

We're going to ping ourselves as a way of inserting a delay in our script. (yes, seriouslywe did say it was a hack!) The parameters we use are -w 1000, which sets the timeout to 1,000 milliseconds, and -n 11, which tells it to send off 11 pings. In principle, this should delay for about 10 seconds, since it won't pause after the last ping. With a bit of experimentation, you'll be able to calibrate how many pings you need for certain lengths of time.

Now, go back and edit the original go.bat file like this:

garnix -x > results.txt wait

 

And we're all set!

Wire up the GPS unit and make sure it's on and connected. Then check that the correct com port is selected in the garnix.cfg file. Take a deep breath and type go from the Windows command line. A cycle should start with go.bat calling wait.bat and wait.bat after a delay calling go.bat. To stop it, type Ctrl-C.

Now, get all three things running: the .bat file cycle in the command shell, the index.html page reloading in Firefox, and, lastly, Google Earth reading in the me.kml file.

4.12.4. Hacking the Hack

4.12.4.1. Pre-cache the Google Earth data.

I'll be the first to admit that needing a wireless connection when you're on the move isn't always ideal or even possible. First off, if you're planning a car trip or even a quick walk, you can go over the route in Google Earth first, and it'll cache the high-resolution images, roads, and other details you decide to enable. You can increase the size of the cache by going to Tools Options images/U2192.jpg border=0> Cache. Stick the GPS unit and the laptop onto the dashboard, and off you go! Youre just playing with the files in the local cache, so no Internet connection is needed.

Tracking with Perl

If the idea of using Firefox to read and write local files seems more than a bit weird to you, you might try obtaining a Windows version of Perl, such as ActivePerl (http://www.activestate.com/), and try running the following bit of Perl code with perl.exe:

my ($lat, $lon); while (1) { sleep 10; unless (open GARNIX, "garnix -x|") { warn "Can't read from garnix: $! "; next; } while () { if (/Latw+s+(-?d+)degs+(d+)mins+([d.]+)sec/o) { $lat = abs($1) + $2 / 60 + $3 / 3600; $lat *= -1 if $lat < 0; } elsif (/Longw+s+(-?d+)degs+(d+)mins+([d.]+)sec/o) { $lon = abs($1) + $2 / 60 + $3 / 3600; $lon *= -1 if $lat < 0; } } close GARNIX; unless (open KML, ">me.kml") { warn "Can't write to me.kml: $! "; next; } print KML < Me $lon $lat 750 0 0 root://styleMaps#default+nicon=0x307+hicon=0x317 $lon,$lat,0 End close KML; }  

As you can see, this code does basically the same thing as the JavaScript, but without the need for Firefox and the results.txt file.

However, if you're willing to use GPSBabel [Hack #35] instead of Garnix, you can actually get away with this simple batch script, since GPSBabel knows how to generate KML directly:

@echo off :again gpsbabel -i garmin,get_posn -f com1: -o kml -F mpme.kml ping 127.0.0.1 -n 1 -w 1000 > nul: goto again  

Either way, by doing without Firefox, we lose the feedback provided by the browser window, particularly some of the nifty bits described in the "Hacking the Hack" section. Figuring out, for example, how to script FTP or scp to upload this file to a server without using Firefox will be left as an exercise for the user.

 

4.12.4.2. Let other Google Earth users follow along in real time.

You're about to cycle across the country, so obviously you're going to be uploading your photos to Flickr and blogging your progress. It's all very well using the GPS and Google Earth to determine where you are, but what about letting other people know? We want to put our .kml file up onto the Internet so other people can connect to it with their Network Link.

It's time to update our index.html file. Edit the table at the bottom to look like this:

 

Input Text Map Results
Output Text
Save Results

 

To put the .kml file up onto the Internet, we're going to need a server and some server-side scripting. I'll use PHP as an example, but it should be easy enough to convert to any other language. Here's the PHP file, which we'll call saveKML.php, and which needs to be uploaded to a server someplace:

'; $kml .= ''; $kml .= ''; $kml .= ' Me'; $kml .= ' '; $kml .= ' '.$HTTP_GET_VARS['fLon'].''; $kml .= ' '.$HTTP_GET_VARS['fLat'].''; $kml .= ' 750'; $kml .= ' 0'; $kml .= ' 0'; $kml .= ' '; $kml .= ' root://styleMaps#default+nicon=0x307+hicon=0x317'; $kml .= ' '; $kml .= ' '.$HTTP_GET_VARS['fLon'].','.$HTTP_GET_ VARS['fLat'].''; $kml .= ' '; $kml .= ''; $kml .= ''; $fr = @fopen('me.kml', 'w'); @fputs($fr, $kml); fclose($fr); header('Content-Type: text/plain'); print 'saved'; ?>

 

The above script takes two parameters, fLon and fLat, from the URL and uses them to build and save a KML file. You'll probably want to change the name in Me to your name, and change the me.kml to something else.

In order to upload the coordinates to the server, we'll add this line at the end of the fnWrangleText( ) function:

document.getElementById('iSave').src='http://www.yourserver.com/urlPath/saveKML.php?fLat=' + fLat + '&fLon=' + fLon;

 

Each time your index.html file reloads, it'll attempt to call the remote file and pass it your current location. If you happen to be near a Wi-Fi hotspot, your position will be updated. All your friends and family can add your .kml file as a Network Link set to update every 30 mins or so and use it to watch your daily progress.

An easier way of getting people to update a network link is to set up the Network Link as you'd want other people to use it, save it, then point people to that file rather than the actual me.kml file. Doing so will automatically subscribe them to the Network Link without any effort.

The file will look like this:

Follow my cycle tour across the USA. My Road Trip http://www.yourserver.com/ urlPath/me.kml onInterval 1800

 

If you don't have a server, you can still update your position by using a service such as Geobloggers.com using the following URL:

document.getElementById('iSave').src='http://www.geobloggers.com/ recordObject?objName=geoFlickrBot' + '&objKey=A56C-2256-FE23&fLat=' + fLat + '&fLon=' + fLon;

 

For your server to serve .kml files, you'll need to set up the correct MIME types:

application/vnd.google-earth.kml+xml kml application/vnd.google-earth.kmz kmz  

Use your favorite search engine to find out how to set up custom MIME types on your web server.

 

4.12.4.3. Add other people's photos into the browser window.

Finally, add this line at the end of the fnWrangleText( ) function.

document.getElementById('iMap').src='http://www.geobloggers.com/mob/index.cfm?lat=' + fLat + '&lon=' + fLon;

 

If you have a connection to the Internet, Firefox will load the mobile phone version of Geobloggers into the other iframe. It shows you the nearest three photos to your current location along with the direction and distance to them. If you are wandering around a city, then every time you found some wireless access, you'd get updates of nearby photos to go and hunt out.

If you're stuck without Internet access, browse to http://www.geobloggers.com/mob/ using your phone's web browser and enter your position via a form.

4.12.4.4. Add other people's photos into Google Earth itself.

Besides having time-based network links, you can also have network links that update as you move around the Earth. Try adding a new network link to Google Earth, but this time set the location to http://www.geobloggers.com/fullscreenBackend/dataFeed.cfm. Set the View-Based Refresh to After Camera Stops, and make the delay four seconds. When you zoom into a location and then pause, after four seconds Google Earth will start to load in Flickr Photos from Geobloggers for the area you are looking at. Combine this with the hack just described and as you move around photos taken by Flickr users will appear.

If you want to see photos from just a single user add ?sUsername=[username] onto the end of the URL. Alternatively, if you're viewing an area where you take a lot of photos yourself, you can add ?sExcludeUsername=[your username] to the URL to get everyone else's photos.

Dan Catt

Категории