Introduction: Surfin' Bird (Arduino Style)
I just hope every body's heard. The Bird is the Word! This is a simple device to play Surfin Bird really loudly when someone trips off the motion sensor. If you don't already own an Adafruit Wave Shield, I'd highly suggest purchasing one. It's become my favorite shield by far. I love the idea of a dead quiet space with no obvious electrical devices and then "Bamm, right in the kisser" with some annoying music. This can be placed anywhere, but my preferred location is the bathroom. It's echos real loud and there's nothing more annoying than letting everyone know that you've just entered the bathroom. Try pooping to surfin bird, I dare ya!
Step 1: Parts
Parts list:
Arduino Uno
Adafruit Wave Shield
PIR(motion sensor)
Battery pack
Rubber Ducky(optional)
Breakaway female Header(Optional)
wire
Tools:
Solder iron
Arduino IDE21(yeah I use an older one) Newer version would prolly work too
Wave shield library
X-acto knife
Step 2: The Code
/*
* //////////////////////////////////////////////////
* //making sense of the Parallax PIR sensor's output
* //////////////////////////////////////////////////
*
* Switches a LED according to the state of the sensors output pin.
* Determines the beginning and end of continuous motion sequences.
*
* @author: Kristian Gohlke / krigo(_)web.de / http://filformat.net
* @date: 3. September 2006
*
* kr1 (cleft) 2006
* released under a creative commons "Attribution-NonCommercial-ShareAlike 2.0" license
* http://creativecommons.org/licenses/by-nc-sa/2.0/de/
*
*
* The Parallax PIR Sensor is an easy to use digital infrared motion sensor module.
* (http://www.parallax.com/detail.asp?product_id=555-28027)
*
* The sensor´s output pin goes to HIGH if motion is present.
* However, even if motion is present it goes to LOW from time to time,
* which might give the impression no motion is present.
* This program deals with this issue by ignoring LOW-phases shorter than a given time,
* assuming continuous motion is present during these phases.
*
*/
/////////////////////////////
//VARS
#include
#include
#include "util.h"
#include "wave.h"
AF_Wave card;
File f;
Wavefile wave;
int calibrationTime = 30; //the time we give the sensor to calibrate itself (10-60 secs according to the datasheet)
long unsigned int lowIn; //the time when the sensor outputs a low impulse
long unsigned int pause = 5000; //the amount of milliseconds the sensor has to be low before we assume all motion has stopped
boolean lockLow = true;
boolean takeLowTime;
int pirPin = 6; //the digital pin connected to the PIR sensor's output
int ledPin = 13;
/////////////////////////////
//SETUP
void setup(){
Serial.begin(9600);
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
digitalWrite(pirPin, LOW);
//give the sensor some time to calibrate
Serial.print("calibrating sensor ");
for(int i = 0; i < calibrationTime; i++){
Serial.print(".");
delay(1000);
}
Serial.println(" done");
Serial.println("SENSOR ACTIVE");
delay(50);
if (!card.init_card()) {
return;
}
if (!card.open_partition()) {
return;
}
if (!card.open_filesys()) {
return;
}
if (!card.open_rootdir()) {
return;
}
}
////////////////////////////
//LOOP
void loop(){
if(digitalRead(pirPin) == HIGH){
digitalWrite(ledPin, HIGH); //the led visualizes the sensors output pin state
if(lockLow){
lockLow = false; //make sure we wait for a transition to LOW before any further output is made
Serial.println("---");
Serial.print("motion detected at ");
Serial.print(millis()/1000);
Serial.println(" sec");
delay(50);
}
takeLowTime = true;
}
if(digitalRead(pirPin) == LOW){
digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
}
if(!lockLow && millis() - lowIn > pause){ //if the sensor is low for more than the given pause, we assume that no more motion is going to happen
lockLow = true; //makes sure this block of code is only executed again after a new motion sequence has been detected
Serial.print("motion ended at "); //output
Serial.print((millis() - pause)/1000);
Serial.println(" sec");
delay(50);
}
switch(digitalRead(pirPin) == HIGH){
case 1:
playcomplete("03SURF~1.WAV");
}
}}
void playcomplete(char *name) {
playfile(name);
while (wave.isplaying);
card.close_file(f);
}
void playfile(char *name) {
// stop any file already playing
if (wave.isplaying) {
wave.stop();
card.close_file(f);
}
f = card.open_file(name);
if (f && wave.create(f)) {
wave.play();
}
}
* //////////////////////////////////////////////////
* //making sense of the Parallax PIR sensor's output
* //////////////////////////////////////////////////
*
* Switches a LED according to the state of the sensors output pin.
* Determines the beginning and end of continuous motion sequences.
*
* @author: Kristian Gohlke / krigo(_)web.de / http://filformat.net
* @date: 3. September 2006
*
* kr1 (cleft) 2006
* released under a creative commons "Attribution-NonCommercial-ShareAlike 2.0" license
* http://creativecommons.org/licenses/by-nc-sa/2.0/de/
*
*
* The Parallax PIR Sensor is an easy to use digital infrared motion sensor module.
* (http://www.parallax.com/detail.asp?product_id=555-28027)
*
* The sensor´s output pin goes to HIGH if motion is present.
* However, even if motion is present it goes to LOW from time to time,
* which might give the impression no motion is present.
* This program deals with this issue by ignoring LOW-phases shorter than a given time,
* assuming continuous motion is present during these phases.
*
*/
/////////////////////////////
//VARS
#include
#include
#include "util.h"
#include "wave.h"
AF_Wave card;
File f;
Wavefile wave;
int calibrationTime = 30; //the time we give the sensor to calibrate itself (10-60 secs according to the datasheet)
long unsigned int lowIn; //the time when the sensor outputs a low impulse
long unsigned int pause = 5000; //the amount of milliseconds the sensor has to be low before we assume all motion has stopped
boolean lockLow = true;
boolean takeLowTime;
int pirPin = 6; //the digital pin connected to the PIR sensor's output
int ledPin = 13;
/////////////////////////////
//SETUP
void setup(){
Serial.begin(9600);
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
digitalWrite(pirPin, LOW);
//give the sensor some time to calibrate
Serial.print("calibrating sensor ");
for(int i = 0; i < calibrationTime; i++){
Serial.print(".");
delay(1000);
}
Serial.println(" done");
Serial.println("SENSOR ACTIVE");
delay(50);
if (!card.init_card()) {
return;
}
if (!card.open_partition()) {
return;
}
if (!card.open_filesys()) {
return;
}
if (!card.open_rootdir()) {
return;
}
}
////////////////////////////
//LOOP
void loop(){
if(digitalRead(pirPin) == HIGH){
digitalWrite(ledPin, HIGH); //the led visualizes the sensors output pin state
if(lockLow){
lockLow = false; //make sure we wait for a transition to LOW before any further output is made
Serial.println("---");
Serial.print("motion detected at ");
Serial.print(millis()/1000);
Serial.println(" sec");
delay(50);
}
takeLowTime = true;
}
if(digitalRead(pirPin) == LOW){
digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
}
if(!lockLow && millis() - lowIn > pause){ //if the sensor is low for more than the given pause, we assume that no more motion is going to happen
lockLow = true; //makes sure this block of code is only executed again after a new motion sequence has been detected
Serial.print("motion ended at "); //output
Serial.print((millis() - pause)/1000);
Serial.println(" sec");
delay(50);
}
switch(digitalRead(pirPin) == HIGH){
case 1:
playcomplete("03SURF~1.WAV");
}
}}
void playcomplete(char *name) {
playfile(name);
while (wave.isplaying);
card.close_file(f);
}
void playfile(char *name) {
// stop any file already playing
if (wave.isplaying) {
wave.stop();
card.close_file(f);
}
f = card.open_file(name);
if (f && wave.create(f)) {
wave.play();
}
}
Step 3: How It Works & Putting It All Together
The trickiest part of this is getting the file format on the SD card in the correct format and writing one line of code propperly so it can be played.
//case:1 playcomplete("03SURF~1.WAV");
Now the file name on the SDcard is something long like "03 surfin bird by the Yardmen" or something like that. I got it off iTunes and let iTunes convert it to a .wav for me. See LadyAda tutorial on how thats done.
The PIR(passive Infrared Sensor) is connected to digital pin6, 5volts, and ground. Pretty simple stuff. I *borrowed* the code to calibrate it better. It's not need but I like having 30 seconds to set it up and get out of the room or space. You could set the calibration delay for longer too.
Half-way through this project I decided I wanted a fancier case than my standard Styrofoam cup. Target and Walmart both sell this rubber ducky that's meant to keep children from bashing their soft little heads on the tub spout. It's five dollars and has a surf board! Styrofoam works better in an Urban outdoor location while something like a ducky is better suited to the house. Think about where you want to place this before you decide on a case for concealment and protection.
Because the ducky's butt is smaller than the cup, I also switched out speakers from the original Adafruit one. I jacked one from a Goodwill "Big Mouth Billy Bass" device(an American cultural meme from 8 years ago that cost $3 and yielded tons of parts).
//case:1 playcomplete("03SURF~1.WAV");
Now the file name on the SDcard is something long like "03 surfin bird by the Yardmen" or something like that. I got it off iTunes and let iTunes convert it to a .wav for me. See LadyAda tutorial on how thats done.
The PIR(passive Infrared Sensor) is connected to digital pin6, 5volts, and ground. Pretty simple stuff. I *borrowed* the code to calibrate it better. It's not need but I like having 30 seconds to set it up and get out of the room or space. You could set the calibration delay for longer too.
Half-way through this project I decided I wanted a fancier case than my standard Styrofoam cup. Target and Walmart both sell this rubber ducky that's meant to keep children from bashing their soft little heads on the tub spout. It's five dollars and has a surf board! Styrofoam works better in an Urban outdoor location while something like a ducky is better suited to the house. Think about where you want to place this before you decide on a case for concealment and protection.
Because the ducky's butt is smaller than the cup, I also switched out speakers from the original Adafruit one. I jacked one from a Goodwill "Big Mouth Billy Bass" device(an American cultural meme from 8 years ago that cost $3 and yielded tons of parts).
Step 4: Making the Ducky Case
I'll note mostly on the pictures, the interior of this has some hard plastic that had to melted rather than Xacto'd through. I heated a screw driver up and used it like a soldering iron to melt it away. I'm currently away from my tools, so I couldn't drill, dremel or smash my way through.