QGIS has the ability to connect to a GPS that uses the NMEA standard. QGIS can use a serial connection to the GPS or communicate with it through the open source software called gpsd using the QGIS GPS information panel. The location information from the GPS can be displayed on the QGIS map, and QGIS can even automatically pan the map to follow the GPS point. In this recipe, we'll use the QGIS API to process NMEA sentences and update a point on a global map. The information needed to connect to different GPS units can vary widely, so we'll use an online NMEA sentence generator to get some simulated GPS information.
We'll grab a batch of NMEA GPS sentences from a free online generator, create a worldwide basemap using online geojson data, create a vector point layer to represent the GPS, and finally loop through the sentences and make our track point move around the map.
To do this, we need to perform the following steps:
import urllib import urllib2 import time
url = 'http://freenmea.net/api/emitnmea' values = {'types' : 'default'} data = urllib.urlencode(values) req = urllib2.Request(url, data) response = urllib2.urlopen(req) results = response.read().split(" ")
wb = "https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json" basemap = QgsVectorLayer(wb, "Countries", "ogr") qmr = QgsMapLayerRegistry.instance() qmr.addMapLayer(basemap)
vectorLyr = QgsVectorLayer('Point?crs=epsg:4326', 'GPS Point' , "memory") vpr = vectorLyr.dataProvider()
mapCanvas
object:cLat = None cLon = None canvas = iface.mapCanvas()
c = QgsNMEAConnection(None)
firstPt = True
for r in results: l = len(r) if "GGA" in r: c.processGGASentence(r,l) elif "RMC" in r: c.processRMCSentence(r,l) elif "GSV" in r: c.processGSVSentence(r,l) elif "VTG" in r: c.processVTGSentence(r,l) elif "GSA" in r: c.processGSASentence(r,l)
i=c.currentGPSInformation()
if i.latitude and i.longitude: lat = i.latitude lon = i.longitude if lat==cLat and lon==cLon: continue cLat = lat cLon = lon pnt = QgsGeometry.fromPoint(QgsPoint(lon,lat))
if firstPt: firstPt = False f = QgsFeature() f.setGeometry(pnt) vpr.addFeatures([f]) qmr.addMapLayer(vectorLyr) else: print lon, lat vectorLyr.startEditing() vectorLyr.changeGeometry(1,pnt) vectorLyr.commitChanges()
vectorLyr.setCacheImage(None) vectorLyr.updateExtents() vectorLyr.triggerRepaint() time.sleep(1)
A live GPS will move in a linear, incremental path across the map. In this recipe, we used randomly-generated points that leap around the world, but the concept is the same. To connect a live GPS, you will need to use QGIS's GPS information GUI first to establish a connection, or at least get the correct connection information, and then use Python to automate things from there. Once you have the location information, you can easily manipulate the QGIS map using Python.
The NMEA standard is old and widely used, but it is a poorly-designed protocol by modern standards. Nearly every smartphone has a GPS now, but they do not use the NMEA protocol. There are, however, several apps available for nearly every smartphone platform that will output the phone's GPS as NMEA sentences, which can be used by QGIS. Later in this chapter, in the Collecting field data recipe, we'll demonstrate another method for tracking a cell phone, GPS, or even estimated locations for digital devices, which is much simpler and much more modern.