Here are three examples of how to use python to get GPS data from a GPS receiver attached to a Raspberry Pi.
- Using GPSD client libraries
- Manually parsing NMEA sentences
- Using pynmea2 to parse NMEA sentences
GPSD client libraries
The gpsd client libraries are based on JSON. The JSON objects have a “class” attribute (E.g. TPV, SKY, DEVICE.etc…) which can be used to filter on different information.
This guide shows how to get gpsd up an running on a Raspberry Pi.
The example python script below filters on the TPV class, which is the Time Position Velocity report and then prints out the relevant information.
#! /usr/bin/python from gps import * import time gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE) print 'latitude\tlongitude\ttime utc\t\t\taltitude\tepv\tept\tspeed\tclimb' # '\t' = TAB to try and output the data in columns. try: while True: report = gpsd.next() # if report['class'] == 'TPV': print getattr(report,'lat',0.0),"\t", print getattr(report,'lon',0.0),"\t", print getattr(report,'time',''),"\t", print getattr(report,'alt','nan'),"\t\t", print getattr(report,'epv','nan'),"\t", print getattr(report,'ept','nan'),"\t", print getattr(report,'speed','nan'),"\t", print getattr(report,'climb','nan'),"\t" time.sleep(1) except (KeyboardInterrupt, SystemExit): #when you press ctrl+c print "Done.\nExiting."
This python script filters on the SKY class and prints out satellite information.
#! /usr/bin/python from gps import * import time import os gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE) try: while True: report = gpsd.next() # if report['class'] == 'SKY': os.system('clear') print ' Satellites (total of', len(gpsd.satellites) , ' in view)' for i in gpsd.satellites: print 't', i print '\n\n' print 'PRN = PRN ID of the satellite. 1-63 are GNSS satellites, 64-96 are GLONASS satellites, 100-164 are SBAS satellites' print 'E = Elevation in degrees' print 'As = Azimuth, degrees from true north' print 'ss = Signal stength in dB' print 'used = Used in current solution?' time.sleep(1) except (KeyboardInterrupt, SystemExit): #when you press ctrl+c print "Done.\nExiting."
Manually parsing NMEA sentences
The python script below shows how to access GPS data by connecting directly to the serial interface.
It filters on $GPRMC NMEA sentences and then splits the well know attributes into different variables.
import serial port = "/dev/serial0" def parseGPS(data): # print "raw:", data #prints raw data if data[0:6] == "$GPRMC": sdata = data.split(",") if sdata[2] == 'V': print "no satellite data available" return print "---Parsing GPRMC---", time = sdata[1][0:2] + ":" + sdata[1][2:4] + ":" + sdata[1][4:6] lat = decode(sdata[3]) #latitude dirLat = sdata[4] #latitude direction N/S lon = decode(sdata[5]) #longitute dirLon = sdata[6] #longitude direction E/W speed = sdata[7] #Speed in knots trCourse = sdata[8] #True course date = sdata[9][0:2] + "/" + sdata[9][2:4] + "/" + sdata[9][4:6]#date print "time : %s, latitude : %s(%s), longitude : %s(%s), speed : %s, True Course : %s, Date : %s" % (time,lat,dirLat,lon,dirLon,speed,trCourse,date) def decode(coord): #Converts DDDMM.MMMMM > DD deg MM.MMMMM min x = coord.split(".") head = x[0] tail = x[1] deg = head[0:-2] min = head[-2:] return deg + " deg " + min + "." + tail + " min" print "Receiving GPS data" ser = serial.Serial(port, baudrate = 9600, timeout = 0.5) while True: data = ser.readline() parseGPS(data)
Using pynmea2 to parse NMEA sentences
The python script below shows how to access GPS data by connecting directly to the serial interface.
It filters on $GPGGA NMEA sentences and then uses pynmea2 to parse the data.
Pynmea2 can be installed with;
import serial import pynmea2 port = "/dev/serial0" def parseGPS(str): if str.find('GGA') > 0: msg = pynmea2.parse(str) print "Timestamp: %s -- Lat: %s %s -- Lon: %s %s -- Altitude: %s %s -- Satellites: %s" % (msg.timestamp,msg.lat,msg.lat_dir,msg.lon,msg.lon_dir,msg.altitude,msg.altitude_units,msg.num_sats) serialPort = serial.Serial(port, baudrate = 9600, timeout = 0.5) while True: str = serialPort.readline() parseGPS(str)
How to specify a remote gpsd server?
What instance would you use NMEA over GPSD?
This is the first time I’ve looked into using pi for gps so keep it simple please 🙂
Thank you very much you have helped me immensely putting a link to the documentation. I was using SKY for the longest time and wondering why I wasn’t able to get all of the data I wanted.
Regarding the question on using gpsd versus nmea. The gpsd client is a full featured gps interface that enables high level programming interface for gps data for lots of conceiveable applications but the price for that is the application programmer does not have visibility into the actual performance of the gps interface and the data. The gps function involves satellites that may or may not be in view and a fairly weak signal that is not received reliably (like not indoors- not unless the signal can leak into the building .) The gpsd software library may not converge for many minutes to compute a gps location so if you application uses a gps computed location of the receiver the programmer must deal with variable delays. With the nmea the software interface to the receiver just uses the serial port and gives access to the low level data which is text based characters, The data is easily parsed and so the programmer can can just check the message streams for a message type that has information his/her application needs. NMEA messages are computed by the gps receiver every second. If the receiver can’t figure out a location solution a message like the $GGA message will have something like “-/-” in a lat/long field. The application program can then keep reading messages until lat/long shows numbers or report a status of a problem. Much simpler to program but certainly not full featured. The trade-off is for the programmer to decide how to use the gps receiver interface and then make the function robust.
Is there a way to specify which serial port the gps library gathers data from? I’m using the USB to USB connector between the GPS/GSM and rPi so my NMEA sentences are piped to ttyACM3, not serial0
The first and second pieces of code use GPSD, which means you would need to update the GPSD config file;
sudo nano /etc/default/gpsd
And for the 3rd example, you can change the port on line 3
Is there any example Python code showing how to read the GPS using the i2c interface on a Raspberry Pi ?
I am in the middle of writing up a guide for this, it should be completed by the end of this week.
Here you go
https://ozzmaker.com/accessing-gps-via-i2c-on-a-berrygps-imu/
Hi
I have a G-STAR IV GPS receiver, and I want to get the $GPZDA to get the time and i want to get the : Hoarse, Minutes, Seconds, and Milliseconds from the GPS from the Raspberry Pi code.
How can I write a code that can give me the GPS time including the Milliseconds ?
thank you
Thanks for this useful information. I am trying to parse using your $GPRMC example, however my raw data looks like this:
b’$GPRMC,……..etc,N*7F\r\n’
Consequently it never finds anything to parse.
Any idea why I have the extra characters at each end of the GPRMC sentence? I am using a GPS on a usb serial port on a RaspberryPi.
Thanks
It looks like there is something else wrong – the extra characters “b” and “\r\n” are not part of the data and are not causing a problem. The problem is that the “if data[0:6] ==”$GPRMC”: statement never comes true even if data[0:6] is $GPRMC. I’ve not used python before so maybe I’m missing the obvious…
OK, so i eventually worked out that the b means the data is binary. However the code is written for string. Easily fixed by changing
str = serialPort.readline()
to
str = serialPort.readline().decode()