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.
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...).
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.
The Missing Link
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) longitude_in = string.atof(datablock) try: altitude = string.atof(datablock) except ValueError: # use last good value altitude = altitude speed_in = string.atof(datablock) try: heading_in = string.atof(datablock) except ValueError: # use last good value heading_in = heading_in if datablock == 'S': latitude_in = -latitude_in if datablock == '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
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.