Reverse Geocache Puzzle Project

A long time ago (about two years ago), I read a post about the very first Reverse Geocache Puzzle™ project by Mikal Hart. The idea about it was stuck in my mind for a while; I really wanted to build one. Some time later, a very good friend of mine was getting married and I took that opportunity to build one myself.

What is a Reverse Geocache Puzzle™?
The idea behind this puzzle is that it’s simply a box that only opens when you take it to a specific location (determined by GPS), chosen by the gift giver. As Mikal Hart describes in his pages, this is a very personal gift and experience, and I agree.

Project Description
For this project, I used Mikal Hart’s own design as a starting point. I’m familiar with the Arduino microcontroller and environment, so I was also able to use some of his awesome libraries. I liked some of the features he had in his own design, but I made a few changes.

The couple I wanted to give this box to got married outside the USA but they reside in New Orleans, LA; I sent them my box after their wedding. What was the gift, you may ask? Well inside the box was a gift certificate to a very fancy restaurant; the programmed location the box to solve the puzzle was at this location, more on the outcome later…

Hardware
Luckily I was able to get all the electronic components from sparkfun.com. Since this project is Arduino based, like Mikal’s, I was able to get everything I really needed from them. Power is provided by 4 AA batteries; although there would probably be no need to replace batteries, I included a panel at the bottom of the box where you had access to the battery pack alone.

Major components
Arduino Duemilanove
EM-408 SiRF III Receiver with Antenna
16×2 White on Black, backlight HD44780 LCD
Small Servo
Red pushbutton
Low voltage Pololu power switch
GPS Shield
1 Battery Holder – 4xAA Square
1 ornamental box purchased at Home Goods.

minor components

3 #14 eyelet screws
4 1500 mAh Alkaline Battery – AA
Various mounting screws and nuts.
Wire, headers, solder, and other circuit connecting items

Software

The box is running the Arduino version 0018 framework. The sketch I wrote uses native libraries SerialServo*, and LiquidCrystal, as well as some of Mikal Hart’s library’s: TinyGPS, and NewSoftSerial. His libraries are freely available for download at Arduiniana.org.

*Note: A different version of the servo library was used (from 0016) because the latest revision is not compatible with the current version of Mikal Hart’s NewSoftSerial (10c at the time of this writing).

The software is pretty simple to follow. When a user presses the button, the pololu switch turns on power to the whole system. It reads a few flags from EEPROM and then goes on to obtain a GPS signal fix. The distance threshold I set the box to be within the programmed destination was 10 meters. Given that the GPS has about this accuracy anyways, this was probably a bad idea, more on this later. After a fix has been acquired, it displays  the distance in meters to the destination. Another feature I added, after 20 attempts, it also displays the bearing i.e. N, NE, E, SE, S, etc.

I wanted the couple to be right on top of the destination in order to solve the puzzle, during my testing, I had proven the box worked correctly. I should have increased the threshold a little higher though.

Conclusion
This was a really good project and learning experience. After I sent the box to my friend in New Orleans, LA he went out to solve it. He was able to correctly get to the destination, however the 10 meter threshold was wayyy to tight, and the box wouldn’t open! There were errors in the measurement’s and the box simply teetered around 15 meters and my friend had to use a back door in made into the box to open it. In the end, this is something I would definitely change. The destination I chose was nice restaurant for which there was a gift certificate inside the box. I really enjoyed building this box and I would do it again for sure.

 

2 Responses to Reverse Geocache Puzzle Project

  1. David Groebl says:

    Can you please share your Reverse GeoCache sketch? I’ve built my own box and I’m really struggling to program it. I’m planning to use it to propose to my girlfriend with and I’m really worried that the puzzle will be confounding and not the fun adventure I’d like it to be. I think your idea of adding the direction bearing will really help to make it much more of a enjoyable process for her.

    Thanks,
    David

    • Jose Brache says:

      I would be happy to give you some more insight but I want to warn you that the code is definitely rather long and probably has some features you don’t need.

      I forget where I got the function to get bearing, but here it is below:

      // get compass bearing
      float getCompassBearing(float lat1,float lon1,float lat2,float lon2)
      {
      /*
      In general, your current bearing will vary as you follow a great circle path (orthodrome);
      the final bearing will differ from the initial bearing by varying degrees according to
      distance and latitude (if you were to go from say 35°N,45°E (Baghdad) to 35°N,135°E (Osaka),
      you would start on a bearing of 60° and end up on a bearing of 120°!).

      This is the initial bearing (sometimes referred to as forward azimuth) which if followed in
      a straight line along a great-circle arc will take you from the start point to the end point:

      =ATAN2(COS(lat1)*SIN(lat2)-SIN(lat1)*COS(lat2)*COS(lon2-lon1),SIN(lon2-lon1)*COS(lat2))
      * Note that Excel reverses the arguments to ATAN2 – see notes below

      Since atan2 returns values in the range -π ... +π (that is, -180° ... +180°), to normalise
      the result to a compass bearing (in the range 0° ... 360°, with -ve values transformed into
      the range 180° ... 360°), convert to degrees and then use (θ+360) % 360, where % is modulo.

      For final bearing, simply take the initial bearing from the end point to the start point
      and reverse it (using θ = (θ+180) % 360).
      */
      return atan2(sin(lon2-lon1)*cos(lat2), cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1));
      }

      Then I recall I used a switch statement to get the general direction.

      const float pi = 3.1415926535897932384626433;
      const float bearingThresh = 22.5;

      bearing = getCompassBearing(flat * pi/180, flon * pi/180, fLatDest * pi/180, fLonDest * pi/180);
      bearing *= 180/pi;
      if ( bearing < 0 ) bearing += 360; Serial.println(bearing, 0); if( attempts >= 20 )
      {
      if( ( bearing > ( 360 - bearingThresh ) ) && ( bearing < bearingThresh ) ) lcd.print("N"); else if( ( bearing > ( 45 - bearingThresh ) ) && ( bearing < ( 45 + bearingThresh ) ) ) lcd.print("NE"); else if( ( bearing > ( 90 - bearingThresh ) ) && ( bearing < ( 90 + bearingThresh ) ) ) lcd.print("E"); else if( ( bearing > ( 135 - bearingThresh ) ) && ( bearing < ( 135 + bearingThresh ) ) ) lcd.print("SE"); else if( ( bearing > ( 180 - bearingThresh ) ) && ( bearing < ( 180 + bearingThresh ) ) ) lcd.print("S"); else if( ( bearing > ( 225 - bearingThresh ) ) && ( bearing < ( 225 + bearingThresh ) ) ) lcd.print("SW"); else if( ( bearing > ( 270 - bearingThresh ) ) && ( bearing < ( 270 + bearingThresh ) ) ) lcd.print("W"); else if( ( bearing > ( 315 - bearingThresh ) ) && ( bearing < ( 315 + bearingThresh ) ) ) lcd.print("NW"); else lcd.print("err"); }

Leave a Reply

Your email address will not be published. Required fields are marked *