Showing posts with label Google Maps. Show all posts
Showing posts with label Google Maps. Show all posts

Sunday, November 27, 2011

GPS dongle, gpsd, and Ubuntu 11.10

This post is an update to my original experiment #1 and experiment #2 with a USB GPS dongle two years ago.

Install the hardware: Plug it in, of course.
  • Check the kernel message log to discover the GPS dongle location in the filesystem:
    $ dmesg | grep tty
    [1769190.919411] usb 2-1: pl2303 converter now attached to ttyUSB0
  • Test for signal with the following command:
    $ cat /dev/ttyUSB0 
    5�y�220,N,08754.5061,W,000.0,316.5,271111,,,A*71
    $GPVTG,316.5,T,,M,000.0,N,000.0,K,A*0C
    $GPGGA,173905.000,4259.7220,N,08754.5060,W,1,08,1.0,190.0,M,-33.8,M,,0000*63
    $GPGSA,A,3,12,04,10,23,02,05,17,25,,,,,1.7,1.0,1.4*31
    $GPRMC,173905.000,A,4259.7220,N,08754.5060,W,000.0,316.5,271111,,,A*71
    
    Use CTRL+C to end the signal check.
    If you get a bunch of zero-data, then try moving closer to a window, since GPS signals are line-of-sight. Or try a USB hub or extension cable, to reduce interference from your computer.

Install the gps daemon so you can use gps data.
  • sudo apt-get install gpsd gpsd-clients
  • Normally, udev will start gpsd automatically when a USB GPS device is inserted. If it fails to start after 5-10 seconds, you can start it manually:
    gpsd /dev/ttyUSB0  #You must tell gpsd where to look for the dongle
  • Test the GPS and gpsd output using the gpsmon and cgps terminal programs, or the xgps program (all included in the gpsd-clients package)
  • Capture data for recycling (optional - handy for development). gpsfake will simulate gpsd output
    $cat /dev/ttyUSB0 > path/to/datalog  # Create data file. Use CTRL+C to end the capture.
    $gpsfake path/to/datalog             # Run gpsd simulator (not a daemon - it will occupy the terminal)

Command-line tools to get GPS data
  • Use the gpspipe command to get gpsd data:
    $ gpspipe -w -n 5
    netlib_connectsock() returns socket on fd 3
    {"class":"VERSION","release":"2.95","rev":"2011-07-27T11:20:24","proto_major":3,"proto_minor":3}
    {"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/ttyUSB0"}]}
    {"class":"WATCH","enable":true,"json":true,"nmea":false,"raw":0,"scaled":false,"timing":false}
    {"class":"TPV","tag":"RMC","device":"/dev/ttyUSB0","time":1322418390.001,"ept":0.005,"lat":42.995410000,"lon":-87.908430000,"alt":195.400,"epx":11.739,"epy":17.294,"epv":36.800,"track":342.2000,"speed":0.000,"climb":0.000,"eps":34.59,"mode":3}
    {"class":"SKY","tag":"GSV","device":"/dev/ttyUSB0","xdop":0.66,"ydop":1.15,"vdop":1.46,"tdop":1.01,"hdop":1.32,"gdop":2.22,"pdop":1.97,"satellites":[{"PRN":2,"el":77,"az":360,"ss":26,"used":true},{"PRN":10,"el":58,"az":72,"ss":32,"used":true},{"PRN":12,"el":51,"az":247,"ss":34,"used":true},{"PRN":5,"el":45,"az":192,"ss":21,"used":true},{"PRN":4,"el":40,"az":65,"ss":20,"used":true},{"PRN":25,"el":39,"az":292,"ss":21,"used":true},{"PRN":13,"el":15,"az":60,"ss":18,"used":true},{"PRN":24,"el":14,"az":258,"ss":0,"used":false},{"PRN":29,"el":12,"az":304,"ss":23,"used":false},{"PRN":17,"el":8,"az":121,"ss":17,"used":true},{"PRN":23,"el":7,"az":35,"ss":10,"used":false},{"PRN":31,"el":0,"az":334,"ss":0,"used":false}]}
  • Let's refine the command a bit, limit to the first "TPV" (time, position, velocity) sentence:
    $ gpspipe -w -n 5 | grep -m 1 TPV
    netlib_connectsock() returns socket on fd 3
    {"class":"TPV","tag":"RMC","device":"/dev/ttyUSB0","time":1322418481.001,"ept":0.005,"lat":42.995406667,"lon":-87.908428333,"alt":195.300,"epx":10.003,"epy":17.383,"epv":36.800,"track":342.2000,"speed":0.000,"climb":0.000,"eps":34.77,"mode":3}
  • We can use basic shell commands to extract single variables from this sentence:
    tpv=$(gpspipe -w -n 5 | grep -m 1 TPV | cut -d, -f4,6-8,13)
    seconds=$(echo $tpv | cut -d, -f1 | cut -d: -f2)
    latitude=$(echo $tpv | cut -d, -f2 | cut -d: -f2)
    longitude=$(echo $tpv | cut -d, -f3 | cut -d: -f2)
    altitude=$(echo $tpv | cut -d, -f4 | cut -d: -f2)
    speed=$(echo $tpv | cut -d, -f5 | cut -d: -f2)
  • For fun, let's compare GPS time with system time using shell commands:
    date -u +%s   # System utc time in seconds
    gpspipe -w -n 5 | grep -m 1 TPV | cut -d, -f4 | cut -d: -f2   # GPS utc time in seconds
    
    # Let's compare them side-by side
    $ echo System: $(date -u +%s) , GPS: $(gpspipe -w -n 5 | grep -m 1 TPV | cut -d, -f4 | cut -d: -f2) 
    netlib_connectsock() returns socket on fd 3
    System: 1322419689 , GPS: 1322419689.000
    # Our sytem time is within one second of GPS time. That's good!
  • For fun, let's use shell script to post the GPS location to Google Maps:
    The format is simple enough: http://maps.google.com/?ll=40.480381,-92.373047&z=16 will return a valid map. So that's three variables: Latitude, longitude, and zoom Level.
    tpv=$(gpspipe -w -n 5 | grep -m 1 TPV | cut -d, -f4,6-8,13)
    latitude=$(echo $tpv | cut -d, -f2 | cut -d: -f2)
    longitude=$(echo $tpv | cut -d, -f3 | cut -d: -f2)
    zoom=20
    map_url="http://maps.google.com/?ll=${latitude},${longitude}&z=${zoom}"
    firefox $map_url

