I've just published my
Pendeli Woodpecker puzzle cache on geocaching.com. The main idea of this cache is that you go to a specific location and at a predesignated time a device makes the sound of a woodpecker drumming on a log. The cache is located at the source of the drumming. Far enough away from the initial coordinates that simply going to the puzzle coordinates and having a manual hunt is unlikely to find the cache.
The idea for this puzzle came from the fantastic
wind-up birds project by HC Gilje.
The basic components required for this project are;
- Atmega 328
- 100N capacitor
- 16MHz crystal
- Solenoid
- 1K resistor * 2
- TIP120 transistor * 2
- 1N4004 diode
- 5V Voltage Regulator (LM78S05)
- Real Time Clock Module
- Water Proof Box
 |
| The Woodpecker |
The general principle is that the Atmega polls the real time clock until 10am either Saturday or Sunday. Once reached, for a 2 minute period the solenoid is powered to drum against a piece of wood.
 |
| The Woodpecker (Naked) |
The solenoid is powered by 2x9V batteries and the Atmega is powered from 3 * 4.5V batteries. The RTC is powered from the same source as the solenoid but with a voltage regulator, LM78S05, bringing that down to the required 5V. This is my first project trying to use a 5V module controlled directly from an Atmega chip. Its been an interesting experience. getting everything working together and able to run uninterupted for a long time. To preserve battery power I've used full power saving features of the Atmega so everything is switched into a low power sleep state for most of the time, only checking the time once every 9 seconds.
The main circuit layout is something like (use at own risk);
I used an Arduino to program the Atmega and then extracted the chip. Not the most elegant solution but the simplest with the hardware I had to hand. Very easy to break off connections doing this though so beware. Here is the script. I'm not big on comments, sorry. The code to calculate Summer time is for Athens Greece, switch over points are the last Sundays in March and October.
// RP © 2010
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <Wire.h>
#ifndef cbi
#define cbi( sfr, bit ) ( _SFR_BYTE( sfr ) &= ~_BV( bit ) )
#endif
#ifndef sbi
#define sbi( sfr, bit ) ( _SFR_BYTE( sfr ) |= _BV( bit ) )
#endif
#define DS1307_I2C_ADDRESS 0x68
int solenoidPin = 7; // digital 7
int SDAPin = 14 + 4; // analog 4
int SCLPin = 14 + 5; // analog 5
int RTCVCCPin = 14 + 3; // analog 3
byte decToBcd( byte val )
{
return ( ( val / 10 * 16 ) + ( val % 10 ) );
}
byte bcdToDec( byte val )
{
return ( ( val / 16 * 10 ) + ( val % 16 ) );
}
volatile boolean watchdogFired = true;
void setup()
{
cbi( SMCR,SE );
cbi( SMCR,SM0 );
sbi( SMCR,SM1 );
cbi( SMCR,SM2 );
randomSeed( analogRead( 0 ) );
Serial.begin( 38400 );
Wire.begin();
beatOutHour();
}
boolean summerTime( byte month, byte dayOfWeek, byte dayOfMonth )
{
if (month < 3 || month > 10)
return false;
if (month == 3)
{
int lastSunday = (dayOfWeek == 7) ? dayOfMonth : (dayOfMonth - dayOfWeek);
return ((31 - lastSunday) < 7);
}
else if (month == 10)
{
int lastSunday = (dayOfWeek == 7) ? dayOfMonth : (dayOfMonth - dayOfWeek);
return ((31 - lastSunday) >= 7);
}
else
return true;
}
void now( byte& second, byte& minute, byte& hour, byte& dayOfWeek )
{
pinMode( RTCVCCPin, OUTPUT );
digitalWrite( RTCVCCPin, HIGH );
Wire.beginTransmission( DS1307_I2C_ADDRESS );
Wire.send( 0x00 );
Wire.endTransmission();
Wire.requestFrom( DS1307_I2C_ADDRESS, 7 );
second = bcdToDec( Wire.receive() & 0x7f );
minute = bcdToDec( Wire.receive() );
hour = bcdToDec( Wire.receive() & 0x3f );
dayOfWeek = bcdToDec( Wire.receive() );
byte dayOfMonth = bcdToDec( Wire.receive() );
byte month = bcdToDec( Wire.receive() );
byte year = bcdToDec( Wire.receive() );
digitalWrite( RTCVCCPin, LOW );
pinMode( RTCVCCPin, INPUT );
if( summerTime( month, dayOfWeek, dayOfMonth ) )
hour++;
Serial.print( "time: " );
Serial.print( hour, DEC );
Serial.print( ":" );
Serial.print( minute, DEC );
Serial.print( ":" );
Serial.print( second, DEC );
Serial.print( ", day of week:" );
Serial.println( dayOfWeek, DEC );
delay( 2 );
}
void beatOutHour()
{
byte second, minute, hour, dayOfWeek;
now( second, minute, hour, dayOfWeek );
pinMode( solenoidPin, OUTPUT );
for( int beat = 0; beat < hour; beat++ )
{
digitalWrite(solenoidPin, HIGH);
delay( 100 );
digitalWrite(solenoidPin, LOW);
delay( 200 );
}
pinMode( solenoidPin, INPUT );
}
void loop()
{
if( watchdogFired == true )
{
watchdogFired = false;
Serial.println( "loop" );
delay( 2 );
byte second, minute, hour, dayOfWeek;
now( second, minute, hour, dayOfWeek );
if( hour == 10 && minute < 2 && (dayOfWeek == 6 || dayOfWeek == 7) )
{
Drum();
system_sleep( random(4) + 6 );
}
else
{
delay( 2 );
for( int seconds = ( 60 - second ); seconds > 0; seconds -= 8 )
system_sleep(9);
}
}
}
void Drum()
{
int beats = 7 + random( 9 );
int cadence = 12 + random( 7 );
int beatSpace = ( 1000 / cadence );
Serial.print( "beats: " );
Serial.print( beats, DEC );
Serial.print( ", cadence: " );
Serial.println( cadence, DEC );
delay( 2 );
pinMode( solenoidPin, OUTPUT );
for( int beat = 0; beat < beats; beat++ )
{
digitalWrite(solenoidPin, HIGH);
delay( beatSpace / 2 );
digitalWrite(solenoidPin, LOW);
delay( beatSpace / 2 );
}
pinMode( solenoidPin, INPUT );
}
void system_sleep(int ii)
{
Serial.print( "sleep: " );
Serial.println( ii, DEC );
delay( 2 );
setup_watchdog(ii);
cbi( ADCSRA, ADEN );
set_sleep_mode( SLEEP_MODE_PWR_DOWN );
sleep_enable();
sleep_mode();
sleep_disable();
sbi( ADCSRA, ADEN );
}
// 6 = 1 sec, 7 = 2 sec, 8 = 4 sec, 9 = 8 sec
void setup_watchdog(int ii)
{
byte bb;
int ww;
if( ii > 9 )
ii = 9;
bb = ii & 7;
if( ii > 7 )
bb |= ( 1 << 5 );
bb |= ( 1 << WDCE );
ww = bb;
MCUSR &= ~( 1 << WDRF );
WDTCSR |= ( 1 << WDCE ) | ( 1 << WDE );
WDTCSR = bb;
WDTCSR |= _BV( WDIE );
}
ISR( WDT_vect )
{
watchdogFired = true;
}
A fun and simple way to add a new dimension to your puzzle caches.
Ive two more variants on this currently in the pipeline.
1) Instead of powering a solenoid a stepper motor turns a hand cranked
music box mechanism. I don't know, the idea of walking in the mountains around Athens and suddenly hearing a music box playing in the middle of nowhere seems magical to me.
2) Using a
audio player to have it appear that someone is shouting "hey, its over here"
Let me know what you think. I would love to hear of anyone else taking puzzle caches to a new level.