As I cannot seem to get me, the project, and a camera all in the same place at the same time, here is the functional code.
All that remains is to add the “back door” feature to allow entry to the box if an external power source is used. According to Mikal Hart, there are 12 people he is aware of building this box, or variations. Two have already published their builds. Take a look at The Frustromantic Box and the Buzzel.
/*
Code written by Allen Burt - youevolve@buidsomething.net
Original build and concept and the TinyGPS and NewsoftSerial libraries – Mikal Hart – arduiniana.org
Also thanks to Mikal for guiding me out of a corner I had painted myself into.
Thank you, also, to the arduino community for all the code examples which have guided me.
Huge thank you to my wife for loving geeks and putting up with my new obsession.
———————————-
Due to a conflict with NewSoftSerial(actually, all Serial libraries) and the Arduino 017
Servo library you MUST use either Arduino 016 (or earlier) OR copy the Servo library from
an earlier version to the Arduino 017 Libraries folder. If you experience random movement
of the servo, this bug is the issue.
This code assumes that you have a 4800-baud serial GPS device hooked up on pins 2(rx)
and 3(tx) and a serial LCD display on pin 1 using kit LCD117b from Modern Device Company
New installations must have the EEPROM cleared.
Use this code to clear the EEPROM registers on fresh installs and new puzzle sessions.
EEPROMCLEAR code:
#include <EEPROM.h>
void setup()
{
// write a 0 to all 512 bytes of the EEPROM
for (int i = 0; i < 512; i++)
EEPROM.write(i, 0);
// turn the LED on when we’re done
digitalWrite(13, HIGH);
}
void loop()
{
}
*/
#include <NewSoftSerial.h>
#include <TinyGPS.h>
#include <EEPROM.h>
#include <Servo.h>
Servo myservo; // create servo object to control a servo
TinyGPS gps;
NewSoftSerial nss(2, 3);
float gpsdump(TinyGPS &gps);
bool feedgps();
void printFloat(double f, int digits = 2);
int address = 0; //address of EEPROM byte we will be writing to
byte value; // number of program cycles
int offPin = 8; // Pololu off line connected to digital pin 8;
int newvalue; //placeholder for incrementing program cycles
float dest_latitude = 39.393839; //exoticfelinerescuecenter.org latitude
float dest_longitude = -87.068743; //exoticfelinerescuecenter.org longitude
float radius = 3956.6;
const float two = 2.0;
unsigned long timer = 0;
void setup()
{
myservo.attach(9); // attaches the servo on pin 9 to the servo object
pinMode(offPin, OUTPUT); // sets the digital pin connected to the Pololu as output
value = EEPROM.read(address); // read a byte from the current address of the EEPROM
Serial.begin(9600); //Display runs at 9600 baud
nss.begin(4800); // GPS runs at 4800 baud
// Serial.print(“?S0″); // lose the original boot screen – this only really needs to be run the first time the kit 117b is used
// delay(100);
delay (3000); //wait a few seconds for the screen to boot up
Serial.print(“?f”); // clear the LCD
delay(10);
Serial.print(“?x00?y0″); // cursor to first character of line 0
delay(10);
Serial.print(“Welcome to”); //Welcome message
delay(10);
Serial.print(“?x00?y1″); // cursor to first character of line 1
delay(10);
Serial.print(“the Game…”);
delay(4000);
Serial.print(“?f”); // clear the LCD
delay(10);
Serial.print(“?x00?y0″); // cursor to first character of line 0
delay(10);
Serial.print(value, DEC); //print the stored attempt counter
delay (10);
Serial.println( ” of 50″);
delay (10);
Serial.print(“?x00?y1″); // cursor to first character of line 1
delay(10);
Serial.print(“Attempts”);
delay(5000);
myservo.write(60); // make sure the servo is in the locked position
newvalue = ++value; //add one to the program cycle counter
EEPROM.write(address, newvalue); //write the new value to EEPROM
if (value >= 51) //if we have used up all our turns, print message and shut down
{
Serial.print(“?f”); // clear the LCD
delay(10);
Serial.print(“?x00?y0″); // cursor to first character of line 0
delay(10);
Serial.print(“Game Over”);
delay(15000); // wait for 15 seconds
digitalWrite(offPin, HIGH); // Sends the signal to the Pololu switch to turn off the arduino
}
}
void loop()
{
bool newdata = false;
{
Serial.print(“?f”); // clear the LCD
delay(10);
Serial.print(“?x00?y0″); // cursor to first character of line 0
delay(10);
Serial.print(“Seeking Signal”);
delay(10);
do //keep feeding the GPS and counting the time until we get a lock or run out of time
{
feedgps();
if (feedgps()){
newdata = true;
}
timer = millis();
delay(1000);
}
while ((newdata = false) && (timer < 300000)); //Look for a signal for 5 minutes if (timer >= 300000){ // if no signal in 5 minutes, power down
Serial.print(“?f”); // clear the LCD
delay(10);
Serial.print(“?x00?y1″); // cursor to first character of line 0
delay(10);
Serial.print(“No Signal”);
delay(5000);
digitalWrite(offPin, HIGH); // Sends the signal to the Pololu switch to turn off the arduino
}
if (feedgps()){
newdata = true;
}
if (newdata) // if we get data, print the distance to target
{
Serial.print(“?f”); // clear the LCD
delay(10);
Serial.print(“?x00?y0″); // cursor to first character of line 0
delay(10);
Serial.println(” Distance”);
delay(10);
Serial.print(“?x00?y1″); // cursor to first character of line 1
delay(10);
printFloat(gpsdump(gps));
Serial.print(” Miles”);
if (gpsdump(gps) <= 0.10) { //set this to the desired distance to target unlock “zone.”
// Remember, you may have poor signal and get some drift in your location.
Serial.print(“?f”); // clear the LCD
delay(10);
Serial.print(“?x00?y0″); // cursor to first character of line 0
delay(10);
Serial.println(” Success!!!”);
myservo.write(160); // if we are close to the target location, open the lock
delay(15000); // wait 15 seconds
digitalWrite(offPin, HIGH); // Sends the signal to the Pololu switch to turn off the arduino
}
else {
delay(60000); // wait for 1 minute
digitalWrite(offPin, HIGH); // Sends the signal to the Pololu switch to turn off the arduino
}
}
}
}
void printFloat(double number, int digits) //this void sequence from the TinyGPS library
{
// Handle negative numbers
if (number < 0.0)
{
Serial.print(‘-’);
number = -number;
}
// Round correctly so that print(1.999, 2) prints as “2.00″
double rounding = 0.5;
for (uint8_t i=0; i 0)
Serial.print(“.”);
// Extract digits from the remainder one at a time
while (digits– > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
Serial.print(toPrint);
remainder -= toPrint;
}
}
float gpsdump(TinyGPS &gps)
{
float flat, flon, d;
unsigned long age, date, time, chars; //look at using date and time as well for unlock conditions!
feedgps();
gps.f_get_position(&flat, &flon, &age); // look at using the age of the data to confirm how good the signal lock is.
/*
Thanks to arduino forum member Alligator for this version of the Haversine formula for distance calculation
*/
float delta_lat = radians(dest_latitude – flat);
float delta_lon = radians(dest_longitude – flon);
float a = square(sin(delta_lat/two)) + cos(radians (flat)) * cos(radians (dest_latitude)) * square(sin(delta_lon/two));
float c = two * asin(sqrt(a));
d = radius * c;
return d;
}
bool feedgps()
{
while (nss.available())
{
if (gps.encode(nss.read()))
return true;
}
return false;
}
