Raspberry Pi Zero gpsd logger with status LEDs.
A longer description of the motivation behind this and the specific hardware that I used is available on my blog: DIY Raspberry Pi Zero GPS Track Logger.
Introduction and Goals
This is a trivial (and not really "supported") project of mine to couple a Raspberry Pi Zero with a USB GPS receiver and a battery pack to GPS track my hikes. The hardware decision was mainly based on what I had lying around: a Raspberry Pi Zero, a 10,000mAh external battery pack for my cell phone, and a USB GPS (well, I thought I had one, and got far enough into the project when I decided it was missing for good that I bought another).
The goal is to package all of this together into a "small" (but not necessarily lightweight, based on the components) package that I can put in the outside pocket of my hiking pack, and record an accurate and detailed GPS track of my hikes. It writes the most recent position data from gpsd to disk at a user-defined interval, flushes IO after each write (so that it's safe to just pull the power on the Pi), and uses two LEDs to indicate status while in the field. Data is written in gpsd's native format, but a conversion tool is provided.
This program relies on gpsd to interact with the GPS itself, as it's very mature and stable software, exposes a simple JSON-based socket interface, and also has decent Python bindings. There's no reason for a logger to have to worry about the nuances of GPS communication itself.
- Raspberry Pi (tested with Pi Zero 1.3) and a MicroSD card (I'm using an 8GB SanDisk Ultra Class 10 UHS-1, which has enough space after the OS for 240 days of 5-second-interval data).
- Raspbian Stretch with Python3 (see installation instructions below)
- gpsd compatible GPS (I use a GlobalSat BU-353-S4 USB; the gpsd folks say some pretty awful things about it, but we'll see...)
- Two GPIO-connected LEDs on the RPi, ideally different colors (see below).
- Some sort of power source for the Pi. I use a standard adapter when testing and a 10000mAh USB battery pack in the field (specifically the Anker PowerCore Speed 10000 QA). That battery pack is extreme overkill, and powers the unit continuously for 42 hours, when logging at a 5-second interval.
This assumes you're running on Linux...
- Download the latest Raspbian Stretch Lite image. I'm using the "November 2017" version, released 2017-11-29, kernel 4.9.
- Verify the checksum on the file and then unzip it.
- Put the MicroSD card in your machine and write the image to it. As root,
dd bs=4M if=2017-11-29-raspbian-stretch-lite.img of=/dev/sdX conv=fsync status=progress(where
/dev/sdXis the device that the SD card showed up at).
- Wait for the copy to finish and IO to the device to stop (run
- Optional: If you're going to be using this on a network (i.e. for setup, troubleshooting, development, etc.) then this would be a good time to mount the Raspian partition on your computer and make some changes. See this script from pi2graphite for some tips.
- Copy your authorized_keys file over to
- Touch the file at
/boot/sshon the Pi boot partition to enable SSH access.
- Set a hostname.
- If desired, configure WiFi (as well as downloading the packages for any required drivers onto the OS partition).
- When finished, unmount,
syncand remove the SD card.
- Put the SD card in your Pi and plug it in. If you're going to be connecting directly with a keyboard and monitor, do so. If you configured WiFi (or want to use a USB Ethernet adapter) and have everything setup correctly, it should eventually connect to your network. If you have issues with a USB Ethernet adapter, try letting the Pi boot up (give it 2-3 minutes) and then plug in the adapter.
- Log in. The default user is named "pi" with a default password of "raspberry".
sudo apt-get update && sudo apt-get install haveged git python3-gpiozero python3-setuptools python3-pip gpsd
- Run sudo raspi-config to set things like the locale and timezone. Personally, I usually leave the
piuser password at its default for devices that will never be on an untrusted network.
git clone https://github.com/jantman/pizero-gpslog.git && cd pizero-gpslog && sudo python3 setup.py develop && sudo pizero-gpslog-install. The installer,
pizero-gpslog-install, templates out a systemd unit file, reloads systemd, and enables the unit. Environment variables to set for the service are taken from command line arguments.
- If you're ready,
sudo systemctl start pizero-gpslogto start it. Otherwise, it will start on the next boot.
- Find out the USB vendor and product IDs for your GPS. My BU-353S4 uses a Prolific PL2303 serial chipset (vendor 067b product 2303) which is disabled by default in the Debian gpsd udev rules. Look at
/lib/udev/rules.d/60-gpsd.rules. If your GPS is commented out like mine, uncomment it and save the file.
- Add two LEDs to the Pi Zero. I prefer to solder a female right-angle header to the Pi, then put the LEDs on a male header so they can be removed. gpiozero, the library used for controlling the LEDs, has pinout diagrams and information on the wiring that the API expects. The code this project uses expects the LEDs to be wired active-high (cathode to ground, anode to GPIO pin through a limiting resistor). I made up a small 8x20 header for my LEDs and (very sloppily) potted them in epoxy.
- Test the LEDs.
- Plug your GPS into the USB input on the RPi, via a "usb on the go" (USB OTG) cable. Then plug the Pi into a power source. Everything else should be automatic after the installation described below.
pizero-gpslog's entire configuration is provided via environment variables. There are NO command-line switches.
LOG_LEVEL- Defaults to "WARNING"; other accepted values are "INFO" and "DEBUG". All logging is to STDOUT.
LED_PIN_RED- Integer. Specifies the GPIO pin number used for the primary ("red") LED. Leave unset if running on non-RPi hardware, in which case LED state will be logged to STDOUT. Note the number used here is the Broadcom GPIO pin number, not the physical board pin number.
LED_PIN_GREEN- Integer. Specifies the GPIO pin number used for the secondary ("green") LED. Leave unset if running on non-RPi hardware, in which case LED state will be logged to STDOUT. Note the number used here is the Broadcom GPIO pin number, not the physical board pin number.
GPS_INTERVAL_SEC- Integer. Interval to poll gps at, and write gps position. Defaults to every 5 seconds.
FLUSH_FILE- String. If set to "false", do not explicitly flush output file after every write.
OUT_DIR- Directory to write log files under. If not set, will use current working directory.
Configure as described above, then use the
pizero-gpslog systemd service.
- Green Solid (at start) - connecting to gpsd. Green LED goes out when connected to gpsd and the output file is opened for writing.
- Red Solid - no active GPS (gpsd does not yet have an active gps, or no GPS is connected).
- Red 3 Fast Blinks (0.1 sec) - GPS is connected but does not yet have a fix.
- Red 2 Slow Blinks (0.5 sec) - GPS has a 2D-only fix; position data is being read.
- Red 1 Slow Blink (0.5s) - GPS has a 3D fix; position data is being read.
- Green Blink (0.25s) - Data point written to disk (and flushed, if flush not disabled).
Log files will be written under the directory specified by the
OUT_DIR environment variable, or the current working directory if that environment variable is not set. Log files will be written under that directory, named according to the time and date when the program started (
Each line of the output file is a single raw gpsd response to the
?POLL command. While this program also decodes the responses, it doesn't make sense for us to invent our own data structure for something that already has one. Each line in the output file should be valid JSON matching the gpsd JSON ?POLL response schema, deserialized and reserialized to ensure that it does not contain any linebreaks.
Getting the Data
At the moment, when I'm home from a hike and the Pi is powered down, I just pull the SD card and copy the data to my computer, then delete the data file(s) from the SD card and put it back. It would certainly be easy to automate this with a Pi Zero W or an Ethernet or WiFi connection, but it's not worth it for me for this project. If you're interested, I have some scripts and instructions that might help as part of my pi2graphite project.
Using the Data
The log files output by
pizero-gpslog are in the gpsd JSON ?POLL response format, one response per line (some responses may be empty). In order to make the output useful, this package also includes the
pizero-gpslog-convert command line tool which can convert a specified JSON file to one of a variety of more-useful formats. While gpsbabel is the standard for GPS data format conversion, it doesn't support the gpsd POLL response format. This utility is provided as a means of converting to some common GPS data formats. If you need other formats, please convert to one of these and then to gpsbabel.
pizero-gpslog-convert YYYY-MM-DD_HH:MM:SS.json- convert
YYYY-MM-DD_HH:MM:SS.jsonto GPX and write at
pizero-gpslog-convert --stats YYYY-MM-DD_HH:MM:SS.json- same as above, but also print some stats to STDERR
It's up to you how to use the data, but there are a number of handy online tools that work with GPX files, including:
- gpsvisualizer.com that has multiple output formats including elevation and speed profiles (and other profiles including slope, climb rate, pace, etc.), plotting the track on Google Maps (including with colorization by speed, elevation, slope, climb rate, pace, etc.), converting to Google Earth KML, etc. Plotting can also use sources other than Google Maps, such as OpenStreetMap, ThunderForest, OpenTopoMap, USGS, USFS, etc. (and there's some explanation about how this is done).
- utrack.crempa.net Takes a GPX file and generates a HTML page "report" giving a map overlay (with optional elevation colorization) as well as elevation and speed profiles (against both time and distance), some statistics, a distance vs time profile, and the option to download that report as a PDF.
- sunearthtools.com has a simple tool (admittedly with a poor UI) that plots GPX data on Google maps along with a separate speed and elevation profile (by distance).
- mygpsfiles Is a web-based app with a native-looking tiled UI that can plot tracks on Google Maps (Satellite or Map + Topo) as well as displaying per-point statistics (distance, time, elevation, speed, pace) and a configurable profile of elevation, speed, distance, pace, etc. As far as I can tell, all units are metric.
There currently aren't any code tests. But there are some scripts and tox-based helpers to aid with manual testing.
pizero_gpslog/tests/data/runfake.sh- Runs gpsfake (provided by gpsd) with sample data. Takes optional arguments for
--nofix(data with no GPS fix) or
--stillfix(fix but not moving).
First, many thanks to the developers of gpsd, who have put forth the massive effort to make a script like this relatively trivial.