Thursday, 19 September 2013

Raspberry Pi - GPS Setup and Python

I got myself one of adafruit's ultimate GPS breakout boards as I want to experiment with capturing GPS data in my car projects.  Its a seriously good bit of kit and if you looking for a GPS module you could do a lot worse than this.  They also have an excellent tutorial on setting it up with the raspberry pi, http://learn.adafruit.com/adafruit-ultimate-gps-on-the-raspberry-pi.

If your in the UK, I noticed that they had them on amazon and pimoroni.

I used the raspberry pi's on board UART to connect to the GPS module, Adafruit advocate using a USB to serial device but that didn't suit my needs (I need the USB for other things).

I also create a GPSController class in python to allow me to communicate with the module easily.



Connecting the GPS module
Wiring it up is pretty simple:
  • Raspberry Pi - 5v -> GPS Module - VIN
  • Raspberry Pi - GND -> GPS Module - GND
  • Raspberry Pi - Tx -> GPS Module - Rx
  • Raspberry Pi - Rx -> GPS Module - Tx

Enable the UART
By default the UART is enabled to allow you to connect a terminal window and login, I needed to disable this to free it up for the GPS Module.

Edit the boot options to change the UART so it doesnt provide a terminal connection by default:

sudo nano /boot/cmdline.txt

The contents looks like this (yours might be slightly different depending on your distribution):

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

remove the following config from the file and save it.

console=ttyAMA0,115200 
kgdboc=ttyAMA0,115200

Change inittab so it doesnt spawn a login to the serial connection:

sudo nano /etc/inittab

Change:

#Spawn a getty on Raspberry Pi serial line
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

to:

#Spawn a getty on Raspberry Pi serial line
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

Reboot

sudo shutdown -r now

Install GPSD
GPSD is an open source project which provides a daemon which streams GPS data via a TCP socket, allowing you to communicate with a whole host of different GPS devices (not just this one):

sudo apt-get install gpsd gpsd-clients python-gps

Run gpsd
GPSD needs to be started up, using the following command:

sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock

Test gpsd
There is a simple GPS client which you can run to test everything is working:

cgps -s

It may take a few seconds for data to come through, but you should see a screen like this:



Python code
In order to control and capture the GPS data in python I started looking round for some code, this took me to http://www.danmandle.com/blog/getting-gpsd-to-work-with-python which I used as a starting point for creating this python GPSController class.  It uses threading to continuously read the stream of data from GPSD and present it as properties of the class.

There is a more in depth example of how to use the class in the code below, but in simple terms you use it like this:

#create controller
gpsc = GpsController()

#start controller
gpsc.start()

#read latitude and longitude
print gpsc.fix.latitude
print gpsc.fix.longitude

#stop controller
gpsc.stopController()

Note - you may have to wait a few seconds for the data to start streaming

GPSController.py

from gps import *
import time
import threading
import math

