Arduino-Based Geocache Finder Toy

For fun I made a dedicated geocache toy from an Arduino, GPS receiver and electronic compass modules and neopixels (RGB LEDs).

The Idea

I had kids in mind – rather than sending them off running around with your bazillion dollar iPhone in their hands, use this gadget instead.

I saw a reverse geocache box on the interweb with Arduino, LCD display, servo motor, GPS, etc. and started to build one in time for some visitors with kids. Of course, I didn’t quite finish it in time so instead they got sent off with a relatively rugged Garmin eTrex with my fingers crossed (not worrying about the children, but my expensive GPS receiver, natch).

About a year later I ordered some neopixels / RGB LEDs to play with and the idea came to me to remix the reverse geocache project into something a bit different. Why not use the neopixels to make a compass display with some status LEDs thrown in for good measure? Then I could throw away the fragile and boring LCD display and, hey, it has blinkenlights so it must be good, right?

I built the gadget in a cigar box since a) I had some around (no, I don’t smoke) and b) it’s a nice steampunk/retro kind of touch although, clearly, sending a very bad message to children about smoking.

In Use

As it stands you need to hard-code the GPS coordinates into the Arduino program for each different geocache and then re-program the Arduino.

Once the gadget is programmed with coordinates, when you fire it up you will see something like this:

The blue LED in the circle pattern is showing information from the compass only since the GPS hasn’t got a position fix yet. The GPS status is indicated by the LED currently illuminated yellow.
When you get a GPS position fix, the compass LED turns green as does the GPS status LED. You also get a ‘distance LED’ (which is a kind-of purple in the photo). When you are far away from the cache, the LED is blue and when you’re closer, the LED goes red. There are a couple of discrete steps in between. I went with just a few discrete steps in the distance LED colour so that it might be more noticeable as you approach the cache.

In short: program your Arduino with your new coordinates, put in some new batteries, switch on the unit, take it outside and wait for a position fix (green blinkenlights) and off you go. As you twist the box it will show you roughly which way to go. The colder-warmer LED will go from blue to red as you get closer to the cache.


For what it’s worth, here’s a Fritzing layout of the system:

The LEDs are wired in a chain. Connect 5V to 5V and gnd to gnd all the way around. Din goes to Dout between each one. I have a 220uF 10V electrolytic across the power supply at the beginning of the chain. The first Din is connected to digital I/O pin 6 of the Arduino via a series 470Ω resistor. The capacitor (which might be better nearer 1000µF) and series resistors are as per Adafruit’s recommendations. Take care that you connect your Arduino to Din! An easy mistake to make, ahem. My chain starts at the South East LED, proceeds clockwise then follows the distance-to-cache and finally the GPS status LED. That’s 10 in total.

