Reading GPS data with Bash

I am presently working on something that requires geolocation. Not knowing much about GPSes and related topics, I decided to get a USB GPS. This week, let’s have a look at how we can extract information from the USB GPS using Bash.


The first step is to locate your USB GPS as a device. If it’s NMEA compliant, it should mount automagically as a USB serial port. You would think that lsusb -v would show you the device, but it does not always. Sometimes it shows as “Brand X GPS”, sometimes it only shows as a generic device, say “MediaTek Inc.”, or even as a modem. It will typically show up as /dev/ttyUSB0 or /dev/ttyACM0.

Once you’ve ascertained the device name, you must add your user to the dialout group (on Linux, anyway) to access the devices. You do so with

sudo adduser $USER dialout

and by login-out and in again (to make the group addition propagate correctly to your environment).

The next step (now that you know the device name and that you’ve added yourself to group dialup), is to configure the baud-rate and other port parameters. To do that, we’ll use stty

stty \
    -F $gps_device \
    raw \
    38400 \
    cs8 \
    clocal \
    cs8 \
    -parenb \
    crtscts \

This commands sets the device pointed by the variable $gps_device to 38400 bauds, no-handshake and 8n1 data (8 bits, no parity, one stop bit).

We can now open the device as files for reading and writing:

exec 4<$gps_device # gps read-stream
exec 5>$gps_device # gps write-stream

…creating stream #4 for reading and stream #5 for writing. While one may not think of a GPS as a read/write device, it does accept configuration commands such as the frequency at which you desire the updates and what NMEA information you want. The simplest command is probably the update frequency that lets you specify the interval, in ms, at which the GPS spews out its data. It would look very much like:

# configure GPS options
# with the help of :
# 2000 ms = $PMTK220,2000*1C
# 1500 ms = $PMTK220,1500*1A
# 1000 ms = $PMTK220,1000*1F
#  750 ms = $PMTK220,750*2C
#  500 ms = $PMTK220,500*2B
#  250 ms = $PMTK220,250*29
#  200 ms = $PMTK220,200*2C
#  100 ms = $PMTK220,100*2F

echo \$PMTK220,1000\*1F$'\r' >&5

The PMTK commands are reminiscent of the old AT modem commands, but with the addition of a (rather crude) check-sum at the end of each command, separated by *. The GPS will answer with a possibly negative acknowledge message to let you know if the command succeeded. The above would result in something like:


Were 001 is the type of the message, here an acknowledge message, 220 is the type of the message it answers to, and 2 or 3 before the check sum tells whether it failed or succeeded.

Pumping the data out of the GPS is rather straightforward:

while [ 1 ]
    read this_line more stuff...

done <&4

The output should look something like


where the $GPGSV data tells you what satellites you are receiving signals from, and the $GPRMC is the minimal positioning data the GPS is supposed to give you to be NMEA-compliant.

* *

In the next entry, we’ll have a look at how to parse this data with Bash

To be continued…

4 Responses to Reading GPS data with Bash

  1. […] Last time we looked at how to get the data to the GPS and now we will have a look at how to parse the data. Turns out that except for the check-sum, everything is pretty straight forward, even in Bash. […]

  2. […] previous installments, we looked at how to read data from a serial-over-USB GPS, then how to parse the data. […]

  3. […] a few previous entries, we looked at how to capture, parse, and evaluate the precision of a NMEA-capable […]

  4. […] a few other entries, I’ve toyed with GPS, either getting or parsing the data with Bash, assessing or using the GPS data. However, when we use GPS, we […]

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s