Wednesday, September 29, 2010

Gemini Puzzle Caches

I came up with an idea for a pair of identical puzzle caches. At the published coordinates there will be a box with a single button and an LCD display. While the button is pressed the LCD will display the location of the cache. Sound easy? Like that yes, but there is a catch. Both boxes must have their buttons pressed at exacly the same time. Only then will the final location be shown. If only one box is activated then an error message is shown. So to solve these caches different people must go to the given coordinates at the same time and work together.

Castor and Pollux. The names of my two boxes

I was planning on basing the initial design around the arduino and an XBee module. In a cost cutting exercise I decided to start out smaller and use a Transceiver nRF24L01+ Module instead.

So the main components are;
Arduino Main Board
Transceiver nRF24L01+ Module with Chip Antenna
Basic 16x2 Character LCD - Red on Black 3.3V
Trimpot 10K with Knob
Wires + Headers
Custom Perspex box.

Nearly forgot to mention, 2 of everything, 2 boxes for this geocache game.

Wiring of the LCD and the tranceiver was very simple. All ports mappings are specified in the script.

I added a arcade machine momentary push button so that the unit would only be powered when the button was pressed. Mainly to prevent it being accidentally left turned on, but also because I thought the buttons looked great.
And finally I descided to rip the Atmega out of the Arduino and use that directly. Another cost saving, but also allows for a smaller box size and better power usage.

Basic layout
Providing connections for Reset, Tx and Rx allow for connecting the Atmega to its chipless Arduino board. This allows the Atmega to be reprogrammed while its in the final device.

Final box showing greeting message
Error message shown when other box not activated

Both perspex boxes cost 10 euros to have made in a shop downtown Athens. To do this I made a prototype box from card to make sure everything would fit and then took that to the shop and they simply copied it.
Protoype case
The main downside of using the nRF24L01+ is range. At clear line of sight a maximum distance of about 80m was possible. This wasnt that much of a problem in that there are plenty of places I can place the devices on my local mountain. Locations where it may be 80m direct between the two points but to walk it required over 1km to avoid a river/cliff/etc. The main problem is that 80m is half the minimum seperation required for publishing new caches. So doing this as 2 puzzle caches would never get published on geocaching.com. To get arround this I simple rebranded it as a single puzzle cache with multiple stages that had to be solved simultaniously.

Here is the script. This script was uploaded to both devices, with only changing the value of 'deviceNumber' from 1 to 2.

 #include <Spi.h>  
 #include <mirf.h>  
 #include <LiquidCrystal.h>  
 #include <string.h>  
 // Pins  
 #define pinUnused 0  
 // LCD  
 #define pinD4 14 // analog 0  
 #define pinD5 15 // analog 1  
 #define pinD6 16 // analog 2  
 #define pinD7 17 // analog 3  
 #define pinEnable 18 // analog 4  
 #define pinRS 19 // analog 5  
 // nRF24L01+  
 #define pinCSN 9  
 #define pinCE 10  
 #define pinMOSI 11  
 #define pinMISO 12  
 #define pinSCK 13  
 LiquidCrystal lcd( pinRS, pinEnable, pinD4, pinD5, pinD6, pinD7 );  
 #define deviceNumber 1  
 #define device1Name  "geminiOne"  
 #define device1Final  " N 38 xx.xxx' "  
 #define device1Alone  "Awaiting Castor."  
 #define device2Name  "geminiTwo"  
 #define device2Final  " E 23 xx.xxx' "  
 #define device2Alone  "Awaiting Pollux."  
 #define RF_DR_LOW   5  
 #define RF_PWR_LOW  1  
 #define RF_PWR_HIGH  2  
 #define cacheMessage   "Gemini Geocache "  
 #define copyrightMessage "  (C)R10N   "  
 #define successMessage  "Final Position: "  
 void setup( void )  
 {  
  Serial.begin(38400);  
  lcd.begin( 16, 2 );  
  lcd.clear();  
  lcd.noAutoscroll();  
  Mirf.csnPin = pinCSN;  
  Mirf.cePin = pinCE;  
  Mirf.init();  
  Mirf.setRADDR( ( deviceNumber == 1 ) ? (byte*)device1Name : (byte*)device2Name );  
  Mirf.setTADDR( ( deviceNumber == 1 ) ? (byte*)device2Name : (byte*)device1Name );  
  Mirf.payload = sizeof( unsigned long );  
  uint8_t settings = ( 1 << RF_DR_LOW ) | ( 1 << RF_PWR_LOW ) | ( 1 << RF_PWR_HIGH );   
  Mirf.configRegister( RF_SETUP, settings );  
  Mirf.config();   
  randomSeed( analogRead( pinUnused ) );  
  displayMessage( cacheMessage, copyrightMessage );  
  delay( 2000 );  
 }  
 void displayMessage( const char* line1, const char* line2 )  
 {  
  lcd.setCursor( 0, 0 );  
  lcd.print( line1 );  
  lcd.setCursor( 0, 1 );  
  lcd.print( line2 );  
 }  
 void sendData( void )  
 {   
  unsigned long now = millis();  
  Mirf.send( (byte*)&now );  
  while( Mirf.isSending() )  
   delay( random( 10 ) );  
 }  
 bool readData( void )  
 {  
  bool dataFound = false;  
  while( Mirf.dataReady() )  
  {  
   byte data[Mirf.payload];  
   Mirf.getData(data);  
   dataFound = true;  
  }  
  return dataFound;  
 }  
 void loop( void )  
 {  
  sendData();  
  if( readData() == true )  
  {  
   displayMessage( successMessage, ( deviceNumber == 1 ) ? device1Final : device2Final );  
   unsigned long now = millis();  
   while( millis() <= (now + 1000) )  
    sendData();  
  }  
  else  
  {  
   displayMessage( cacheMessage, ( deviceNumber == 1 ) ? device1Alone : device2Alone );  
  }  
 }  

As I mentioned before, XBee was my original thought for this. Depending on the XBee module a range of 1.6km is possible. Much more for the high end versions, but the price is large and a hefty antenna is needed. 1.6km would allow for the initial plan of it being 2 seperate puzzle caches.
For my next project, instead of using XBee, I've decided to take this further and go international. Using the internet as the communication channel. More to come on that later.

No comments:

Post a Comment