wiki:Linux/Ubuntu/GoogleEarthPlusRealTimeGPS

Google Earth Real-time GPS Tracking

The recent release of Google Earth v4.3 beta makes it possible to enable real-time GPS tracking for Google Earth on Linux - functionality that has been conspicuously and annoyingly missing and makes the Linux version a poor relation to its Windows and Mac siblings. It is also possible without requiring the built-in functionality since it only entails creating a Network Link.

Realtime GPS

If you are using Google Earth v4.3 Plus (subscription version) you should have the Tools > GPS menu. In the resulting dialog there are two tabs. The Realtime tab has a button to start tracking.

Set the correct configuration and press the Start button and you'll find there's a new entry in Temporary Places called Realtime GPS. This is a Network Link that points to a local KML file. The location is "./realtime/Realtime GPS.kml". The location is relative to Google Earth's installation directory.

Google Earth basic (free) version only

If you're using the free version you can create this Network Link manually and then enjoy GPS support too. If you have a Plus subscription skip this section.

Save the following file 'Realtime GPS.kml' to the Google Earth installation directory. On my system that is "/opt/google-earth/Realtime GPS.kml"

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<NetworkLink>
	<name>Realtime GPS</name>
	<open>1</open>
	<Link>
		<href>./realtime/Realtime GPS.kml</href>
		<refreshMode>onInterval</refreshMode>
	</Link>
</NetworkLink>
</kml>

Now open the file in Places (File > Open...).

GPS Device

Many GPS devices output data using the NMEA text format. They do it via a slow serial port link. Therefore any application that can connect to a serial port and read text can make use of the output.

I have a Pretec CompactGPS (Compact Flash form-factor) device that can, with a PCMCIA adapter, be used in a PC as well as a PDA. The Pretec CompactGPS presents to Linux as a 16-bit PCMCIA device that without additional drivers provides a serial port connection at 4800 baud, 8 data bits, no parity, 1 stop bit and no flow control (4800 8n1).

The kernel must support 16-bit PCMCIA devices (CONFIG_PCMCIA) and create a serial port for PCMCIA aka Card Services (CONFIG_SERIAL_8250_CS). On most distributions this will be the case but if you use a custom kernel make sure of these. If using modules these are pcmcia.ko and serial_cs.ko

$ lsmod | egrep pcmcia
pcmcia                 50592  1 serial_cs
pcmcia_core            49732  4 serial_cs,pcmcia,yenta_socket,rsrc_nonstatic

When the device is plugged in the log will show something like:

[ 5154.579392] pccard: PCMCIA card inserted into slot 0
[ 5154.579776] pcmcia: registering new device pcmcia0.0
[ 5154.623709] 0.0: ttyS0 at I/O 0x3f8 (irq = 16) is a 16550A

If you're using a USB device the procedure to ensure it creates a serial port may be different.

Google Earth for Linux doesn't ship with a 'GPS data server' to create and update the Realtime GPS file but an enterprising user, Jaroslaw Zachwieja, created a simple server called  GEgpsd in the python language to do it. I've modified the GEgpsd script slightly to make it more configurable.

Install the python serial package first:

sudo apt-get install python-serial

Save this script to the file gegpsd.py in a convenient directory. If it will only be used with Google Earth then /opt/google-earth/ might be a good location.

#!/usr/bin/python

# Copyright (C) 2007 by Jaroslaw Zachwieja <grok!warwick.ac.uk>
# Copyright (C) 2008 by TJ <linux!tjworld.net>
# Published under the terms of GNU General Public License v2 or later.
# License text available at http://www.gnu.org/licenses/licenses.html#GPL

import serial
import string
import sys
import getopt

def usage():
		print "Usage:"
		print " -p | --port <device>   e.g. /dev/ttyS0"
		print " -b | --baud <speed>    e.g. 4800"
		print " -f | --file <filename> e.g. /tmp/gps.kml"
		print " -h | --help     display options"

