Message Boards Message Boards

11 Replies
21 Total Likes
View groups...
Share this post:

Building a GPS tracker with the Raspberry Pi

Posted 11 years ago
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:


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.

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
11 Replies
Posted 9 years ago

Good Afternoon,

I have been working on this GPS tracker and I love the information. I did find that data = DeviceReadBuffer[serial,"String"] did not work. I had to use data = FromCharacterCode[DeviceReadBuffer[serial]]

If I wanted to replay the GPS data as if it were coming off of the Satellite, would I replay this data verbatim? I am indoors, so I am not getting a lock and so I am getting void status on the $GPRMC but when I get a lock and the status becomes Active and the sentence changes the data. Would this void vs. active status change the transmission broadcast?


POSTED BY: Stephen G

What do you mean by "transmission broadcast"? The GNSS receiver cannot transmit anything.

Neither is the NMEA0183 data output by the GNSS receiver, representative of the data or signal received from the constellation. The data output is the locally calculated solution derived from the signal timing differences between three or more satellites of known location.

You can get GNSS recorders that record the raw signal and timing, and you can get GNSS simulators that can generate arbitrary signals to simulate any position and time. They are used for testing and development purposes for navigation electronics and are expensive. , Rebroadcasting that signal would be disruptive to nearby GNSS receivers. Such "spoofing" of GNSS can get you into trouble (with law enforcement kind of trouble), and could be a safety issue in some cases. Don't do that.

LabSat and Spectracom on are two manufacturers so such test equipment.

If on the other hand you simply want to feed the NMEA data directly to your application bypassing the GNSS for test purposes, then you only need to generate valid sentences. That is easy to do, but software such as NemaStudio will do that for you.

Posted 11 years 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
Posted 11 years ago
Arnoud, thanks you for the answer. Can you help me. How can i read data from UART,else the DeviceReadBuffer[].
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
Posted 11 years 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.
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:,-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

I do not know Mathmatica syntax, (I found my way here because your post was mentioned on the 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.

Thanks (and apologies for the late reply).

I believe this is the corresponding Wolfram Language function to implement your algorithm:

convert[{lat_, ns_, long_, we_}] := Module[{},
   If[ns === "N", 1, -1] (IntegerPart[lat/100] + (5/3) FractionalPart[lat/100]),
   If[we === "W", -1, 1] (IntegerPart[long/100] + (5/3) FractionalPart[long/100])

For example:

convert[{4005.832`, "N", 8814.7365`, "W"}]


{40.0972, -88.2456}

which seems to be correct:

GeoGraphics[GeoMarker[{40.0972`, -88.24560833333335`}], GeoRange -> Quantity[1, "km"]]

enter image description here

POSTED BY: Arnoud Buzing

That works, but the article still contains the error. You are trusting that people read the comments.

Alan, thanks for noticing (fixed).
POSTED BY: Arnoud Buzing
Posted 11 years 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
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
or Discard

Group Abstract Group Abstract