Tracking a GPS

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.

Getting ready

This recipe doesn't require any preparation.

How to do it...

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:

  1. First, we need to import some standard Python libraries using the QGIS Python Console:
    import urllib
    import urllib2
    import time
    
  2. Next, we'll connect to the online NMEA generator, download a batch of sentences, and turn them into a list, as follows:
    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("
    ")
    
  3. Next, we can add our world countries basemap using a geojson service:
    wb = "https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json"
    basemap = QgsVectorLayer(wb, "Countries", "ogr")
    qmr = QgsMapLayerRegistry.instance()
    qmr.addMapLayer(basemap)
    
  4. Now, we can create our GPS point layer and access its data provider:
    vectorLyr = QgsVectorLayer('Point?crs=epsg:4326', 'GPS Point' , "memory")
    vpr = vectorLyr.dataProvider()
    
  5. Then, we need some variables to hold the current coordinates as we loop through the locations, and we'll also access the mapCanvas object:
    cLat = None
    cLon = None
    canvas = iface.mapCanvas()
    
  6. Next, we'll create a GPS connection object for data processing. If we are using a live GPS object, we will use this line to enter the device's information:
    c = QgsNMEAConnection(None)
    
  7. Now, we set up a flag to determine whether we are processing the first point or not:
    firstPt = True
    
  8. We can loop through the NMEA sentences now, but we must check the sentence type to see which type of information we are using. In a live GPS connection, QGIS handles this part automatically and this part of the code will be unnecessary:
    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)
    
  9. Then, we can get the current GPS information:
        i=c.currentGPSInformation()
    
  10. Now, we will check this information to make sure that the GPS location has actually changed since the previous loop before we try to update the map:
      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))
    
  11. Now that we have a new point, we check whether this is the first point and add the whole layer to the map if it is. Otherwise, we edit the layer and add a new feature, as follows:
            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()
    
  12. Finally, we refresh the map and watch the tracking point jump to a new location:
            vectorLyr.setCacheImage(None)
            vectorLyr.updateExtents()
            vectorLyr.triggerRepaint()
            time.sleep(1)
    

How it works...

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.

There's more...

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset