Getting GPSd to work with Python and Threading

I bought a few Raspberry Pis with great ambition of doing something awesome with them. Beyond showing my co-workers how cool I was for having them, the Raspberry Pis  pretty much just sat on my desk collecting dust. A month or two after getting them I realized that the Pis would fit nicely into our RallyRecorder project as a GPS tracker/recorder. Previously we had this running on a netbook with a USB GPS receiver using GPSd, a combination of command-line PHP and shell scripts, and MySQL. With the reduced specs on the Raspberry Pi (700 MHz, 256 MB RAM), I wanted to go with something with a little less overhead. Wisely or not, I chose Python and SQLite. Not having worked with either of the before, it should also provide a nice challenge.

After I started looking around the web for info about getting GPSd working with Python, I quickly found that any information was out of date, out of version, or just didn’t compile. It didn’t help that I started learning Python last night. Hey, go big or go home, right?

First we’ll quickly go through how to get all of the software prereqs. This is written for the Raspberry Pi but should work on most Linux distros too.

Required Hardware

  • Raspberry Pi with Debian Wheezy installed (or something running Linux)
  • GPSd compatible GPS Receiver (I used this one)

Getting the Software

If you have a USB GPS receiver, don’t plug it in yet.

From the command-line, enter the following command to install Python, GPSd, and the Python modules to bring them together.

sudo apt-get install python gpsd gpsd-clients

If you have a USB receiver, you can plug it in now. For Bluetooth and serial receivers, you’re on your own for this step. Plugging in the USB receiver should start GPSd automatically. To make sure that GPSd is playing nice, you can open cgps to see what data it is receiving.

cgps

After your GPS receiver has a satellite fix, it should look something like this:

Reading GPS data with Python

Now that GPSd is communicating successfully with your receiver and you have the right software installed, we can read in the GPS data through Python. The code below uses threading to get every GPS update (otherwise the buffer fills up) and when requested (lines 31-54) fetches the most recent set of data. You can replace lines 31-54 with whatever you want to do with the data. I plan on storing unique points in a SQLite database (maybe in a follow-up post).

#! /usr/bin/python
# Written by Dan Mandle http://dan.mandle.me September 2012
# License: GPL 2.0

import os
from gps import *
from time import *
import time
import threading

gpsd = None #seting the global variable

os.system('clear') #clear the terminal (optional)

class GpsPoller(threading.Thread):
	def __init__(self):
		threading.Thread.__init__(self)
		global gpsd #bring it in scope
		gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
		self.current_value = None
		self.running = True #setting the thread running to true

	def run(self):
		global gpsd
		while gpsp.running:
			gpsd.next() #this will continue to loop and grab EACH set of gpsd info to clear the buffer

if __name__ == '__main__':
	gpsp = GpsPoller() # create the thread
	try:
		gpsp.start() # start it up
		while True:
			#It may take a second or two to get good data
			#print gpsd.fix.latitude,', ',gpsd.fix.longitude,'	Time: ',gpsd.utc

			os.system('clear')

			print
			print ' GPS reading'
			print '----------------------------------------'
			print 'latitude    ' , gpsd.fix.latitude
			print 'longitude   ' , gpsd.fix.longitude
			print 'time utc    ' , gpsd.utc,' + ', gpsd.fix.time
			print 'altitude (m)' , gpsd.fix.altitude
			print 'eps         ' , gpsd.fix.eps
			print 'epx         ' , gpsd.fix.epx
			print 'epv         ' , gpsd.fix.epv
			print 'ept         ' , gpsd.fix.ept
			print 'speed (m/s) ' , gpsd.fix.speed
			print 'climb       ' , gpsd.fix.climb
			print 'track       ' , gpsd.fix.track
			print 'mode        ' , gpsd.fix.mode
			print
			print 'sats        ' , gpsd.satellites

			time.sleep(5) #set to whatever

	except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
		print "\nKilling Thread..."
		gpsp.running = False
		gpsp.join() # wait for the thread to finish what it's doing
	print "Done.\nExiting."

To use this code, copy/paste all of it in to a text editor of you choosing and save it as gpsdData.py. You can then run it with the following command:

python gpsdData.py

I am by no means an expert in well… anything. But this does work with GPSd 3.6, Python 2.7.3, and Debian Wheezy. I am all ears with ways to make this better and more efficient. Please let me know in the comments.

Some resources that helped me put this all together:

Donate Dogecoin: DJoF2AUA7HyoQEhwmSG5jCSHJorFZWNd9p
Donate Bitcoins

