Thursday 11 October 2012

Pharos/Microsoft GPS-360 on Raspberry Pi

I bought a Microsoft GSP-360 USB dongle on eBay as an impulse purchase, toying with the idea of running a Raspberry Pi in my car for live map display or at least route tracking for contributing road traces to the Open Street-Map project. Just getting my location out of it proved harder than I'd expected.

The front of the dongle has a big Microsoft logo, while the sticker on the back (which has a bright blue LED when active) says:
P/N: X11-49577
360-1000-02
S/N: ...
GPS-360
Tested to comply with FCC standards
Rating: DC 3.5 - 5.5V 70mA
Pharos USA
SiRF Powered
Made in China
For running this with a Raspberry Pi that current information could be useful, and the broad voltage tolerance is reassuring. What do we learn at the command line? It appears as a Profilic USB/Serial adaptor at the USB level - here's what my Mac tells me:

$ system_profiler SPUSBDataType
...
            USB-Serial Controller:

              Product ID: 0xaaa0
              Vendor ID: 0x067b  (Prolific Technology, Inc.)
              Version: 3.00
              Serial Number: 12345678
              Speed: Up to 12 Mb/sec
              Manufacturer: Prolific Technology Inc.
              Location ID: 0xfa130000 / 6
              Current Available (mA): 500
              Current Required (mA): 500

And in Linux, running on a Raspberry Pi (with no other devices attached):

$ lsusb 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp. 
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. 
Bus 001 Device 004: ID 067b:aaa0 Prolific Technology, Inc. Prolific Pharos


USB/Serial Drivers

I should be able to talk to the USB-serial port, but to do on the Mac it seems I must first install a Prolific USB-serial driver. That's what this and this helpful blog told me.  Finding the Prolific USB/serial driver for Mac OS X took a while, it was hiding behind a "GUEST"/"GUEST" password protected page - but I eventually found md_PL2303_MacOSX10.6_dmg_v1.4.0.zip released 2011/05/13 which claims to support OS X 10.8 Mountain Lion. There's also an open source driver, osx-pl2303 on SourceForge (SVN latest updated Jan 2008), forked as osx-pl2303 on Github (last updated Nov 2011), reported to have been tested under Mac OS X 10.7 Lion and 10.8 Mountain Lion. I punted on this.

As an aside, finding drivers for older versions of Windows was quite easy, but Profilic won't support their older PL-2303HXA and PL-2303X chips under Windows 8, using this as a stick to encourage people to buy their newer PL2303TA chip instead. Ouch.

For Linux there drivers should be already installed - so I went with that. Here's an excerpt from the Raspberry Pi boot log (with the GSP-360 dongle as the only external USB device plugged in):

$ dmseg
...
[   38.098548] usb 1-1.3: new full-speed USB device number 4 using dwc_otg
[   38.200535] usb 1-1.3: New USB device found, idVendor=067b, idProduct=aaa0
[   38.200565] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[   38.200581] usb 1-1.3: Product: USB-Serial Controller
[   38.200595] usb 1-1.3: Manufacturer: Prolific Technology Inc.
[   38.200608] usb 1-1.3: SerialNumber: 12345678
[   38.270238] usbcore: registered new interface driver usbserial
[   38.272087] USB Serial support registered for generic
[   38.273859] usbcore: registered new interface driver usbserial_generic
[   38.273887] usbserial: USB Serial Driver core
[   38.283343] USB Serial support registered for pl2303
[   38.283511] pl2303 1-1.3:1.0: pl2303 converter detected
[   38.290249] usb 1-1.3: pl2303 converter now attached to ttyUSB0
[   38.291944] usbcore: registered new interface driver pl2303
[   38.291972] pl2303: Prolific PL2303 USB to serial adaptor driver

As per that log, the new serial port is available as /dev/ttyUSB0

$ ls -l /dev/ttyUSB0 
crw-rw---T 1 root dialout 188, 0 Oct 11 15:57 /dev/ttyUSB0

I'm using the default image here, username 'pi', and I am therefore a member of the dialout group so should be able to connect to this device:

$ groups
pi adm dialout cdrom sudo audio video plugdev games users input

Strangely I didn't (immediately) get anything from the device using a low level check:

$ cat /dev/ttyUSB0
(nothing)


GPSD

It seems the main low-level GPS software for Linux is gpsd, so I installed that and tried to run it.

$ sudo apt-get install gpsd gpsd-clients
...

Encouragingly the GPSD hardware page says support for the Microsoft GPS-360 is good, they test it before each release, and it should be plumbed into the Linux hotplug system to start gpsd automatically.

Rebooting with the GPS attached should create /dev/gps0 as an alias for /dev/ttyUSB0 and start the gpsd daemon automatically, check with:

$ ps -e | grep gpsd
  307 ?        00:00:00 gpsd

