One of the main contributing factors to GPS position accuracy is the geometric configuration (the position in the sky) of the satellites used to obtain a position.
The best position fix is given when a satellite is directly overhead and another three are equally spaced around the horizon.
This aspect is called the 'geometry' of the system and is measured as DOP (Dilution of Precision).
The influence of satellite geometry on imprecision is demonstrated in the image below. When both satellites are widely separated (figure left) the position error (area in red) is smaller. If the satellites are close to one another (right figure), then the area of error is more spread out. This is valid when the uncertainty for determining the position,
known as the Range Error (R-E: yellow and blue areas), is the same for both satellites. R (R1 and R2) refers to the
measured distance of the satellites to the user (pseudorange).
Satellite precision error
There are a number of different DOP elements which can be used, we will focus on HDOP (Horizontal-DOP).
The HDOP can be seen when using gpsmon. The image below has HDOP highlighted;
The HDOP can also be found in the GSA sentence. Below it is shown as 1.3;
$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39
A HDOP value of 1 or below would give you an accuracy of about 2.5M.
When in mountainous areas, forests and urban canyons, you can experience high HDOP values as some of the available satellites will be obstructed. The satellites used will be closer together creating a large area of error as the signal from each satellite have a larger intersect.
Low accuracy in a city
Out on the open see, you should be able to see a low HDOP value as the satellites used would be spread out and has less area of a intersect.
u-Center from u-Blox is a graphical interface which can be used to monitor and configure all aspects of the GPS module on a BerryGPS-IMU or BerryGPS-GSM.
U-Center
u-Center only runs on Windows. It can connect over the network to a Raspberry Pi. This will require us to redirect the serial interface on the Raspberry Pi to a network port using ser2net.
Once installed, open u-Center. You will get the default view as shown below. No data will be shown as we are not connected to a GPS.
The next step, is to create a new network connection and connect to the GPS which is connected to our Raspberry Pi. You can create a new connection under the Receiver and thenNetwork connection menus.
In the new window, enter the IP address of the Raspberry Pi and specify port 6000. This is the port we configured in ser2net on the Raspberry Pi.
This is what the default view looks like when connected and the GPS has a fix.
u-Center
Below I will list of the more useful windows/tools within u-Center.
You can also click on the images below for a larger version.
Data View This window will show you the longitude, latitude, altitude and fix mode. It will also show the HDOP, which is the Horizontal Dilution of Precision. Lower is better, anything below 1.0 means you have a good signal.
u-Center Data View
Ground Track This window will show you where the satellites are as well as what time.
u-Center Ground Track
Skye View Sky view is an excellent tool for analyzing the performance of antennas as well as the conditions of the satellite observation environment.
u-Center Sky View
Deviation Map This map shows the average of all previously measured positions.
In this guide we will show you how to control the GPIO pins of a Raspberry pi by send a SMS to the Raspberry Pi from a mobile phone.
For this guide, the GSM modem we are using to receive the SMS is the BerryGPS-GSM.
On the software side, we will be using Gammu, which is specifically designed to control phones and GSM modules. It also has a daemon which will monitor the GSM modem for incoming SMSs.
We will configure Gammu to trigger a python script when a new SMS is received. We will use the contents of the SMS to control what happens in Python
LEDs are used here as an example, but you can do anything you like Eg. Open a garage door, turn on some lights, etc..
Wiring
We will be using the three bottom right GPIO pins on the Raspberry Pi header. These are GPIO 16, 20 and 21.
Each is connected to a different color LED as shown above. The
The resistors used are 330 Ohm and the GND pin (shorter pin) of the LEDs is connected to the GND power rail.
Send a test SMS to a mobile number. The mobile number below is an example, you will need to update this;
pi@raspberrypi ~ $ echo "This is a test from a Raspberry Pi" | /usr/bin/gammu --sendsms TEXT +614123456789
Python Script
This python script will run every time a new SMS is received.
pi@raspberrypi ~ $ nano ~/smsReceived.py
Copy in the below code
import RPi.GPIO as GPIO
import time
import sys
import re
RED_LED = 21
GREEN_LED = 20
BLUE_LED = 16
GPIO.setmode(GPIO.BCM)
filename=str(sys.argv[1]) #Gammu will pass the filename of the new SMS as an argument
complete_filename="/var/spool/gammu/inbox/"+filename #we create the full path to the file here
GPIO.setup(RED_LED , GPIO.OUT)
GPIO.setup(GREEN_LED , GPIO.OUT)
GPIO.setup(BLUE_LED , GPIO.OUT)
sms_file=open(complete_filename,"r")
#read the contents of the SMS file
message=sms_file.read(160) #note that a not-parted SMS can be maximum 160 characters
#search the contents and perform an action. Rather than use 'find',
# we will use regular expression (re) so we can ignore case.
#Most smartphones will have the first letter capitalised
if re.search('red', message, re.IGNORECASE):
GPIO.output(RED_LED , GPIO.HIGH)
time.sleep(2)
GPIO.output(RED_LED , GPIO.LOW)
elif re.search('green', message, re.IGNORECASE):
GPIO.output(GREEN_LED , GPIO.HIGH)
time.sleep(2)
GPIO.output(GREEN_LED , GPIO.LOW)
elif re.search('blue', message, re.IGNORECASE):
GPIO.output(BLUE_LED , GPIO.HIGH)
time.sleep(2)
GPIO.output(BLUE_LED , GPIO.LOW)
GPIO.cleanup()
In this guide we will show you how to send a SMS using a button connected to the GPIO pins of a Rasberry Pi Zero.
For this guide, the GSM modem we are using to send the SMS is the BerryGPS-GSM.
On the software side, we will be using Gammu, which is specifically designed to control phones and GSM modules.
Python will be used to monitor some buttons connected to GPIO pins and Gammu python bindings will be used to send a SMS.
Buttons are used here as an example, but you can use anything to trigger the SMS, E.g. Temperature sensor, water level sensor, light sensor, etc..
We have includes some LEDs so we can see when the buttons are pressed.
Wiring
We will be using the three bottom right GPIO pins on the Raspberry Pi header. These are GPIO 16, 20 and 21.
Each is connected to a button and different color LED as shown above. The internal pull-down resisters will be used on these GPIO.
3.3v and GND are connect to the power rails on the breadboard.
The resistors used are 330 Ohm and the GND pin (shorter pin) of the LEDs is connected to the GND power rail.
Initialstate has some great tools to easily stream data from a Raspberry Pi to Initialstate.com and show this data within a dashboard using tiles. We will send longitude, latitude and speed. And use a BerryGPS-GSM to get these values and upload them via 3G.
You will need to create an account on Initialstate.com and then grab your access key which can be found under "My Settings"
BerryGPS-GSM setup
If you are using a BerryGPS-GSM, you can follow this guide to get the GPS working and get your Pi to connect to via 3G using PPP.
The above guide also shows how to make your Pi connect to the carrier network automatically when booted. You will need this if you plan to perform remote tracking(E.g. Asset tracking).
Here we will create the main script which will stream the GPS data to Initialstate.com.
The code below creates a separate thread which is used to monitor the serial port. This is needed because we have a pause in the main loop. The pause is there to limit how much data we upload over 3G.
If we did everything in the same thread during the pause, the serial buffer would fill up (it is FIFO) and when we get the next value from the buffer, it will be old by a few seconds. This happens every loop and eventually the data will be minutes or hours behind.
The access key below is not a valid key, it is just an example. You will need to replace it with your own key.
pi@raspberrypi ~ $ nano ~/GPStracker.py
#! /usr/bin/python
from gps import *
from time import *
import threading
import datetime
from ISStreamer.Streamer import Streamer
gpsd = None #Setup global variable
#Setup the Initialstate stream, give it a bucket name and the access key
streamer = Streamer(bucket_name="GPS_Tracker20190713", bucket_key="GPS_Tracker20190713", access_key="ist_W4aHj0eCkMjCD8JVpp3AMsKomys8NaD")
class GPSDcollector(threading.Thread):
def __init__(self, threadID):
threading.Thread.__init__(self)
self.threadID = threadID
global gpsd #bring it in scope
gpsd = gps(mode=WATCH_ENABLE) #Start GPSD
self.running = True #Start running this thread
def run(self):
global gpsd
while gpsdThread.running:
gpsd.next()
if __name__ == '__main__':
gpsdThread = GPSDcollector(1) # create a thread to collect data
try:
gpsdThread.start() # start it up
while True:
print 'GPS ' , gpsd.utc,'--> CPU time->',datetime.datetime.now().time() ,
if (gpsd.fix.longitude<>0) and (gpsd.fix.longitude<>'nan'): #Only upload data if it is valid
streamer.log("Location", "{lat},{lon}".format(lat=gpsd.fix.latitude,lon=gpsd.fix.longitude))
streamer.log("speed",gpsd.fix.speed)
print ' lat ' , gpsd.fix.latitude,
print ' lon ' , gpsd.fix.longitude,
print ' speed ', gpsd.fix.speed
sleep(5)
except (KeyboardInterrupt, SystemExit): #when you press ctrl+c
print "\nKilling Thread..."
gpsdThread.running = False
gpsdThread.join() # wait for the thread to finish what it's doing
print "Done.\nExiting."
Start the script automatically on boot
If you are doing remote monitoring, you would want the script to run on boot. To do this, we will create a small script which will start the main python program.
This is an all in one module which can provide location tracking and GSM services such as data, text and SMS to your project. It comes in the same form factor as a Raspberry Pi Zero, which makes it nice and compact when used with a Raspberry Pi Zero.
The two main components that make this board great are;
uBlox CAM-M8 GPS module (Same GPS found on BerryGPS-IMU)
uBlox SARA-U201 GSM for GSM connectivity, which has global coverage.
Both of these modules working together results in obtaining a GPS fix in secs, using Assisted GPS.
Along with other sponsors, we are happy to congratulate Plastic Monkeys team for placing 3rd (out of over 70 teams taking part) in the CanSats in Europe Polish Competition.
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.
Have you ever wondered why it sometimes takes your GPS module 10-20 minutes to get a GPS fix? This post will explain why.
Each satellite sends a message every 30 seconds. This message consists of two main components;
Ephemeris data, used to calculate the position of each satellite in orbit
Almanac , which is information about the time and status of the entire satellite constellation.
Only a small portion of the Almanac is included in a GPS message. It takes 25 messages (12.5 minutes) to get the full Almanac. The full Almanac is needed before a GPS fix can be obtained. This is Time To First Fix (TTFF).
TTFF is a measure of the time required for a GPS receiver to acquire satellite signals and navigation data, and calculate a position solution (called a fix).
The above happens during a cold start, this is when the GPS module has been off for some time and has no data in its memory. A full Almanac download is required to get TTFF. If the GPS module has clear line of sight to all satellites, the shortest time for TTFF is 12.5 minutes.
In a warmstart scenario, the GPS module has valid Almanac data, is close to its last position (100km or so) and knows the time within about 20 seconds. This approximate information helps the receiver estimate the range to satellites. The TTFF for a warm start can be as short as 30 seconds, but is usually just a couple of minutes.
A receiver that has a current almanac, ephemeris data, time and position can have a hot start. A hot start can take from 0.5 to 20 seconds for TTFF.
Smarts phones use Assisted GPS (aGPS), this allows them to download the Ephemeris data and Almanac over the cell network which greatly reduces the TTFF.