28 responses to “Getting GPSd to work with Python and Threading

  1. Get the hardware then make the plan. Learn a language for a project. I love everything about this!

  2. Josh B.

    Thanks for this!

  3. Pingback: GPS Python Module Error | Code and Programming

  4. Nick

    Excellent! Thanks!!

  5. I have the exact same environment as you , but I get this error:

    Traceback (most recent call last):
    File “gps.py”, line 29, in
    gpsp = GpsPoller() # create the thread
    File “gps.py”, line 19, in __init__
    gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
    NameError: global name ‘gps’ is not defined

  6. Sorcier_FXK

    Thank’s a lot for your snippet, realy usefull & interesting :)

  7. JRI

    Thanks for your post – it helped me get a gpsd output in python. It made me realise that gps.fix doesn’t hold any useful data until you have called gps.next() enough times to read in some helpful status lines from gpsd.

    Also, I managed to get it working with a QStarz bluetooth gps. I used “sudo apt-get install bluetooth bluez-utils –no-install-recommends” to install a minimal set of bluetooth drivers (no GUI support), then used the instructions at http://www.catb.org/gpsd/bt.html to set up the RFCOMM port and configure gpsd to use it from startup.

    The only catch I had was getting my bluetooth dongle working. To start with I could detect the USB dongle, but not bring up the interface with hcitool. I had to add “dwc_otg.speed=1″ to my /boot/cmdline.txt file. That downgrades the speed of the USB bus from USB 2.0 to USB 1.1 – it seems there is a kernel bug with USB support. While changing the bus speed fixed the problem for me, other people report it causes problems with ethernet and other USB devices.

  8. Nice code Dan!! Worked first time. I’d like to add to your code some things I wanted gpxlogger to do. See the whole project thread here: http://www.raspberrypi.org/phpBB3/viewtopic.php?f=45&t=49852&p=389004#p389004 (raspberry forum, “GPS not working well” thread). As always, will be leaving your authorship on the attribution line at the top.

  9. Pingback: Raspberry Pi Portable 3G/4G Network Quality Logger Project – Part 1 | Anthony Agius

  10. Ben O.

    Thanks Great Code!
    The Adafruit example didn’t work for me

  11. DMD

    Thanks a lot for your post!!! :-) It helped me a lot, I finally get the longitude and latitude data from the GPS in python. At first I also got the same error message (“global name ‘gps’ is not defined”). It turned out I had another program in the same folder called gps.py, after I renamed it, the code worked perfectly.
    I am using a Garmin GPS18xUSB, no other code addressing the GPS device directly worked for me.

  12. Thanks a lot for this, I used your code as the basis for creating my own GPSController class.

    http://www.stuffaboutcode.com/2013/09/raspberry-pi-gps-setup-and-python.html

    • Dan Mandle

      Thanks! I’m glad we can share! I’m ‘borrowing’ your code from your OBD-II reader for the Pi to create a car logger! Been busy, so I haven’t been able to work on it, but I’ll let you know when it’s ready! Also let me know if you’d be interested in collaborating!

  13. Anthony VZ

    Why is there self.current_value = None still in this snippet?
    Leftover from http://stackoverflow.com/questions/6146131/python-gps-module-reading-latest-gps-data ?

  14. Thijs

    Thanks alot, i’m going to use your code for a High altitude balloon project.

  15. maximran

    I have a question, i want to use python for my project, and i already install the gpsd and already copy your coding. However, when i try to run it on idle3, it say there are no module name gps. (error at line 5). What should i do?

    • Dan Mandle

      Unfortunately this is the only project I’ve done with Python, so I can’t help you. Hopefully someone who sees this and can help!

      • maximran

        Owh i see. In this project, you are using idle or idle3?

      • maximran

        Ok, i get the problem. I am using the python 3 (idle3= python 3) and in python 3 there are no modules name GPS.
        now i am using idle (python) , but i encountered a different problem… it related to something with ” non-ASCII character ‘\xc2′ ”
        do you know anything about it?

        • Kolumbus42

          Hello, there is no gps module for python3. But i solved the problem using memory mapped files (shared memory) between a gps requester working with python2 and the gps module and a thread which reads the current coordinates from the shared memory with python3. Both have a class design for reuse.

  16. Markus

    Works like a charm! Thanks!

  17. icon

    Dude, you are my hero ! :)
    Since the info on Python and gpsd from PerryGeo (just google it) is so outdated, it did not work at all.
    Thanks to your little code example, now finally everything works exactly as expected. Fantastic !

  18. hello
    your script is working good for me
    how can i simply log this data on a CSV file

    i have tried different thing but i am not good in programing
    must be simple , but didn t sucess

    thank you , for all your answer

  19. Glidux

    Hi, is there a simple way to tanslate results from gpsdData.py to kml (for Google earth use) ?

  20. Sukotruco

    Hi , this post has been really helpfull…
    I´m really interesting in send the datas to google map in a client pc…
    Thanks

Leave a Reply