Group Abstract Group Abstract

Message Boards Message Boards

Building a GPS tracker with the Raspberry Pi

GROUPS:
This post shows how to build a simple GPS tracker with the Wolfram Language on a Raspberry Pi.

To recreate this experiment you will need the following hardware (in addition to the Raspberry Pi itself):
Plug the GPS module into the breadboard as shown and connect red to VIN, black to GND, green to RX and white to TX, using the jumper wires and the USB to TTL serial cable. Plug the USB end of the cable into the Raspberry Pi (powered down). Power up your Raspberry Pi.



The GPS module starts to transmit data shortly after power up and will continue to do so until it is unplugged from a power source.

In a terminal start the Wolfram Language using the following command:
> wolfram

Wolfram Language (Raspberry Pi Pilot Release)
Copyright 1988-2013 Wolfram Research
Information & help: wolfram.com/raspi

In[1]:=


You can now open the serial port using the DeviceOpen by entering:
serial = DeviceOpen["Serial",{"/dev/ttyUSB0","BaudRate"->9600}]


This returns a DeviceObject which can be used to read GPS data from. In this case we use DeviceReadBuffer to read all available GPS data that has been generated up to this point:
data = DeviceReadBuffer[serial,"String"]

The data returned is in a comma separated format, called GPS NMEA sentences.
     $GPRMC,154541.000,A,4005.8369,N,08814.7322,W,0.04,253.32,201113,,,A*79
     $GPVTG,253.32,T,,M,0.04,N,0.07,K,A*3B
     $GPGGA,154542.000,4005.8369,N,08814.7322,W,1,8,1.07,228.0,M,-33.9,M,,*6B
     $GPGSA,A,3,04,12,10,17,23,24,25,02,,,,,1.31,1.07,0.76*04
     $GPGSV,3,1,12,04,65,040,24,02,63,265,16,10,55,135,39,12,48,302,21*7D
     $GPGSV,3,2,12,17,35,096,33,05,19,190,17,25,13,321,33,24,12,247,16*71
     $GPGSV,3,3,12,23,05,061,31,13,02,090,27,20,02,036,35,45,,,*45
     $GPRMC,154542.000,A,4005.8369,N,08814.7322,W,0.06,253.32,201113,,,A*78

We can import the data with the Wolfram Language using ImportString:
csv = ImportString[ data, "CSV" ]

The NMEA sentences which contain GPS coordinates start with $GPRMC so we filter for those using Cases and pattern matching:
gps = Cases[ csv, {"$GPRMC", ___} ]

The coordinates (latitude and longitude) are in the 4th and 6th position of each list, for example this is the GPS coordinate for the first data point:
Part[ gps, 1, {4,6} ] / 100

which returns the GPS location for Champaign, Illinois, where Wolfram Research is located 40' North, 88' West):
{40.0583, 88.1474}
POSTED BY: Arnoud Buzing
Answer
1 year ago
Arnoud, great article and a fab opportunity for getting involved in Mathematica.  Minor editorial correction, your co-ordinates of Champaign have the West and North transposed.
POSTED BY: Alan Woodward
Answer
10 months ago
Alan, thanks for noticing (fixed).
POSTED BY: Arnoud Buzing
Answer
10 months ago
Part[ gps, 1, {4,6} ] / 100 will not yield the correct long/lat.  

The RMC string format for longitude is: dddmm.mmmm

and for latitude: ddmm.mmmm

When dd / ddd are degrees, mm.mmmm is decimal minutes of a degree (1 minute = 1/60th of a degree).

Moreover western hemisphere longitudes are negative (as are southern latitudes).

So the correct lon/lat in decimal degrees are:

lat: 40 + 5.8369/60 = 40.0973
lon: -(88 + 14.7322/60) = -88.2455

You can verify these coordinates by entering 40.0973,-88.2455 directly into Google Maps' search box:  https://maps.google.com/maps?q=40.0973,-88.2455&hl=en&ll=40.104862,-88.246994&spn=0.168849,0.338173&sll=51.429637,-2.206103&sspn=0.017205,0.042272&t=m&z=12

Or l reckon you were closer at McDonalds on South Neil Street than the middle of a field between East Curtis and County Road?

Your coordinates are in fact in China due to the +88 degrees, but if you correct for that, you are still adrift by 9406 metres (calculated using http://www.movable-type.co.uk/scripts/latlong.html)

I do not know Mathmatica syntax, (I found my way here because your post was mentioned on the RaspberryPi.org site, and I was interested because I work as a software developer in the marine electronics industry), but if you interpret the string as a real number as you have, you can handle it arithmetically as follows (pseudocode):

Where x is dddmm.mmmm or ddmm.mmmm interpreted as a real number:

degrees = floor( x / 100 )
minutes = x - degrees
degrees = degrees + minutes / 60
 if( hemisphere == 'S' or hemisphere == 'W' ) degrees = -degrees

This approach is probably simpler and more efficient than extracting the dd / ddd and mm.mmmm fields as strings, and has the advantage that the algorithm is identical for both lon and lat without having to worry about the different width of the dd and ddd fields.
POSTED BY: Clifford Slocombe
Answer
10 months ago
 Arnoud Buzing, I have a problem with DeviceReadBuffer[], I read data GPS and then write this data to a text file. In the beginning it works, but an error occurs "malloc:memory corruption". Do you know the solution for this error.
POSTED BY: Artem K
Answer
9 months ago
Artem, there will be an updated Mathematica for Raspberry Pi release soon, which addresses some instabilities in the serial device driver.
POSTED BY: Arnoud Buzing
Answer
9 months ago
Arnoud, thanks you for the answer. Can you help me. How can i read data from UART,else the DeviceReadBuffer[].
POSTED BY: Artem K
Answer
9 months ago
If you read data from the GPS using DeviceReadBuffer, the last or first NMEA sentence is not read completely: sometimes the first parts are not read and sometimes the last parts are not read. Of course a filter removes all these broken sentences. But i am interested in getting all complete NMEA sentences from the GPS device. Is there a way using DeviceReadBuffer?
POSTED BY: Ulf Schmidt
Answer
7 months ago