# Building a GPS tracker with the Raspberry Pi

GROUPS:
 Arnoud Buzing 17 Votes 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:> wolframWolfram Language (Raspberry Pi Pilot Release)Copyright 1988-2013 Wolfram ResearchInformation & help: wolfram.com/raspiIn[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*78We 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} ] / 100which returns the GPS location for Champaign, Illinois, where Wolfram Research is located 40' North, 88' West):{40.0583, 88.1474}
4 years ago
9 Replies
 Alan Woodward 1 Vote 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.
4 years ago
 Alan, thanks for noticing (fixed).
4 years ago
 Clifford Slocombe 1 Vote Part[ gps, 1, {4,6} ] / 100 will not yield the correct long/lat.  The RMC string format for longitude is: dddmm.mmmmand for latitude: ddmm.mmmmWhen 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.0973lon: -(88 + 14.7322/60) = -88.2455You 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=12Or 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 - degreesdegrees = degrees + minutes / 60 if( hemisphere == 'S' or hemisphere == 'W' ) degrees = -degreesThis 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.
4 years ago
 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"}] gives: {40.0972, -88.2456} which seems to be correct: GeoGraphics[GeoMarker[{40.0972, -88.24560833333335}], GeoRange -> Quantity[1, "km"]] 
3 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.
4 years ago
 Artem, there will be an updated Mathematica for Raspberry Pi release soon, which addresses some instabilities in the serial device driver.