Wednesday, July 06, 2011

Low cost GPS on a Mac

I recently acquired a copy of Shai Vaingast's book, "Beginning Python Visualization" and his examples are based on GPS data. Not having a source of GPS data and not wanting to spend a lot of money, for $19 I bought a USB GPS dongle, a UniTraQ UD-731. Its package contained the GPS receiver, a short USB extension cable, and a miniCD with user-level Windows apps. Because I cannot easily read miniCDs, I prefer Mac, and I wanted to read and parse the data myself, I was on my own. But the price was right.

Having worked some with USB I started there, but soon discovered the protocol was overly complex for what I wanted to do. Poking around I learned the UD-731 is really a serial device behind a USB interface and that a serial-over-USB driver might be all I needed. Indeed, SiLabs (http://www.silabs.com/.../USBtoUARTBridgeVCPDrivers.aspx) has such drivers for the Mac, Linux, and several flavors of Windows. The Mac driver came with it's own installer (reboot required) and installing PySerial was a snap. A quick look in /dev revealed the device name, but you might try:
    ls /dev | fgrep tty.   [include the trailing dot]
Alternatively, you could use   ls /dev/tty.*

The final step was to write a short Python program and here are the essential elements of that program. Note that the UD-731 talks at 4800 baud.
from serial   import Serial
from binascii import unhexlify

def cksum(msg):
    """ the check sum is a simple XOR over all 
        characters after the leading '$' up to 
        but not including the '*'.
    """
    cksum = 0
    for byt in msg[1:]:
        if byt == '*': break
        cksum ^= ord(byt)
    return cksum

ser = Serial('/dev/tty.SLAB_USBtoUART', 4800)
ser.open()
if ser.isOpen():
    print '\nUse cntl-C to quit \n'
    # consume the first one as it may be partial
    ser.readline()
    while True:
        gps_stmt  = ser.readline()
        msg_cksum = gps_stmt.split('*')[1].strip()
        old_cksum = ord(unhexlify(msg_cksum))
        new_cksum = cksum(gps_stmt)
        if new_cksum != old_cksum:
            print '  ** checksum error >>>',
        print gps_stmt, 
    ser.close()
    print
If all you want is to see the output stream, from Terminal you can enter:
    screen /dev/tty.SLAB_USBtoUART 4800

UD-731 Data Sheet:
  http://www.unitraq.com/.../UD-731 Data sheet V1.3-20091217.pdf
UD-731 User Manual:
  http://www.unitraq.com/.../UD-731 User Manual V1.3-20100730.pdf
 

Labels: ,