class GpsController(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
        self.running = False
   
    def run(self):
        self.running = True
        while self.running:
            # grab EACH set of gpsd info to clear the buffer
            self.gpsd.next()

    def stopController(self):
        self.running = False
 
    @property
    def fix(self):
        return self.gpsd.fix

    @property
    def utc(self):
        return self.gpsd.utc

    @property
    def satellites(self):
        return self.gpsd.satellites

if __name__ == '__main__':
    # create the controller
    gpsc = GpsController() 
    try:
        # start controller
        gpsc.start()
        while True:
            print "latitude ", gpsc.fix.latitude
            print "longitude ", gpsc.fix.longitude
            print "time utc ", gpsc.utc, " + ", gpsc.fix.time
            print "altitude (m)", gpsc.fix.altitude
            print "eps ", gpsc.fix.eps
            print "epx ", gpsc.fix.epx
            print "epv ", gpsc.fix.epv
            print "ept ", gpsc.gpsd.fix.ept
            print "speed (m/s) ", gpsc.fix.speed
            print "climb ", gpsc.fix.climb
            print "track ", gpsc.fix.track
            print "mode ", gpsc.fix.mode
            print "sats ", gpsc.satellites
            time.sleep(0.5)

    #Error
    except:
        print "Unexpected error:", sys.exc_info()[0]
        raise

    #Ctrl C
    except KeyboardInterrupt:
        print "User cancelled"

    finally:
        print "Stopping gps controller"
        gpsc.stopController()
        #wait for the tread to finish
        gpsc.join()
     
    print "Done"



38 comments:

  1. how can you give 5v to raspberry pi.....???

    ReplyDelete
    Replies
    1. Im not sure I understand your question. But, if your talking about how do I wire the GPS unit up. I take the 5v line from the raspberry pi gpio and connect it to the VIN on the gps module.

      I dont give the raspberry pi 5v!

      Delete
  2. What is the correct way to test if:
    1) the GPS unit is present, ie: is there an error code genberated when gpsc.start() is run and even though gpsd is running, there is no GPS unit attached?
    2) test to see if the data read is good? At the moment, I just loop until lat/log are both no longer 0.0.

    thanks.

    ReplyDelete
    Replies
    1. I dont know a better way to be honest, ive not looked into it, if you find out let me know though

      Delete
  3. Which gps module are you use?

    ReplyDelete
    Replies
    1. adafruit gps ultimate breakout board (see link at the top of the page)

      Delete
  4. hi martin.where should i go to create the python GPSController class

    ReplyDelete
  5. Is there a kit that would allow the GPS to automatically download via wifi when the vehicle returns home? Thx

    ReplyDelete
    Replies
    1. I dont know of a 'kit' but it doesnt sound like a particularly difficult problem to code. A script which runs every x minutes, if it can find a connection, it copies the file of gps data to a share.

      Delete
  6. when i reboot my raspberry doesnt turn on again ... looks like a broke boot particion, i had to reinstall 3 times ._. some idea why ?

    ReplyDelete
    Replies
    1. Knackered SD Card? Have you tried using a different one?

      Delete
    2. I get the same problem I'm afraid. After reboot I get a kernel issue and have to reload. Tried another SD and the same thing happens. I don't think all packages were 100% up to date, so im going to give it another shot.

      Delete
    3. Did you have any luck? I have never experienced this problem before?

      Delete
    4. Any one else had luck with this. Im getting the same problem

      Delete
    5. Right I have managed to re-produce the error. Its because the raspbian / noobs setup has changed. Where I originally said:

      Change:

      dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

      to:

      dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

      You need to just remove the:

      console=ttyAMA0,115200 kgdboc=ttyAMA0,115200

      parts.

      If you cut and paste my code directly it would have resulted in raspbian being unable to find the root and the kernal error. Ive updated the post.

      Delete
    6. Hello,

      I had a problem with this part of the code:

      #Spawn a getty on Raspberry Pi serial line
      T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

      to:

      #Spawn a getty on Raspberry Pi serial line
      #T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

      When I would try to reboot..nothing would happen! It's like I had to re-install everything on the sd-card. I rebooted my pc with a debian live cd and change the above code back. My PI booted back like normal.

      In order not to run into this problem again:

      on console I entered :

      sudo raspi-config In the software configuration tool select option 8 then select option A7 Serial and select NO.
      Select OK and close app.
      In console enter:

      sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock
      cgps -s

      wait for gps data

      That was my work around for serial (none USB method)
      The last two steps have to be re-entered everytime you reboot. Just for testing reasons I did not automatically had it run on boot time.

      Delete
  7. I can't run GPScontroll.py
    Why occured this error?

    pi@raspberrypi ~ $ python GPSController.py
    File "GPSController.py", line 53
    time.sleep(0.5)
    SyntaxError: default 'except:' must be last

    ReplyDelete
    Replies
    1. It sounds like a code indentation problem. Did you cut and paste the code from the page? Did it cut and paste properly?

      Delete
    2. I got the same error, but managed to fix it. The lines
      except:
      print "Unexpected error:", sys.exc_info()[0]
      raise
      must be moved so they come _after_
      except KeyboardInterrupt:
      print "User cancelled"

      Thanks for the excellent write-up Martin!
      Cheers, Lars

      Delete
  8. Hi,

    do you know how to send the data you get from GPSController.py to a html page on webiopi?

    Cheers.

    ReplyDelete
    Replies
    1. I have never looked at webiopi. I doubt it would be too difficult though.

      Delete
  9. I am trying to run this on a RPi in idle3 with the adafruit ultimate gps but I keep getting a syntax error on the quotation Mark after latitude. Help!

    ReplyDelete
    Replies
    1. Ah Python 3. I wrote this in Python 2. Its probably because Python 3 expects While(True): and print("hello") - note the brackets. I cant guarantee there wont be other python 2 - 3 issues.

      Delete
  10. This is really useful, great!
    but by the way, how to send the output data (longitude and latitude) from py code to website (html)? Is it need other library or package? or if I start the gpsd I can be able to call the longitude and latitude in html without python code like this example http://www.w3schools.com/html/html5_geolocation.asp? thank you

    ReplyDelete
  11. Did you use GPS library module in Python 3? How did you do that?

    ReplyDelete
    Replies
    1. Do you mean the GPS modue I wrote (i.e. the one in the blog post)? If so the code I wrote is python 2 but I dont think it would be that difficult to migrate it to Python 3.

      Delete
  12. This comment has been removed by the author.

    ReplyDelete
  13. Hi,
    Thank you very much for posting this tutorial
    I want to ask a question
    if I want to use the USB instead of uart pins
    Do I have to configure something in order to use the python class that you have created
    thank you again and I hope my question is not that stupid :)

    ReplyDelete
    Replies
    1. The python code remains the same, but when you startup gpsd, you need to give it a different device:

      sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock

      change the ttyAMA0 to the usb serial device, sorry I dont know what it is. Im sure google will help though.

      Delete
  14. I get a really bad freeze (I can only kill it with -9) at the .join() line. has anyone else seen this issue?

    ReplyDelete
    Replies
    1. The command gpsc.join() is waiting for the GPS controller to finish. I dont know why it wouldnt stop though. Other than that does it work?

      Delete
  15. It seems to. I have not tested it with a gps receiver, but my program gets nan from it with no problem. I will have to work to test it more thoroughly. I am just not sure why the thread would hang when it works fine if I don't put it in a thread. (but that won't work for my main application.)

    ReplyDelete
    Replies
    1. I dont know, but it could be that its not erroring correctly as its expecting a GPS receiver to be returning data.

      Delete
  16. how to store gps data in database

    ReplyDelete
  17. Sim908 interfacing with raspberry pi...coding and interfacing

    ReplyDelete
  18. Sim908 interfacing with raspberry pi...coding and interfacing

    ReplyDelete
  19. Sim908 interfacing with raspberry pi...coding and interfacing

    ReplyDelete
  20. Sim908 interfacing with raspberry pi...coding and interfacing

    ReplyDelete

Note: only a member of this blog may post a comment.