The GPS is a fully 5V-compatible module with its own regulator and level matching transistors on-board. I like the u-blox brand modules – they seem fast to start up, accurate enough, etc. I’ve used them in one form or another on various projects. I connected 0V, 5V and the serial data output (the ribbon cable in the photo shows 4 wires but the data wire Arduino -> GPS is not connected. I connected the data output (green in the photo, marked TX on the GPS module) to pin 8 on the Arduino. Unfortunately the SoftSerial library doesn’t allow for unidirectional configuration (i.e. receive-only which is what we want here) so I configured pin 9 as the transmit pin, even though it’s not connected. It would be great to be able to specify -1 as the pin ID for transmit or receive in the constructor of SoftwareSerial so that you could do transmit-only (a typical debug output scenario) or receive-only (like in our case with the GPS).

The I2C-connected electronic compass module (HMC5983) seems to be a strictly-3.3V affair with regard to the signal voltages even though you can definitely supply it with 5V since it has a low-dropout regulator on the module PCB. To be sure I used one of the level-shifter PCBs that seems to do the job quite nicely and also functions as the I2C bus pull-up. As per Arduino Uno convention, the I2C bus is on Analog(ue) pins 4 and 5 (SDA and SCL respectively).

The AA battery pack gives about 4.3V under load which squeaks in as just-about-good-enough. The GPS and compass modules are 3.3V internally with low-dropout regulators on-board. The Arduino seems fine at 4.3V although should, perhaps be at a lower clock speed at this voltage – but then you run into all sorts of problems with the SoftwareSerial, etc. libraries. If you wanted, you could always use a 4-AA pack which would work for sure – you’d need top feed the Vin rather than 5V pin on the Arduino and, frankly, most of the energy from that extra AA would go into warming up regulators.


Build Notes

I used an Arduino Uno variant with a CH340 chip (no nasty FTDI). These are super-cheap from China via eBay at around $4 or less. Delivered. I used a prototype shield as a quick way of connecting / disconnecting the wires to the Arduino. These are cheap-ish although you could also just use the sockets on the Arduino or solder straight to the Arduino

You could equally use an Arduino Pro Mini (although a pain to re-program frequently since you’d need to permanently or temporarily attach the USB adaptor) or a Nano. A Nano seems like a Good Idea.

You need to play with the orientation (including which-side-up) of the e-compass. So wire a long-ish wire to allow you to play with that. I used masking tape to play with that until I was confident I knew which way to fix it in the box so that the North LED was lit when facing North (without GPS).

I used hot-melt glue to tack everything in place. When I say ‘tack’ what I really mean is ‘stuck for eternity’. So you want to be quite sure everything’s working before committing. Case in point: I casually glued the GPS module + antenna in place on the lid before trying to close the box. When I did try to close the lid I realised that I’d put the GPS just a bit to close to the hinge. Fortunately the glue was still slightly fluid so I could nudge the bits away from the hinge.

The cigar box is OK, but these days they come with huge health warning stickers. I found a hot air gun warmed up the glue for easy removal although I still haven’t got rid of all the sticky residue. A hair dryer might also work in a pinch. Use a new / sharp drill for the holes in the cigar box. If anybody has any tips for getting rid of the remaining sticky ick from the wood, please let me know – I’ve tried heat+scraping and pure alcohol+wiping without success. That glue attracts cat hair like some kind of death star tractor beam.

Placement of parts: The GPS antenna needs to be facing upwards and not be covered by any other metal bits. The electronic compass should be placed away from other parts of the circuit, hinges, etc. I printed out a drill pattern that I made with Inkscape to drill the holes for the LEDs.

For debugging I have to say that my Rigol DS1054Z scope with full hack upgrades was awesome. What’s the baud rate of the GPS output? Decode with the serial option and flick though the baud rates until you see the NMEA string decoded to give you a warm feeling you have the baud rate right. What’s happening on the I2C bus? Just hook up 2 probes and trigger on the falling edge to see the I2C data decoded – ace.

I sourced just about all the parts for this build from eBay. Search for “5V GPS module”, “I2C level shifter”, “CH340 Arduino Uno”, “WS2128B LED”, “arduino prototype shield” and “HMC5983 module”.

Arduino Software

I posted the source on GitHub under Apache 2.0 licence.

The code is straightforward, using SoftwareSerial (standard Arduino library), TinyGPS++, Adafruit Neopixel and HMC5983 libraries.

You need to set your longitude and latitude of the geocache in the #defines at the top of the source file.

The setup function initialises everything (including calling the begin() method on the compass object, which I forgot and had me scratching my head for a bit).

The main loop waits for a complete packet from the GPS receiver and then goes off to set LEDs according to GPS status, compass data, heading to geocache and distance remaining to the geocache (the latter assuming that we have a position fix).

Distance is calculated using the Haversine formula, in case you were interested.

Enhancement Ideas

Programming the destination by reprogramming the Arduino might be a bit of a pain for some and definitely not convenient if you’re out on a trip doing several caches in the same trip. So you might want to attach a Bluetooth module to send new coordinates from your smartphone (yes, I see the irony). I could imagine an app with a map that could send the coordinates to the toy on a map click. You’d want to use the Arduino’s EEPROM to store the coordinates and probably accept conversation with the smartphone on startup since you run into problems with getting too busy at runtime with too many serial I/O channels for the poor little microcontroller to handle.

Slightly less convenient but easier to implement would be an SD Card module that you could pre-program a bunch of SD cards (taking care to label them!) with coordinates in a simple text file and swap them out for each destination.

My build sucks about 90mA. You could save a bit of power by desoldering / track cutting to disable some superfluous LEDs on the Arduino board, etc.

The electronic compass doesn’t work very well inside a car, so dynamically switching to using the GPS course over ground heading output when moving above speed x (where x is about 10km/h) might be an idea. But you’d need to hold the box in a known orientation when in the card for that to make sense.

A more-rugged enclosure would be good. Whilst metal would be very rugged and has the possibility to look uber-cool, there is the issue of getting the GPS antenna its sky-view. Perhaps one of the plastic electrical junction boxes would fit the bill – about the right size, cheap, rugged, weatherproof. Or, dare I say it, you might be able to 3D print an enclosure (enclosures being just about the only thing that I consistently come up with as a genuine use for a home 3D printer as they stand today).

A little piezo buzzer might be cool to make some clicks and chirps or even a vibration motor to give haptic feedback as you get closer to the cache.

Some pretty effects on the LEDs might be nice, but take care that the batteries might take a nosedive and when /if the Arduino is powered through its regulator you could hit the current limit.

Some artwork on the box would be nice!

The RGB LED’s would work better with a diffuser of some sort since the eye doesn’t mix the RGB colours very well when you’re up close. Perhaps discs of white plastic punched from a PE bottle would do the trick.


The cat was most helpful during the coding process.