In this case it is running (with process identifier 307). Similarly, if you boot up without the dongle and then plug it in, it should be recognised as gpsd started automatically. If it is running, this should kill it (advice from the GPSD Troubleshooting page):

$ sudo killall gpsd
$ sudo rm /var/run/gpsd.sock

You can (re)start it manually with:

$ gpsd /dev/ttyUSB0 

I then tried a little test (with the daemon off):

$ gpsctl -f -n /dev/ttyUSB0
gpsctl:SHOUT: vendor/product match with 091e:0003 not found
gpsctl:ERROR: packet recognition timed out.

That isn't good... the -f meant without using the deamon mode of gpsd, the -n meant switch to NMEA mode. When it works I got this and could look at the raw NMEA output:

$ gpsctl -f -n /dev/ttyUSB0
gpsctl:SHOUT: vendor/product match with 091e:0003 not found
gpsctl:SHOUT: /dev/ttyUSB0 identified as a SiRF binary at 4800.
gpsctl:SHOUT: switching to mode NMEA.

$ cat /dev/ttyUSB0 
$GPGGA, ...

Incidentally, until I read this blog post about why GPS support sucks, I'd been under the impression that NMEA 0183 was a good standard.

The GPSD Troubleshooting suggests starting with xgps or cgps. When cgps works:

