GPS logger running CircuitPython.

I’ve been fascinated by the GPS technology for years. There is something magical about being able to accurately pinpoint one’s position on the globe at any given time. Having that capability currently integrated in our phones is even more remarkable and something that we usually take for granted.

The downside, however, is that accurately tracking our position is very taxing on our phones and severely impacts their battery life. I wanted a small standalone device capable of doing just that. It would allow me to geotag photos taken with a mirrorless camera, keep a log of road trips and export tracks to google maps, among other things. This post goes over the design, assembly and programming of such device.


  • Fully standalone GPS tracker ( not cell phone assisted).
  • Location data is recorded to a micro SD card.
  • Integrated screen showing basic location information.
  • GPS coordinates are recorded only if the position changes by a certain predefined number of degrees. That way, we don’t end up with hundreds of recorded points for the same location if the device doesn’t move for a long period of time.
  • Battery lasts for around 70 hrs. on a single charge. Also, it keeps working while charging.
  • Integrated rechargeable battery (micro USB connector). It can be charged by pretty much any USB port or portable battery pack.
  • GPS module sensitive enough to work indoors most of the time.
  • Bluetooth BLE ready. However, this functionality is not used on this version.


The project’s hardware is a mix of Adafruit components and Particle components. In a nutshell, a Particle Xenon micro-controller board takes readings from the GPS module, shows certain information on the OLED screen (connected through I2C) and writes to a micro SD card through a breakout board connected to the controller via the SPI bus. Here is a detailed list of the components:

GPS Logger

GPS logger components.

3D Printed Case

  • ABS filament (diameter would depend on your particular 3D printer).
  • Acrylic sheet. Make sure it’s 0.083 inch (2.24mm) thick to sit flush on the 3d case per the design below. Cut it to be 69.8 x 86.5 mm (I’d recommend printing the case first and then cut it to size).
  • Flat head screws M2.5x6mm.
  • Dremel 194 high speed cutter. This is the perfect Dremel bit size for drilling the screw holes on the acrylic sheet and for grinding/polishing its corners.


All code is done in CircuitPython, which makes it fairly easy to read and maintain. Be advised that Particle doesn’t officially support CircuitPython running on their boards. However, since they have adopted the Feather format and the hardware of some of their boards is the same or pretty close to certain Adafruit boards, CircuitPython can be installed. The process however; is not straightforward (here is a detailed guide). If you are not feeling adventurous and would like a ready-to-go option, You might be better buying Adafruit’s Xenon equivalent, the nRF52840 Feather board; which is ready to go.

Finally, make sure you have the latest version of CircuitPython 4.x (I’m using their latest beta version) in addition to the latest version of their library bundle. Once the O.S. and libraries are installed, we are ready to work on the main script.

All needed files are in the project repository on GitHub, which includes the CircuitPython files and the STL files for the 3D printed case. The CircuitPython side is comprised of only two files: and font5x8.bin, which are the main script and the OLED screen font respectively.

The main script might look a bit long, but that’s because I have included comments explaining what some of the lines do and added some additional lines that can be uncommented to adapt the script to other boards or modify the current device behavior.

The first part of the script imports the needed libraries and initializes global variables, then the main settings are defined:

# Update interval for OLED and screen messages
# IMPORTANT NOTE: Setting this interval to less than 2 seconds
# causes erratic behavior: GPS doesn't seem to be given enough time
# to update data and only a few rows are written to the SD Card. 
UPDATE_INTERVAL = 5.0 #5.0 works well
# Difference between previous and current GPS readings to record change on file.
GPS_DIFF = 0.000025 #0.00002 & 0.00003 work well

The GPS, OLED screen and SD Card instances are then created and configured. After that, three helper functions are setup for measuring the battery voltage, updating the OLED screen and writing to the Sd card. The script then attempts to mount the SD card, raising an error and showing a message on screen if there is no card inserted in the breakout board. If no errors are raised, it enters the main loop and gets GPS data on each iteration. Then, the script updates data on the oled screen, terminal and - potentially - SD Card if the elapsed time between the last update and the current time is larger than the UPDATE_INTERVAL in seconds. New location data is written to the SD card only if the difference in degrees between the previous and the current GPS readings is larger than the GPS_DIFF .

3D Printed Case

The stl file for the 3D printed case is included in the project repository. I have also included x3g and fpp files for use on the Flashforge Creator Pro printer.

The case can be printed without supports as there are no significant overhanging features. I strongly recommend printing in ABS if the device is planned to be left inside a car. High temperatures don’t go well with PLA.

Project case in Fusion360.

Once the case is printed, cut the acrylic sheet to size and drill holes with the recommended Dremel bit. Use the Dremel tool and bit to grind the sheet’s corners, then screw it into the 3D printed case.

Left: 3D printed case in ABS. Right: Acrylic sheet cut to size.

Assembly and Usage

Putting all pieces together is pretty straight forward, the images on this post may serve as reference. First, solder the toggle switch and SD card breakout to the tripler, then proceed to screw these components into the case, doing the SD breakout first. I wanted for that section to be a tight fit, so be ready to do some massaging to place the breakout board in place. Once the tripler and SD card breakout are screwed in, insert the Xenon, OLED screen and GPS module.

GPS logger waiting to get a fix. The red led blinks constantly while searching for satellites. Once a fix is acquired, it blinks every 15 seconds.

Place the device so that it has a clear view of the sky, flip up the switch and wait until it gets a fix of the satellites available at your current location. I’ve used it for many consecutive days and it has performed quite well.

The resulting CSV files can be directly imported into google maps or can be converted to GPX files to geotag photos taken with a DSLR or a mirrorless camera in a photo managing app like Lightroom. There are several apps and websites capable of converting CSV files, but this one proved to be the easiest and most effective one.

Feel free to either reach out to me or leave a comment below if you have any questions.

Assembled GPS logger in 3D printed case.