Python tools to get GPS data
  • Python bindings to gpsd are provided by the python-gps package.
    sudo apt-get install python-gps
  • The python tools have changed a *lot* in two years. The old methods don't work anymore. No Python 3 version is available yet. There's a decent example here, but I couldn't get it to work.

Conversion between Lat/Lon and MGRS/UTM and other systems: gpsd doesn't do this, though apparently the geographiclib-tools package does. And so does this website.

Tuesday, February 24, 2009

You Are Here on a Google Map

This post is obsolete and has been superseded


The following python 2.x script shows your current (GPS-enabled) location on a Google Map. A useful learning experience:

#!/usr/bin/env python

"""This is a python 2.5 script that plot's a GPS receiver's location on the
Google Maps website.

In order to work, you need a network connection, an attached GPS receiver, and
the GPS daemon (gpsd).
"""
import os
#import subprocess and SU
import gps
import dbus
import sys


def test( ):
    """ Step 1: Test for the existence of a running gpsd, test for the existence of an open network connection, and test for a firefox process.
    If any fail, give an error message, don't try to recover. FUTURE: Could also use DBus to test for firefox and gpsd."""

    process_list = os.popen('ps -e')    # os.popen is deprecated in favort of subprocess.Popen
    #process_list = SU.Popen(['ps','e'], stdout=SU.PIPE).stdout.read()  
    gpsd_existence_flag = 0
    firefox_existence_flag = 0
    for line in process_list.readlines():
        if line.count('gpsd') > 0: gpsd_existence_flag = 1
        if line.count('firefox') > 0: firefox_existence_flag = 1

    if not gpsd_existence_flag:
        print ("gpsd is not running. Use 'gpsd -b /dev/ttyUSB0' to start it, and then try again.")
        sys.exit()       
    else: print ('Checking...found gpsd')

    if not firefox_existence_flag:
        print ("firefox is not running. Please start it and try again.")
        sys.exit()
    else: print ('Checking...found firefox')

    bus = dbus.SystemBus()
    nm_item = ('org.freedesktop.NetworkManager')  # This string gets used a lot
    nm_path = ('/org/freedesktop/NetworkManager')
    nm_device = ('org.freedesktop.NetworkManager.Device')

    list_of_interface_paths = dbus.Interface(bus.get_object(nm_item, nm_path), nm_device).getDevices()

    found_network_flag = 0
    for interface_path in list_of_interface_paths:
        one_interface = dbus.Interface(bus.get_object(nm_item, interface_path), nm_device)
        if one_interface.getLinkActive():   # True if there is an active network on this interface
            if one_interface.getType() == 2: # 0 unknown, 1 wired, 2 wireless
                print('Checking...found the wireless network') 
                found_network_flag = 1
            elif one_interface.getType() == 1: 
                print('Checking...found the wired network')
                found_network_flag = 1
                
    if found_network_flag: return
    else:
        print ("cannot find a network connection. Please connect and try again.")
        sys.exit()    


def get_position_fix( ):
    """Step 2: Get a position fix from gpsd."""
    session = gps.gps('localhost','2947')  # Open a connection to gpsd
    session.query('p')                     # Get the location fix 
    lat = session.fix.latitude
    lon = session.fix.longitude
    print ('Location is ' + str(lat) + ' latitude and ' + str(lon) + ' longitude.')
    return (lat, lon)


def show_map(lat_lon_tuple):
    """Step 3: Submit the position fix to Google Maps. Note that the parentheses '()' in the URL must be escaped '\' to work.
    Sample URL format: http://maps.google.com/maps?q=37.771008,+-122.41175+(You+can+insert+your+text+here)&iwloc=A&hl=en"""
    url_string = ('http://maps.google.com/maps?q=' + str(lat_lon_tuple[0]) + ',+' + str(lat_lon_tuple[1]) + '+\(You+Are+Here\)&iwloc=A&hl=en')
    os.popen('firefox ' + url_string)
    return

# Run this script as a standalone program
if __name__ == "__main__" :
    test()
    location = get_position_fix()
    show_map(location)