$ cgps
┌───────────────────────────────────────────┐┌─────────────────────────────────┐
│    Time:       2012-10-11T17:06:42.920Z   ││PRN:   Elev:  Azim:  SNR:  Used: │
│    Latitude:    56.XXXXXX N               ││   1    XX    XXX    XX      Y   │
│    Longitude:    3.XXXXXX W               ││  11    XX    XXX    XX      Y   │
│    Altitude:   58.9 m                     ││  32    XX    XXX    XX      Y   │
│    Speed:      1.4 kph                    ││  20    XX    XXX    XX      Y   │
│    Heading:    215.3 deg (true)           ││  14    XX    XXX    XX      Y   │
│    Climb:      12.8 m/min                 ││  28    XX    XXX    XX      Y   │
│    Status:     3D FIX (3 secs)            ││  19    XX    XXX    XX      Y   │
│    Longitude Err:   +/- 10 m              ││  17    XX    XXX    XX      Y   │
│    Latitude Err:    +/- 11 m              ││  11    XX    XXX    XX      Y   │
│    Altitude Err:    +/- 32 m              ││                                 │
│    Course Err:      n/a                   ││                                 │
│    Speed Err:       +/- 84 kph            ││                                 │
│    Time offset:     0.509                 ││                                 │
│    Grid Square:     IO86kk                ││                                 │
└───────────────────────────────────────────┘└─────────────────────────────────┘
{"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/ttyUSB0","activated":"2012-10-11T17:06:39.461Z","flags":1,"driver":"SiRF binary","subtype":...

I've masked out my exact location. Note CPU usage running gpsd and cgps with the default SiRF binary protocol was about 8%.

However, after rebooting and immediately running cgps it starts, waits for a bit with missing location information, then quits with a time out:

$ cgps
┌───────────────────────────────────────────┐┌─────────────────────────────────┐
│    Time:       n/a                        ││PRN:   Elev:  Azim:  SNR:  Used: │
│    Latitude:   n/a                        ││                                 │
│    Longitude:  n/a                        ││                                 │
│    Altitude:   n/a                        ││                                 │
│    Speed:      n/a                        ││                                 │
│    Heading:    n/a                        ││                                 │
│    Climb:      n/a                        ││                                 │
│    Status:     NO FIX (0 secs)            ││                                 │
│    Longitude Err:   n/a                   ││                                 │
│    Latitude Err:    n/a                   ││                                 │
│    Altitude Err:    n/a                   ││                                 │
│    Course Err:      n/a                   ││                                 │
│    Speed Err:       n/a                   ││                                 │
│    Time offset:     n/a                   ││                                 │
│    Grid Square:     n/a                   ││                                 │
└───────────────────────────────────────────┘└─────────────────────────────────┘
{"class":"WATCH","enable":true,"json":true,"nmea":false,"raw":0,"scaled":false,"timing":false}
cgps: GPS timeout

I also ran into this:

$ gpsctl -n /dev/ttyUSB0
gpsctl:ERROR: error 'Multiple subscribers, cannot change control bits on /dev/ttyUSB0.'
gpsctl:ERROR: /dev/ttyUSB0 mode change to NMEA failed

And:

$ cat /dev/ttyUSB0 
cat: /dev/ttyUSB0: Device or resource busy

I'm not quite sure what is going on here. I suspect a problem in how gpsd is started automatically (possibly Debian or Raspian specific?). What does seem to work is a cold restart (from power off) with the dongle attached, log in, kill and restart gpsd, and then run cgps.


GPS Babel

The  Open Street-Map on their instructions for uploading GPS tracks request GPX format and recommend GPS Babel to generate this. At the time of writing the latest release is GPSBabel 1.4.4, the repository hasn't caught up yet as this gave me v1.4.3:

$ sudo apt-get install gpsbabel
...

$ gpsbabel -V

GPSBabel Version 1.4.3

Then (provided that everything was co-operating - see above), I could use the gpsd utility to switch the output to NMEA mode, capture some of that to a file, and convert it into GPX format using gpsbabel:

$ gpsctl -f -n /dev/ttyUSB0
gpsctl:SHOUT: vendor/product match with 091e:0003 not found
gpsctl:SHOUT: /dev/ttyUSB0 identified as a SiRF binary at 4800.
gpsctl:SHOUT: switching to mode NMEA.
$ cat /dev/ttyUSB0 
$GPGGA,...
^C
$ cat /dev/ttyUSB0 > temp.nmea
^C
$ gpsbabel -i nmea -f temp.nmea -o gpx -F temp.gpx
$ head temp.gpx 
<?xml version="1.0" encoding="UTF-8"?>
<gpx
  version="1.0"
  creator="GPSBabel - http://www.gpsbabel.org"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.topografix.com/GPX/1/0"
  xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
<time>2012-10-11T18:17:34Z</time>
<bounds minlat="56.xxxxxxxxx" minlon="-3.xxxxxxxxx" maxlat="56.xxxxxxxxx" maxlon="-3.xxxxxxxxx"/>
<trk>

In principle that should work with the SiRF binary format, but perhaps something is going wrong when I try to capture a random section with since the GPX file is essentially empty (valid XML, but no actual data unlike the NMEA capture above):

$ gpsctl -f /dev/ttyUSB0
gpsctl:SHOUT: vendor/product match with 091e:0003 not found
gpsctl:SHOUT: /dev/ttyUSB0 identified as a SiRF binary at 4800.
$  cat /dev/ttyUSB0 > temp.sbn 
^C
$ gpsbabel -i sbn -f temp.sbn -o gpx -F temp.gpx
$ more temp.gpx 
<?xml version="1.0" encoding="UTF-8"?>
<gpx
  version="1.0"
  creator="GPSBabel - http://www.gpsbabel.org"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.topografix.com/GPX/1/0"
  xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
<time>2012-10-11T18:25:47Z</time>
</gpx>

That was rather tortuous. But with the rough edges sorted out could work as the basis of a GPS track logger.

Update

Here's a link to Peter Mount's blog post using a GPS dongle and Raspberry Pi as an NTP server (Network Time Protocol), useful as a way to set the clock on a RPi as it has no internal battery like a normal PC - meaning it needs a network connection or other external system to set the time and date. It seems he is also wondering about connecting his Raspberry Pi to his telescope...

Update

Here's a link to David Taylor's GSP based Raspberry Pi NTP server page, incredibly detailed including how to use Pulse Per Second (PPS) for improved precision.

5 comments:

  1. Thank you very much for sharing all this. It helped me to get this same hw configuration running.

    ReplyDelete
  2. How to fix this error,

    gpsctl:SHOUT: vendor/product match with 091e:0003 not found
    gpsctl:ERROR: packet recognition timed out.

    I am consistently getting ot when converting the OP into NMEA

    ReplyDelete
  3. We have found that a number NMEA GPS receivers time output actually jumps either side of the PPS output, making the provision of a stable time quite difficult. We have generally found Trimble parts very good, but can be quite expensive.

    ReplyDelete
  4. Regarding the issue of booting, killing gpsd and restarting it, I was having the same problem too. It seems that gpsd is getting started via systemd and thus no arguments were being provided to the daemon including the path to the GPS device. After much searching, I came across a thread at http://www.raspberrypi.org/forums/viewtopic.php?f=45&t=53644 which gave two solutions. I chose the solution of disabling USB hot-plugging of the GPS device via "dpkg-reconfigure gpsd". By selecting "no" to the question "Should gpsd handle attached USB GPS receivers automatically" it works fine now. I boot the Raspberry and gpsd is running with the correct arguments as long as I have the GPS connected at boot. I am planning to use this device as a time server (in addition to an ADS-B monitor) so having it be able to reboot itself without human intervention is very important.

    ReplyDelete
  5. Thank you for putting this online, it was a huge help trying to set up an old GPS-360 on my Pi.

    I also used the thread Aardvark mentioned, and followed amrbekhit advice adding two lines to /etc/default/gpsd

    GPSD_OPTIONS="/dev/ttyACM0"
    GPSD_SOCKET="/var/run/gpsd.sock"

    Thanks again for this post and the comments!

    ReplyDelete