def main():
	# defaults
	serial_port = "/dev/ttyS0"
	serial_baud = 4800
	file = './realtime/Realtime GPS.kml'

	try:
		opts, args = getopt.getopt(sys.argv[1:], "p:b:f:h", ["port=", "baud=", "file=", "help"])
	except getopt.GetoptError:
		usage()
		sys.exit(1)
	else:
		for opt, arg in opts:
			if opt in ("-p", "--port"):
				serial_port = arg
			elif opt in ("-b", "--baud"):
				serial_baud = string.atof(arg)
			elif opt in ("-f", "--file"):
				file = arg
			elif opt in ("-h", "--help"):
				usage()
				sys.exit(0)
			else:
				print "Unknown option"

	gps = serial.Serial(serial_port, serial_baud, timeout=1)

	print "Serving data from %s (%d baud) to %s" % (serial_port, serial_baud, file)

	latitude = 0
	longitude = 0
	speed = 0
	heading_in = 0
	altitude = 0
	range = 1000
	tilt = 30

	while 1:
		line = gps.readline()
		datablock = line.split(',') 

		if line[0:6] == '$GPRMC':
			latitude_in = string.atof(datablock[3])
			longitude_in = string.atof(datablock[5])
			try:
				altitude = string.atof(datablock[8])
			except ValueError:
				# use last good value
				altitude = altitude
			speed_in = string.atof(datablock[7])
			try:
				heading_in = string.atof(datablock[8])
			except ValueError:
				# use last good value
				heading_in = heading_in
			if datablock[4] == 'S':
				latitude_in = -latitude_in
			if datablock[6] == 'W':
				longitude_in = -longitude_in

			latitude_degrees = int(latitude_in/100)
			latitude_minutes = latitude_in - latitude_degrees*100

			longitude_degrees = int(longitude_in/100)
			longitude_minutes = longitude_in - longitude_degrees*100

			latitude = latitude_degrees + (latitude_minutes/60)
			longitude = longitude_degrees + (longitude_minutes/60)

			speed = int(speed_in * 1.852)
			range = ( ( speed / 100  ) * 350 ) + 650
			tilt = ( ( speed / 120 ) * 43 ) + 30
			heading = heading_in

			if speed < 10:
				range = 200
				tilt = 30
				heading = 0

			output = """<?xml version="1.0" encoding="UTF-8"?>
	<kml xmlns="http://earth.google.com/kml/2.0">
		<Placemark>
			<name>%s km/h</name>
			<description>^</description>
			<LookAt>
				<longitude>%s</longitude>
				<latitude>%s</latitude>
				<range>%s</range>
				<tilt>%s</tilt>
				<heading>%s</heading>
			</LookAt>
			<Point>
				<coordinates>%s,%s,%s</coordinates>
			</Point>
		</Placemark>
	</kml>""" % (speed,longitude,latitude,range,tilt,heading,longitude,latitude,altitude)

			f=open(file, 'w')
			f.write(output)
			f.close()

	ser.close()

if __name__ == "__main__":
	main()

Make it executable:

$ sudo chmod +x /opt/google-earth/gegpsd.py

Ensure the directory for the generated file is available:

$ sudo mkdir /opt/google-earth/realtime

Using

Now, when you want to use realtime GPS with Google Earth start this 'data server':

$ sudo /opt/google-earth/gegpsd.py

Note: I'm using sudo here because the python script needs write permissions to the Google Earth directory and I didn't feel like configuring alternate user group permissions for the directory to allow a regular user write access.

Then in Google Earth enable the Realtime GPS Place either via Tools > GPS > Realtime or (if not using Plus) by manually enabling the Network Link as described above.

Using the command-line options I've added to gegpsd you should be able to configure it easily to match your requirements without needing to hack the script itself.

$ /opt/google-earth/gegpsd.py --help
Usage:
 -p | --port <device>   e.g. /dev/ttyS0
 -b | --baud <speed>    e.g. 4800
 -f | --file <filename> e.g. /tmp/gps.kml
 -h | --help     display options

If you change the file location from the default ("./realtime/Realtime GPS.kml") you'll also need to alter the Network Link in Places to point to the same location, otherwise the Network Link will fail.

I also added some additional data checking to catch exceptions in the data stream so it doesn't stop unexpectedly.

It should be easy to add additional shell hooks to have the 'data server' start as part of the system init process and shutdown cleanly too.

Attachments