Saturday, 9 November 2013

Setting up the GPS

Setting up the GPS

I have been lucky on this.

Apart from the Adafruit Ultimate GPS I recently purchased, I did find in my drawers a
couple more:
As shown in this photo, apart of the Adafruit GPS, I also had a choice from a Garmin 18-5, a 5 Hz device with serial TTL output and a 1-Hz OEM USB GPS,
I decided to use the USB unit because:
A. since the speed -in absolute terms- I will be moving with is low, 1 GPS sample per second is more than sufficient.
B. The USB GPS has a long cable, long enough to put it out of the window now that I am doing the development, something that enables the system to get a fix!

Setting it up was plain simple:
1. Installed the required packages:
sudo apt-get install gpsd gpsd-clients python-gps
2. Associate gpsd with the physical GPS device:
sudo gpsd /dev/ttyUSB0 -F /var/run/gpsd.sock

The setup was verified using the following command:
cgps -s

This produced the following result:
Which mean that the GPS works and communicates with the Raspberry.
Further tests where conducted using Python:
#!/usr/bin/python
import gps
session = gps.gps("localhost", "2947")
session.stream(gps.WATCH_ENABLE | gps.WATCH_NEWSTYLE)
while True:
    try:
        report = session.next()
        print report
    except KeyError:
        pass
    except KeyboardInterrupt:
        quit()
    except StopIteration:
        session = None
        print "GPSD has terminated"

gpsd documentation can be found at gpsd home, and a quickstart how-to can be seen here.
At this document one can find info on the gpsd report structure which has as follows:

NameAlways?TypeDescription
classYesstringFixed: "TPV"
tagNostringType tag associated with this GPS sentence; from an NMEA device this is just the NMEA sentence type.
deviceNostringName of originating device.
modeYesnumericNMEA mode: %d, 0=no mode value yet seen, 1=no fix, 2=2D, 3=3D.
timeNostringTime/date stamp in ISO8601 format, UTC. May have a fractional part of up to .001sec precision. May be absent if mode is not 2 or 3.
eptNonumericEstimated timestamp error (%f, seconds, 95% confidence). Present if time is present.
latNonumericLatitude in degrees: +/- signifies West/East. Present when mode is 2 or 3.
lonNonumericLongitude in degrees: +/- signifies North/South. Present when mode is 2 or 3.
altNonumericAltitude in meters. Present if mode is 3.
epxNonumericLongitude error estimate in meters, 95% confidence. Present if mode is 2 or 3 and DOPs can be calculated from the satellite view.
epyNonumericLatitude error estimate in meters, 95% confidence. Present if mode is 2 or 3 and DOPs can be calculated from the satellite view.
epvNonumericEstimated vertical error in meters, 95% confidence. Present if mode is 3 and DOPs can be calculated from the satellite view.
trackNonumericCourse over ground, degrees from true north.
speedNonumericSpeed over ground, meters per second.
climbNonumericClimb (positive) or sink (negative) rate, meters per second.
epdNonumericDirection error estimate in degrees, 95% confidence.
epsNonumericSpeed error estinmate in meters/sec, 95% confidence.
epcNonumericClimb/sink error estimate in meters/sec, 95% confidence.


For example, the following code
#!/usr/bin/python
import gps
# Listen on port 2947 (gpsd) of localhost
session = gps.gps("localhost", "2947")
session.stream(gps.WATCH_ENABLE | gps.WATCH_NEWSTYLE)

while True:
    try:
        report = session.next()
        # Wait for a 'TPV' report
        if report['class'] == 'TPV':
            print 'fix mode:', report.mode
            print 'Course over ground, degrees from true north', report.track
            print 'Speed over ground, meters per second', report.speed
            print '-----------------------------------------------------------------'
    except KeyError:
        pass
    except KeyboardInterrupt:
        quit()
    except StopIteration:
        session = None
        print "GPSD has terminated"

produces this output:
fix mode: 2
Course over ground, degrees from true north 0.0
Speed over ground, meters per second 0.0
-----------------------------------------------------------------
fix mode: 2
Course over ground, degrees from true north 0.0
Speed over ground, meters per second 0.0
-----------------------------------------------------------------
This report says that we have 2D fix (possibly a result of not having a good view of the sky) and that we are stationary.



This concludes post "Setting up the GPS".

Additional details will be found in future post with title something in the line of "GPS Software"



References:
GPSD Home
GPSD Client HOWTO
GPSD Result Structures
The Architecture of Open Source Applications, GPSD
GPS Protocol Reference Manual


UPDATE:
After rebooting the Raspberry PI, gpsd didn't seem to work.
I did some debuging using
gpsmon /dev/ttyUSB0 
This showed that hardware-wise the GPS was working.
The same time gpsd daemon was running and hooked to TCP port 2947.
I killed the process and started it again manually giving
/usr/sbin/gpsd -n -F /var/run/gpsd.sock -P /var/run/gpsd.pid /dev/ttyUSB0
gpsd & cgps got working.
Reboot caused once again the same issue.
I check the default gpsd config (cat /etc/default/gpsd) but looked OK.
I reconfigured the gpsd using "dpkg-reconfigure gpsd" but on reboot I had the same issue.
I decided to take matters in hand, "runlevel" indicated the Raspberry was running in level 2.
I deleted the S04gpsd file from /etc/rc2.d (a link to /etc/init.d/gpsd) and added the above command ("/usr/sbin/gpsd -n -F /var/run/gpsd.sock -P /var/run/gpsd.pid /dev/ttyUSB0" to the end of the /etc/rc.local file.

Now the system works everytime.

It's probably a quick and dirty solution but for the time being it works.

The actual solution to the initial problem came by adding the -n flag ("don't wait for client connect to poll GPS") to the gpsd initialization.

UPDATE 2:
few more problems with gpsd, sometimes after reboot, gpsd was running but gpsd.pid had wrong id.
Quick and dirty solution by removing the line
/usr/sbin/gpsd -n -F /var/run/gpsd.sock -P /var/run/gpsd.pid /dev/ttyUSB0
and adding
pkill gpsd
service gpsd start
on the /etc/rc.local