Categories

Archives

The Code - beta

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;
}

Bitwise Operations Tutorial

I came across this wonderful tutorial today. evilmadscientist.com posted a link in their December linkdump.

If you find bitwise operations confusing, check it out. It sure cleared many things up for me.

Success!

The code is finished and everything works as advertised!

I’ll be documenting the build on Instructables in the days to come. Please stand by…..

NewSoftSerial, Servo, and Arduino 017

After my initial joy of completing the distance to target code, imagine my frustration when I could not get a simple servo to function. I’d load my code and the servo would jump around like crazy for NO perceptible reason.

After hours of beating my head on the keyboard, I finally found the cause. Turns out there is a conflict between NewSoftSerial and the Arduino 017 Servo library. This has to do with interrupts; a subject of which I know nothing.

The solution? Download Arduino 016, copy the Servo library to the Arduino 017 libraries folder, enjoy your functional code.

Progress...

I finally threw up my hands in frustration and contacted the creator of the GPS puzzle box, Mikal Hart. The problem was I trying to pull a value from a void statement. Mikal was very helpful and made a couple of suggestions to improve my code. All I had to do to get the code to do what I wanted was change the void statement to a float instead. *smacks hand to forehead*

Beyond that, Mikal suggested I change the distance to target calculation I am using. He pointed out that over long distances the error to target location could be significant. I was aware of this problem, but hadn’t considered what would happen if I sent the box to someone over 1000 miles away. He pointed me to the NMEA library’s distance_to function. However, I cannot get the example code to compile. Anyone else have any luck with this?

Pointers

As I am developing the puzzle box code, I find I do not fully understand the Tinygps library example code. The problem is the use of the “&” symbol along with a variable name. It turns out this is a “pointer operator.”

Great.

What is it?

The arduino documentation says the following:

The pointer operators
& (reference) and * (dereference)

Pointers are one of the more complicated subjects for beginners in learning C, and it is possible to write the vast majority of Arduino sketches without ever encountering pointers. However for manipulating certain data structures, the use of pointers can simplify the code, and and knowledge of manipulating pointers is handy to have in one’s toolkit.

Great.

What is it?

So I turned to a trusty friend who just so happens to teach programming and his response was much better.

“…When a value is passed to a function, a brand new variable is created and the value is copied to it. This protects the original value from any changes that might accidentally occur to the value. Occasionally, a programmer really does want to change the value of the original variable. In C, the programmer would pass the address of the variable in memory to the function and then access the variable through the memory. So the value copied was the location of the variable and not the variable itself.

The implementation in C was a little confusing, so C++ added the concept of reference variables. A reference variable is a way for the programmer to declare “I intend to alter the contents of this variable in a way that will alter the original variable passed.” The & symbol is only used in declaring the intent in the function declaration. The variable may be used just as if it was the original. It does not need to have the same name. Think of the reference variable as an alias. I may call myself Daniel or Dan, but they both refer to me. When the function is complete, any changes made to the variable inside the function persist.

gps (variable in loop() function) ——> location in memory <—–gps (variable in gpsdump() function)

normally, without a reference variable it looks like this:

gps (variable in loop() function) ——> location in memory ——-> copied to new location in memory <—— gps (variable in gpsdump() function)

To further complicate matters, the & symbol is used to grab the address of any variable to store in a pointer and it is also used to perform bitwise “and” operation. For the purposes of reference variables, they will always and only occur in function declarations….”

Got it? Me either, but I’m working on it.

P.S. Thanks for the help, Dan!

My new Instructable


Using the Pololu Pushbutton Power SwitchMore DIY How To Projects

Interesting variation…

A comment on the GPS puzzle page got me thinking. The commenter talked about a magical box that could only be opened by the correct person, on the correct date, time, and place. Date, time and place could all be pulled from the GPS data. But how to make sure the correct person is opening the box? RFID, fingerprint scanner, and passwords all come to mind. Each has particular positive and negative traits. Right now, RFID is looking the best and most affordable solution.

Still waiting for replacement parts…..

Setback

I was bread boarding and coding away at the coffee table in our living room when my wife arrived home with our kids. This would not have been an issue except they brought over two other neighborhood kids. I needed to move my project.

As I was getting everything out of the way (too quickly) I suddenly saw a spark appear on the GPS module. As the magic blue smoke escaped I saw my dream of finishing this project this weekend float away.

Two new GPS units ordered from Sparkfun as well as a couple more Pololu switches.

Easier than I thought

The Pololu switch turned out to be much easier than I thought. Basically, you have voltage in, voltage out, and a control pin. Apply power to the voltage in and place your load on the voltage out. At this point you have a basic on/off switch. Press the button and the load is powered, press again and it turns off.

Now use this to power up a microcontroller and run a wire from one of its pins to the control point of the Pololu switch (labeled OFF on the circuit board). Program your microcontroller to set that pin HIGH when you wish to power the unit down and you are done!

Here is an example sketch using the arduino pin 7 for control. Press the button to turn the arduino on, 30 seconds later it shuts off.
———————-
//Pololu example code for the Arduino

int offPin = 7; // Pololu off line connected to digital pin 7;

void setup()
{
pinMode(offPin, OUTPUT); // sets the digital pin as output

}

void loop()
{
delay(30000); // wait for 30 seconds
digitalWrite(offPin, HIGH); // sends the signal to turn off the arduino

}