Introduction: Multi-personality Fortune Teller
This Arduino project is a throwback to several carnival and novelty arcade games from when I was a kid. I’ve done many Arduino projects, but this is my first project that was my own design. Prior to this, I generally followed someone else’s design or idea.
My main motivation was to try to understand using the Adafruit Wave shield. Someday I would like to have the Arduino also control the servo that controls the skull, but for this project the talking skull portion was a kit. There are other talking skulls available (Talking thru Boris, a halloween decoration that can be found on auction sites).
I also wanted to build this as inexpensively as possible & use parts that are either things I already had on hand, or parts that are plentiful & cheap.
Using this approach often makes the finished project more unique.
A note about the video: I removed the glass to make the project more visible in the video.
Step 1: Parts List
This was a long project so I won't attempt to list everything but the key elements are:
-Arduino
-Wave shield & SD card(Adafruit)
-Talking skull (I got mine from Nuts & Volts)
-potentiometer (Radio Shack)
-coin op mechanism (Adafruit)
-inexpensive computer speakers (Thrift store)
-LED strip lights (online supplier)
-UV LED lights(online supplier)
-Windshield wiper motor (salvage)
-11X14 frame
-Mirror window tint
-3/4" plywood
-1/2 doors
-flocked paper
I will try to point out helpful parts throughout the instructable but slight alterations in the design should make it easier to utilize parts you already have.
-Arduino
-Wave shield & SD card(Adafruit)
-Talking skull (I got mine from Nuts & Volts)
-potentiometer (Radio Shack)
-coin op mechanism (Adafruit)
-inexpensive computer speakers (Thrift store)
-LED strip lights (online supplier)
-UV LED lights(online supplier)
-Windshield wiper motor (salvage)
-11X14 frame
-Mirror window tint
-3/4" plywood
-1/2 doors
-flocked paper
I will try to point out helpful parts throughout the instructable but slight alterations in the design should make it easier to utilize parts you already have.
Step 2: Skull Housing Construction
I built the box that contains the skull first. The dimensions of the box will depend on the size of frame you use & how thick the border of the frame is. The wider the border, the more room for error. It is mounted with a piano hinge on one side & some brackets on the other, so I could make adjustments easily, although it doesn't allow easy access to the general public. My box is slightly wider than the inside edge of the frame. There is a groove that is cut into the plywood on the backside for mounting the back panel.
Once the box was constructed, I lined the inside of the box with black paper on all sides except for the bottom. Fuzzy, flocked paper works best, but ordinary black construction paper will be fine, or even painting the inside of the box. I cut a piece of plywood that fits just inside the bottom of the box when stood upright. This is what we'll mount the bracket that holds the skull to.
I used flat steel bracket stock to make the bracket. After deciding approximately how high I wanted the skull, I cut & bent the bracket accordingly, being sure to allow enough surface area to mount the skull securely. Once I'd bent the bracket, I mounted the skull on it. In my case, I cut two small notches in the hole at the base of the skull, which were large enough to insert the bracket. I also added a bolt for the skull to rest on. Now put the whole assembly together & line it up in the box, confirming that the skull is where you want it. Confirm the bend is at the right place & that the skull has enough clearance at the front & the back, since you do not want the spinning disc rubbing up against the skull or the skull touching the glass. Mark where you want your mounting holes for the bracket & remove everything so you can drill your pilot holes into the base. Remove everything from the bracket temporarily, and make any necessary adjustments to the bracket. Once you have the bracket perfect, heat the bracket with a plumbers torch until it's red hot. Then drop it into a pan of water to cool it quickly. This will set your bend & make it springy & rigid. Cover your plywood base with black paper & cut out your pilot holes with a craft knife.
I rolled some paper over a piece of a florescent tube protector & taped it with some black tape to conceal the bracket.
Drill a hole large enough to fit the ends to all your power & audio cables into at the base of the bracket. You want your tube to be able to conceal this. NOTE: this hole needs to be big enough to stuff the cables through, while also having other wires running through it. Mount your bracket using large screws & washers or lag bolts. I used a stiff piece of wire to fish all the cables through the hole & the tube.
Your finished base should look something like the final picture in this step.
Once the box was constructed, I lined the inside of the box with black paper on all sides except for the bottom. Fuzzy, flocked paper works best, but ordinary black construction paper will be fine, or even painting the inside of the box. I cut a piece of plywood that fits just inside the bottom of the box when stood upright. This is what we'll mount the bracket that holds the skull to.
I used flat steel bracket stock to make the bracket. After deciding approximately how high I wanted the skull, I cut & bent the bracket accordingly, being sure to allow enough surface area to mount the skull securely. Once I'd bent the bracket, I mounted the skull on it. In my case, I cut two small notches in the hole at the base of the skull, which were large enough to insert the bracket. I also added a bolt for the skull to rest on. Now put the whole assembly together & line it up in the box, confirming that the skull is where you want it. Confirm the bend is at the right place & that the skull has enough clearance at the front & the back, since you do not want the spinning disc rubbing up against the skull or the skull touching the glass. Mark where you want your mounting holes for the bracket & remove everything so you can drill your pilot holes into the base. Remove everything from the bracket temporarily, and make any necessary adjustments to the bracket. Once you have the bracket perfect, heat the bracket with a plumbers torch until it's red hot. Then drop it into a pan of water to cool it quickly. This will set your bend & make it springy & rigid. Cover your plywood base with black paper & cut out your pilot holes with a craft knife.
I rolled some paper over a piece of a florescent tube protector & taped it with some black tape to conceal the bracket.
Drill a hole large enough to fit the ends to all your power & audio cables into at the base of the bracket. You want your tube to be able to conceal this. NOTE: this hole needs to be big enough to stuff the cables through, while also having other wires running through it. Mount your bracket using large screws & washers or lag bolts. I used a stiff piece of wire to fish all the cables through the hole & the tube.
Your finished base should look something like the final picture in this step.
Step 3: Preparing the Frame
The frame is just an ordinary picture frame purchased from a hobby supplier. You want to get a wood frame that is wide enough to hide the edges of the box, yet deep enough to put a screw into without the screw coming out of the front of the frame. As I mentioned before, the wider the border of the frame, the more forgiving it will be when aligning it.
I used mirror privacy tint on the glass, which can be purchased at a hardware store or done by a pro at an auto tint service. I had mine done at an auto-tinter because I didn't see the need to buy a whole roll of tint just so I could use a couple of feet of it.
When you typically buy frames at a hobby store, they are just the frame, so I used strips of 1/8" plywood that were cut on the table saw. I predrilled the holes for the screws & lined it all up on the frame. I predrilled holes in the frame also, using a scrap piece of plexiglas instead of the glass as a spacer. In my project, I used a matte board border to frame the skull & help conceal the lights. Since this sits right next to the glass, I slipped a piece of this next to the plexiglas before drilling my pilot holes.
When drilling your pilot holes, mark one spot on each strip on both the strip & the frame with something distinct. This is so you will not get the pieces mixed up when you reassemble them. I drew a line on one, an x on the next one, a 0 on the third one and a black dot on the final one. This way, when or if you take it apart, you can easily reassemble it by aligning the symbols, so that all you pilot holes will match up.
Mounting a piano hinge is usually easier than using separate hinges. Just line it up so that it’s even along the frame from the edge. Drill a pilot hole for a screw on the middle of the hinge and put a screw in it. Re-align so that you’re sure it’s where you want it & drill a pilot hole for one of the end screws. Then put a screw in it. It should be held in place good enough that you can drill all the other pilot holes. The other side is easy because it should just line up with the outside edge of the box.
Once assembled, the whole box & frame should resemble a very deep medicine cabinet.
I used mirror privacy tint on the glass, which can be purchased at a hardware store or done by a pro at an auto tint service. I had mine done at an auto-tinter because I didn't see the need to buy a whole roll of tint just so I could use a couple of feet of it.
When you typically buy frames at a hobby store, they are just the frame, so I used strips of 1/8" plywood that were cut on the table saw. I predrilled the holes for the screws & lined it all up on the frame. I predrilled holes in the frame also, using a scrap piece of plexiglas instead of the glass as a spacer. In my project, I used a matte board border to frame the skull & help conceal the lights. Since this sits right next to the glass, I slipped a piece of this next to the plexiglas before drilling my pilot holes.
When drilling your pilot holes, mark one spot on each strip on both the strip & the frame with something distinct. This is so you will not get the pieces mixed up when you reassemble them. I drew a line on one, an x on the next one, a 0 on the third one and a black dot on the final one. This way, when or if you take it apart, you can easily reassemble it by aligning the symbols, so that all you pilot holes will match up.
Mounting a piano hinge is usually easier than using separate hinges. Just line it up so that it’s even along the frame from the edge. Drill a pilot hole for a screw on the middle of the hinge and put a screw in it. Re-align so that you’re sure it’s where you want it & drill a pilot hole for one of the end screws. Then put a screw in it. It should be held in place good enough that you can drill all the other pilot holes. The other side is easy because it should just line up with the outside edge of the box.
Once assembled, the whole box & frame should resemble a very deep medicine cabinet.
Step 4:
The base sits inside the box on two strips of wood, which allows the wires to sit in the space without being pinched. I used a piece of stretchy fabric in the back to keep the wires in place for the notch in the back cover.
I mounted the LED light strips onto some drywall corner protector. This material already has adhesive strips on them. I was able to peel adhesive off of the LEDs & the adhesive off the corner protector to make a really good bond. I then used screws to mount the corner protector to the inside front of the box, just inside where the frame is. On this project, I also wanted to use some UV LEDs, but I couldn't find any lightstrips that were UV so I made my own with single LEDs & some spare strips of thin plastic.
I cut a piece of 1/2 inch plywood to fit inside the groove on the back of the box. This is what we will mount the windshield wiper motor to. I also mounted the Arduino electronics to this, but if I did it again I probably wouldn't do it that way. When mounting the motor, be sure that you mount it securely because over time, vibration from the motor might work it loose. I made the support sturdier by using a metal plate on the inside. Make sure that you put the screw heads on the inside so that you'll have enough clearance for your spinning disc. Since the skull sits right in the middle of the spinning disc, it isn't necessary to cover up the mounting bolt to the motor because it won't be visible.
I mounted the LED light strips onto some drywall corner protector. This material already has adhesive strips on them. I was able to peel adhesive off of the LEDs & the adhesive off the corner protector to make a really good bond. I then used screws to mount the corner protector to the inside front of the box, just inside where the frame is. On this project, I also wanted to use some UV LEDs, but I couldn't find any lightstrips that were UV so I made my own with single LEDs & some spare strips of thin plastic.
I cut a piece of 1/2 inch plywood to fit inside the groove on the back of the box. This is what we will mount the windshield wiper motor to. I also mounted the Arduino electronics to this, but if I did it again I probably wouldn't do it that way. When mounting the motor, be sure that you mount it securely because over time, vibration from the motor might work it loose. I made the support sturdier by using a metal plate on the inside. Make sure that you put the screw heads on the inside so that you'll have enough clearance for your spinning disc. Since the skull sits right in the middle of the spinning disc, it isn't necessary to cover up the mounting bolt to the motor because it won't be visible.
Step 5: Cutting the Disc
My disc is cut from Plexiglas, but could be done with anything fairly lightweight. There is an easy method for cutting true circles out of plexiglas. First, decide how big you want your circle, then divide that number in half. Nail two nails in a strip of wood exactly that far apart. Then, drive the nails in, just far enough that the points only stick out an 1/8". Drill a hole in your plexiglas where you would like your disc’s center to be. Sharpen one of the nails so that the front side is flat. Picture a chisel edge on the nail, instead of a knife edge. Insert the other nail in the hole on the plexiglas & slowly rotate the tool around the perimeter of the hole. Flip the plastic over & do the same on the other side. Make multiple passes. The more patient you are, the better the finished product.
Gently flex the plex along the cut edge, so that it snaps along where you've made your cut. This is the best method I've used to cut from plex, because using a saw heats the plastic & melts it. I glued my spiral to the disc using craft glue. The example shown isn't the same size disc that I used in the final project, it's just an example I made to show this technique.
Gently flex the plex along the cut edge, so that it snaps along where you've made your cut. This is the best method I've used to cut from plex, because using a saw heats the plastic & melts it. I glued my spiral to the disc using craft glue. The example shown isn't the same size disc that I used in the final project, it's just an example I made to show this technique.
Step 6:
This is how I have assembled the back cover. Originally, I used a cigar box to contain the electronics, but it isn't important to the design. This box was available & was about the right size, so I used it.
The LED light strips are 12v, so they are controlled using IRF510 mosfets using a signal sent from the Arduino. These lights flicker/strobe, which creates the illusion that the spinning disc is moving slower than it actually is. The motor is also 12V & is just turned on via mosfet. I used a separate power source to avoid any interference to the Arduino.
Lining the area where the back cover meets the box with craft foam sheets cut into strips will dampen any noise caused by the vibration of the motor. Using a layer of foam between the motor & the back cover will help as well.
The mosfets could all be soldered to the same board, but I just used one that I had created prior to this project. Since the motor & the LEDs are only on briefly, a heat sink isn't needed. Although if you alter the sketch to where they’re always on, a heat sink would be a good idea, especially for the motor mosfet.
The LED light strips are 12v, so they are controlled using IRF510 mosfets using a signal sent from the Arduino. These lights flicker/strobe, which creates the illusion that the spinning disc is moving slower than it actually is. The motor is also 12V & is just turned on via mosfet. I used a separate power source to avoid any interference to the Arduino.
Lining the area where the back cover meets the box with craft foam sheets cut into strips will dampen any noise caused by the vibration of the motor. Using a layer of foam between the motor & the back cover will help as well.
The mosfets could all be soldered to the same board, but I just used one that I had created prior to this project. Since the motor & the LEDs are only on briefly, a heat sink isn't needed. Although if you alter the sketch to where they’re always on, a heat sink would be a good idea, especially for the motor mosfet.
Step 7:
The cabinet itself could be an instructable all on it's own. I had two half doors sitting in my basement, so I cut them to the right length & used them for the sides. I used scrap plywood to make shelves that hold everything together. Make sure that you make the shelves wide enough to fit your skull compartment, but not so wide that you'll have to fill up extra space.
Since I was going to make this coin operated, I needed a compartment that would be easily accessible. I made three shelves that were the same size: One for the box to sit on and to be the top of the compartment, one for the lower part of the compartment, and one shelf for the bottom that also helps stabilize the whole project. I also attached a hinged door to the middle shelf. This will be the access point to collect the coins. I was also able to install a lock on the door, which is just a simple lock that you put a key in and turns. A little strip of metal slides into a groove & keeps the whole compartment locked.
The interior of the compartment contains the potentiometer, the amplifier, the speakers, & the coin op mechanism. The coin op mechanism is programmable. Once it is powered up, you push a button on the top of the unit. Then, you would drop 30 of same coin you'd like it to accept. After this, the light goes out & from then on it will only accept that coin, unless you repeat the programming process. From then on, any time someone drops the proper coin in, it sends a 5v signal out which is read by the Arduino. I made it 5 cents because I wanted to make it cheap, but didn't want to have to beg the bank to take my pennies. The potentiometer had an extraordinarily long shaft, so I mounted the pot to a piece of bracket stock & mounted the bracket stock to the machine.
The front side has the knob, the coin op slot, and the grills for the speakers. I routed the slots in the plywood & mounted the speakers behind them. I wanted there to be some depth to the front plate, so I copied my designs (5 cents/mood meter) to some shrink plastic & shrunk them down. They were then attached to the unit using screws. Shrink plastic shrinks down to a third of it's size, so calculate accordingly if you use this method.
Since I was going to make this coin operated, I needed a compartment that would be easily accessible. I made three shelves that were the same size: One for the box to sit on and to be the top of the compartment, one for the lower part of the compartment, and one shelf for the bottom that also helps stabilize the whole project. I also attached a hinged door to the middle shelf. This will be the access point to collect the coins. I was also able to install a lock on the door, which is just a simple lock that you put a key in and turns. A little strip of metal slides into a groove & keeps the whole compartment locked.
The interior of the compartment contains the potentiometer, the amplifier, the speakers, & the coin op mechanism. The coin op mechanism is programmable. Once it is powered up, you push a button on the top of the unit. Then, you would drop 30 of same coin you'd like it to accept. After this, the light goes out & from then on it will only accept that coin, unless you repeat the programming process. From then on, any time someone drops the proper coin in, it sends a 5v signal out which is read by the Arduino. I made it 5 cents because I wanted to make it cheap, but didn't want to have to beg the bank to take my pennies. The potentiometer had an extraordinarily long shaft, so I mounted the pot to a piece of bracket stock & mounted the bracket stock to the machine.
The front side has the knob, the coin op slot, and the grills for the speakers. I routed the slots in the plywood & mounted the speakers behind them. I wanted there to be some depth to the front plate, so I copied my designs (5 cents/mood meter) to some shrink plastic & shrunk them down. They were then attached to the unit using screws. Shrink plastic shrinks down to a third of it's size, so calculate accordingly if you use this method.
Step 8: The Arduino Sketch
I really wanted a fortune teller that would have more personality than the average machine, so I decided that I'd make it so the user could select the mood of the fortune teller. In the sketch, the wave files are divided up into different sections. You'll need to either name your sound files after the file names listed in the sketch or rename the names in the sketch after your files. So for example, the normal fortunes are named 1-14 (case 1-14). The sarcastic fortunes are named 15s-29s (case 15-29), so on & so forth. When you load your SD card with sound files, you'll need to rename your files accordingly. So if you were going to use this sketch as is, in order to make a Beatles jukebox , you’d have to rename Hey Jude “1” (that's 1, not 1.wav).
You'll need the wave shield, the Arduino, and an SD card. You'll also need to install the library for WaveHC. There are instructions on the Adafruit website on how to properly convert your audio files to the proper format for the Wave shield. I used Audacity for this, since there are lots of options for changing the sound of the files in Audacity, and also because I didn't really want the fortune teller to sound like me.
There are only a few digital pins available because the wave shield needs some of the pins to communicate with the Arduino. In my sketch, I used pins 6,7,8,& 9, as well as analog pin 5. The sketch uses noise from analog pin 0 for a more random audio selection. My project uses two different light sources. In the sketch, these are leduvPin & ledstrobePin. It also uses a pin for motor control (pin 9) & a pin for the coin slot (pin 8), labeled button in the sketch. The pot is wired to analog pin 5.
#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"
int ledstrobePin = 7;
int leduvPin = 6;
int delayPeriod = 20;
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the filesystem on the card
FatReader f; // This holds the information for the file we're play
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
#define MOTOR 9
#define BUTTON 8
#define LED 13
int val = 0;
int potvalue = 0;
long randNum;
// this handy function will return the number of bytes currently free in RAM, great for debugging!
int freeRam(void)
{
extern int __bss_end;
extern int *__brkval;
int free_memory;
if((int)__brkval == 0) {
free_memory = ((int)&free_memory) - ((int)&__bss_end);
}
else {
free_memory = ((int)&free_memory) - ((int)__brkval);
}
return free_memory;
}
void sdErrorCheck(void)
{
if (!card.errorCode()) return;
putstring("\n\rSD I/O error: ");
Serial.print(card.errorCode(), HEX);
putstring(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
void setup() {
// set up serial port
Serial.begin(9600);
pinMode(BUTTON, INPUT);
pinMode(LED, OUTPUT);
pinMode(leduvPin, OUTPUT);
pinMode(ledstrobePin, OUTPUT);
randomSeed(analogRead(0));
digitalWrite (BUTTON,HIGH);
pinMode(MOTOR, OUTPUT);
putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad
Serial.println(freeRam()); // if this is under 150 bytes it may spell trouble!
// Set the output pins for the DAC control. This pins are defined in the library
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
// if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
if (!card.init()) { //play with 8 MHz spi (default faster!)
putstring_nl("Card init. failed!"); // Something went wrong, lets print out why
sdErrorCheck();
while(1); // then 'halt' - do nothing!
}
// enable optimize read - some cards may timeout. Disable if you're having problems
card.partialBlockRead(true);
// Now we will look for a FAT partition!
uint8_t part;
for (part = 0; part < 5; part++) { // we have up to 5 slots to look in
if (vol.init(card, part))
break; // we found one, lets bail
}
if (part == 5) { // if we ended up not finding one :(
putstring_nl("No valid FAT partition!");
sdErrorCheck(); // Something went wrong, lets print out why
while(1); // then 'halt' - do nothing!
}
// Lets tell the user about what we found
putstring("Using partition ");
Serial.print(part, DEC);
putstring(", type is FAT");
Serial.println(vol.fatType(),DEC); // FAT16 or FAT32?
// Try to open the root directory
if (!root.openRoot(vol)) {
putstring_nl("Can't open root dir!"); // Something went wrong,
while(1); // then 'halt' - do nothing!
}
// Whew! We got past the tough parts.
putstring_nl("Ready!");
/* TCCR2A = 0;
TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;
//Timer2 Overflow Interrupt Enable
TIMSK2 |= 1<<TOIE2;
*/
}
void loop()
{
val = digitalRead(BUTTON);
potvalue = analogRead(5);
Serial.println(potvalue, DEC);
if (val == HIGH && potvalue >= 0 && potvalue <= 4)
{
randNum = random(1, 14);
delay(1000);
switch (randNum)
{
case 1:
Serial.println(1);
playcomplete("1.WAV");
break;
case 2:
Serial.println(2);
playcomplete("2.WAV");
break;
case 3:
Serial.println(3);
playcomplete("3.WAV");
break;
case 4:
Serial.println(4);
playcomplete("4.WAV");
break;
case 5:
Serial.println(5);
playcomplete("5.WAV");
break;
case 6:
Serial.println(6);
playcomplete("6.WAV");
break;
case 7:
Serial.println(7);
playcomplete("7.WAV");
break;
case 8:
Serial.println(8);
playcomplete("8.WAV");
break;
case 9:
Serial.println(9);
playcomplete("9.WAV");
break;
case 10:
Serial.println(10);
playcomplete("10.WAV");
break;
case 11:
Serial.println(11);
playcomplete("11.WAV");
break;
case 12:
Serial.println(12);
playcomplete("12.WAV");
break;
case 13:
Serial.println(13);
playcomplete("13.WAV");
break;
case 14:
Serial.println(14);
playcomplete("14.WAV");
break;
default:
break;
}
}
if (val == HIGH && potvalue >= 5 && potvalue <= 15)
{
randNum = random(15, 29);
delay(1000);
switch (randNum)
{
case 15:
Serial.println(15);
playcomplete("15s.WAV");
break;
case 16:
Serial.println(16);
playcomplete("16s.WAV");
break;
case 17:
Serial.println(17);
playcomplete("17s.WAV");
break;
case 18:
Serial.println(18);
playcomplete("18s.WAV");
break;
case 19:
Serial.println(19);
playcomplete("19s.WAV");
break;
case 20:
Serial.println(20);
playcomplete("20s.WAV");
break;
case 21:
Serial.println(21);
playcomplete("21s.WAV");
break;
case 22:
Serial.println(22);
playcomplete("22s.WAV");
break;
case 23:
Serial.println(23);
playcomplete("23s.WAV");
break;
case 24:
Serial.println(24);
playcomplete("24s.WAV");
break;
case 25:
Serial.println(25);
playcomplete("25s.WAV");
break;
case 26:
Serial.println(26);
playcomplete("26s.WAV");
break;
case 27:
Serial.println(27);
playcomplete("27s.WAV");
break;
case 28:
Serial.println(28);
playcomplete("28s.WAV");
break;
case 29:
Serial.println(29);
playcomplete("29s.WAV");
break;
default:
break;
}
}
if (val == HIGH && potvalue >= 16 && potvalue <= 22)
{
randNum = random(30, 44);
delay(1000);
switch (randNum)
{
case 30:
Serial.println(30);
playcomplete("30m.WAV");
break;
case 31:
Serial.println(31);
playcomplete("31m.WAV");
break;
case 32:
Serial.println(32);
playcomplete("32m.WAV");
break;
case 33:
Serial.println(33);
playcomplete("33m.WAV");
break;
case 34:
Serial.println(34);
playcomplete("34m.WAV");
break;
case 35:
Serial.println(35);
playcomplete("35m.WAV");
break;
case 36:
Serial.println(36);
playcomplete("36m.WAV");
break;
case 37:
Serial.println(37);
playcomplete("37m.WAV");
break;
case 38:
Serial.println(38);
playcomplete("38m.WAV");
break;
case 39:
Serial.println(39);
playcomplete("39m.WAV");
break;
case 40:
Serial.println(40);
playcomplete("40m.WAV");
break;
case 41:
Serial.println(41);
playcomplete("41m.WAV");
break;
case 42:
Serial.println(42);
playcomplete("42m.WAV");
break;
case 43:
Serial.println(43);
playcomplete("43m.WAV");
break;
case 44:
Serial.println(44);
playcomplete("44m.WAV");
break;
default:
break;
}
}
if (val == HIGH && potvalue >= 23 && potvalue <= 1023)
{
randNum = random(45, 60);
delay(1000);
switch (randNum)
{
case 45:
Serial.println(45);
playcomplete("45.WAV");
break;
case 46:
Serial.println(46);
playcomplete("46e.WAV");
break;
case 47:
Serial.println(47);
playcomplete("47e.WAV");
break;
case 48:
Serial.println(48);
playcomplete("48e.WAV");
break;
case 49:
Serial.println(49);
playcomplete("49e.WAV");
break;
case 50:
Serial.println(50);
playcomplete("50e.WAV");
break;
case 51:
Serial.println(51);
playcomplete("51e.WAV");
break;
case 52:
Serial.println(52);
playcomplete("52e.WAV");
break;
case 53:
Serial.println(53);
playcomplete("53e.WAV");
break;
case 54:
Serial.println(54);
playcomplete("54e.WAV");
break;
case 55:
Serial.println(55);
playcomplete("55e.WAV");
break;
case 56:
Serial.println(56);
playcomplete("56e.WAV");
break;
case 57:
Serial.println(57);
playcomplete("57e.WAV");
break;
case 58:
Serial.println(58);
playcomplete("58e.WAV");
break;
case 59:
Serial.println(59);
playcomplete("59e.WAV");
break;
case 60:
Serial.println(60);
playcomplete("60e.WAV");
break;
default:
break;
}
}
}
// Plays a full file from beginning to end with no pause.
void playcomplete(char *name) {
// call our helper to find and play this name
playfile(name);
while (wave.isplaying) {
digitalWrite (MOTOR, HIGH);
flash (20, delayPeriod);
digitalWrite (MOTOR, LOW);
// do nothing while its playing
}
// now its done playing
}
void flash (int numFlashes, int d)
{
for (int i = 0; i < numFlashes; i ++)
{
digitalWrite (ledstrobePin, HIGH);
digitalWrite (leduvPin, LOW);
delay (d);
digitalWrite (ledstrobePin, LOW);
digitalWrite (leduvPin, HIGH);
delay (d);
digitalWrite (ledstrobePin, LOW);
digitalWrite (leduvPin, LOW);
}
}
void playfile(char *name) {
// see if the wave object is currently doing something
if (wave.isplaying) {
flash (20, delayPeriod);// already playing something, so stop it!
wave.stop(); // stop it
}
// look in the root directory and open the file
if (!f.open(root, name)) {
putstring("Couldn't open file "); Serial.print(name); return;
}
// OK read the file and turn it into a wave object
if (!wave.create(f)) {
putstring_nl("Not a valid WAV"); return;
}
// ok time to play! start playback
wave.play();
}
You'll need the wave shield, the Arduino, and an SD card. You'll also need to install the library for WaveHC. There are instructions on the Adafruit website on how to properly convert your audio files to the proper format for the Wave shield. I used Audacity for this, since there are lots of options for changing the sound of the files in Audacity, and also because I didn't really want the fortune teller to sound like me.
There are only a few digital pins available because the wave shield needs some of the pins to communicate with the Arduino. In my sketch, I used pins 6,7,8,& 9, as well as analog pin 5. The sketch uses noise from analog pin 0 for a more random audio selection. My project uses two different light sources. In the sketch, these are leduvPin & ledstrobePin. It also uses a pin for motor control (pin 9) & a pin for the coin slot (pin 8), labeled button in the sketch. The pot is wired to analog pin 5.
#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"
int ledstrobePin = 7;
int leduvPin = 6;
int delayPeriod = 20;
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the filesystem on the card
FatReader f; // This holds the information for the file we're play
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
#define MOTOR 9
#define BUTTON 8
#define LED 13
int val = 0;
int potvalue = 0;
long randNum;
// this handy function will return the number of bytes currently free in RAM, great for debugging!
int freeRam(void)
{
extern int __bss_end;
extern int *__brkval;
int free_memory;
if((int)__brkval == 0) {
free_memory = ((int)&free_memory) - ((int)&__bss_end);
}
else {
free_memory = ((int)&free_memory) - ((int)__brkval);
}
return free_memory;
}
void sdErrorCheck(void)
{
if (!card.errorCode()) return;
putstring("\n\rSD I/O error: ");
Serial.print(card.errorCode(), HEX);
putstring(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
void setup() {
// set up serial port
Serial.begin(9600);
pinMode(BUTTON, INPUT);
pinMode(LED, OUTPUT);
pinMode(leduvPin, OUTPUT);
pinMode(ledstrobePin, OUTPUT);
randomSeed(analogRead(0));
digitalWrite (BUTTON,HIGH);
pinMode(MOTOR, OUTPUT);
putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad
Serial.println(freeRam()); // if this is under 150 bytes it may spell trouble!
// Set the output pins for the DAC control. This pins are defined in the library
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
// if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
if (!card.init()) { //play with 8 MHz spi (default faster!)
putstring_nl("Card init. failed!"); // Something went wrong, lets print out why
sdErrorCheck();
while(1); // then 'halt' - do nothing!
}
// enable optimize read - some cards may timeout. Disable if you're having problems
card.partialBlockRead(true);
// Now we will look for a FAT partition!
uint8_t part;
for (part = 0; part < 5; part++) { // we have up to 5 slots to look in
if (vol.init(card, part))
break; // we found one, lets bail
}
if (part == 5) { // if we ended up not finding one :(
putstring_nl("No valid FAT partition!");
sdErrorCheck(); // Something went wrong, lets print out why
while(1); // then 'halt' - do nothing!
}
// Lets tell the user about what we found
putstring("Using partition ");
Serial.print(part, DEC);
putstring(", type is FAT");
Serial.println(vol.fatType(),DEC); // FAT16 or FAT32?
// Try to open the root directory
if (!root.openRoot(vol)) {
putstring_nl("Can't open root dir!"); // Something went wrong,
while(1); // then 'halt' - do nothing!
}
// Whew! We got past the tough parts.
putstring_nl("Ready!");
/* TCCR2A = 0;
TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;
//Timer2 Overflow Interrupt Enable
TIMSK2 |= 1<<TOIE2;
*/
}
void loop()
{
val = digitalRead(BUTTON);
potvalue = analogRead(5);
Serial.println(potvalue, DEC);
if (val == HIGH && potvalue >= 0 && potvalue <= 4)
{
randNum = random(1, 14);
delay(1000);
switch (randNum)
{
case 1:
Serial.println(1);
playcomplete("1.WAV");
break;
case 2:
Serial.println(2);
playcomplete("2.WAV");
break;
case 3:
Serial.println(3);
playcomplete("3.WAV");
break;
case 4:
Serial.println(4);
playcomplete("4.WAV");
break;
case 5:
Serial.println(5);
playcomplete("5.WAV");
break;
case 6:
Serial.println(6);
playcomplete("6.WAV");
break;
case 7:
Serial.println(7);
playcomplete("7.WAV");
break;
case 8:
Serial.println(8);
playcomplete("8.WAV");
break;
case 9:
Serial.println(9);
playcomplete("9.WAV");
break;
case 10:
Serial.println(10);
playcomplete("10.WAV");
break;
case 11:
Serial.println(11);
playcomplete("11.WAV");
break;
case 12:
Serial.println(12);
playcomplete("12.WAV");
break;
case 13:
Serial.println(13);
playcomplete("13.WAV");
break;
case 14:
Serial.println(14);
playcomplete("14.WAV");
break;
default:
break;
}
}
if (val == HIGH && potvalue >= 5 && potvalue <= 15)
{
randNum = random(15, 29);
delay(1000);
switch (randNum)
{
case 15:
Serial.println(15);
playcomplete("15s.WAV");
break;
case 16:
Serial.println(16);
playcomplete("16s.WAV");
break;
case 17:
Serial.println(17);
playcomplete("17s.WAV");
break;
case 18:
Serial.println(18);
playcomplete("18s.WAV");
break;
case 19:
Serial.println(19);
playcomplete("19s.WAV");
break;
case 20:
Serial.println(20);
playcomplete("20s.WAV");
break;
case 21:
Serial.println(21);
playcomplete("21s.WAV");
break;
case 22:
Serial.println(22);
playcomplete("22s.WAV");
break;
case 23:
Serial.println(23);
playcomplete("23s.WAV");
break;
case 24:
Serial.println(24);
playcomplete("24s.WAV");
break;
case 25:
Serial.println(25);
playcomplete("25s.WAV");
break;
case 26:
Serial.println(26);
playcomplete("26s.WAV");
break;
case 27:
Serial.println(27);
playcomplete("27s.WAV");
break;
case 28:
Serial.println(28);
playcomplete("28s.WAV");
break;
case 29:
Serial.println(29);
playcomplete("29s.WAV");
break;
default:
break;
}
}
if (val == HIGH && potvalue >= 16 && potvalue <= 22)
{
randNum = random(30, 44);
delay(1000);
switch (randNum)
{
case 30:
Serial.println(30);
playcomplete("30m.WAV");
break;
case 31:
Serial.println(31);
playcomplete("31m.WAV");
break;
case 32:
Serial.println(32);
playcomplete("32m.WAV");
break;
case 33:
Serial.println(33);
playcomplete("33m.WAV");
break;
case 34:
Serial.println(34);
playcomplete("34m.WAV");
break;
case 35:
Serial.println(35);
playcomplete("35m.WAV");
break;
case 36:
Serial.println(36);
playcomplete("36m.WAV");
break;
case 37:
Serial.println(37);
playcomplete("37m.WAV");
break;
case 38:
Serial.println(38);
playcomplete("38m.WAV");
break;
case 39:
Serial.println(39);
playcomplete("39m.WAV");
break;
case 40:
Serial.println(40);
playcomplete("40m.WAV");
break;
case 41:
Serial.println(41);
playcomplete("41m.WAV");
break;
case 42:
Serial.println(42);
playcomplete("42m.WAV");
break;
case 43:
Serial.println(43);
playcomplete("43m.WAV");
break;
case 44:
Serial.println(44);
playcomplete("44m.WAV");
break;
default:
break;
}
}
if (val == HIGH && potvalue >= 23 && potvalue <= 1023)
{
randNum = random(45, 60);
delay(1000);
switch (randNum)
{
case 45:
Serial.println(45);
playcomplete("45.WAV");
break;
case 46:
Serial.println(46);
playcomplete("46e.WAV");
break;
case 47:
Serial.println(47);
playcomplete("47e.WAV");
break;
case 48:
Serial.println(48);
playcomplete("48e.WAV");
break;
case 49:
Serial.println(49);
playcomplete("49e.WAV");
break;
case 50:
Serial.println(50);
playcomplete("50e.WAV");
break;
case 51:
Serial.println(51);
playcomplete("51e.WAV");
break;
case 52:
Serial.println(52);
playcomplete("52e.WAV");
break;
case 53:
Serial.println(53);
playcomplete("53e.WAV");
break;
case 54:
Serial.println(54);
playcomplete("54e.WAV");
break;
case 55:
Serial.println(55);
playcomplete("55e.WAV");
break;
case 56:
Serial.println(56);
playcomplete("56e.WAV");
break;
case 57:
Serial.println(57);
playcomplete("57e.WAV");
break;
case 58:
Serial.println(58);
playcomplete("58e.WAV");
break;
case 59:
Serial.println(59);
playcomplete("59e.WAV");
break;
case 60:
Serial.println(60);
playcomplete("60e.WAV");
break;
default:
break;
}
}
}
// Plays a full file from beginning to end with no pause.
void playcomplete(char *name) {
// call our helper to find and play this name
playfile(name);
while (wave.isplaying) {
digitalWrite (MOTOR, HIGH);
flash (20, delayPeriod);
digitalWrite (MOTOR, LOW);
// do nothing while its playing
}
// now its done playing
}
void flash (int numFlashes, int d)
{
for (int i = 0; i < numFlashes; i ++)
{
digitalWrite (ledstrobePin, HIGH);
digitalWrite (leduvPin, LOW);
delay (d);
digitalWrite (ledstrobePin, LOW);
digitalWrite (leduvPin, HIGH);
delay (d);
digitalWrite (ledstrobePin, LOW);
digitalWrite (leduvPin, LOW);
}
}
void playfile(char *name) {
// see if the wave object is currently doing something
if (wave.isplaying) {
flash (20, delayPeriod);// already playing something, so stop it!
wave.stop(); // stop it
}
// look in the root directory and open the file
if (!f.open(root, name)) {
putstring("Couldn't open file "); Serial.print(name); return;
}
// OK read the file and turn it into a wave object
if (!wave.create(f)) {
putstring_nl("Not a valid WAV"); return;
}
// ok time to play! start playback
wave.play();
}
Step 9:
Once the sketch is loaded, the audio from the wave shield should go directly to the audio "in" input, inside the skull. The plug for audio from the amplifier should go to the audio “out” input inside the skull. You will want the volume on the wave shield turned all the way up, but you can adjust the amplifier to the volume that best suits you. I made some adjustments to the skull kit just for visual purposes. The kit comes with LEDs, which light up with the sound for the eyes. I didn't think it had enough contrast, so I cut out some insulating foam to fit the eye sockets. I then glued some black paper to the exposed area of the foam & installed the LEDs into the foam.
Step 10:
I decided that I wanted to make this project look as professional as possible. I felt that the back needed to be covered, but I also wanted to have easy access without having to move it too much to get into it. The chances are pretty good that it will be sitting against a wall somewhere, so a hinged door would require too much space to open. I decided to cut plywood to fit the back & use gravity to keep the covers on. I ripped a piece of wood on the table saw at an angle, and then cut segments of it for my gravity brackets. If you use this technique, use a strong enough wood type where you can drill a hole & put a screw into it without splitting. Be sure to cut large enough segments so that there is plenty of room to drill for a screw, without compromising the strength of the brackets. Measure carefully so that the brackets on both the panel & cabinet line up. Then, drill pilot holes. I only used one screw so that the brackets would be self aligning. Put the screw in tight enough so that the bracket doesn't move around when covering & removing the panel, but will move slightly to align with the angle on it's mate.
The final picture is the back view with the panels installed.
The final picture is the back view with the panels installed.
Step 11: Finishing
I wanted my fortune teller to have an old look. Since I'd chosen to re-use some pre-painted doors I already had, I decided rather than to strip & refinish the whole project, I'd just use that to my advantage by using milk paint on them.
Milk paint dries differently than other paints. It shrinks as it dries, so if it's painted over another painted surface, it'll crack & bunch up in some areas, yet adhere well in others. This gives a look similar to something that has been painted & repainted over a long period of time. It's easy to use, has no fumes, is durable, and lasts a long time. Once the paint was dry, I applied a liquid beeswax protectant to protect the paint from dirt.
Milk paint dries differently than other paints. It shrinks as it dries, so if it's painted over another painted surface, it'll crack & bunch up in some areas, yet adhere well in others. This gives a look similar to something that has been painted & repainted over a long period of time. It's easy to use, has no fumes, is durable, and lasts a long time. Once the paint was dry, I applied a liquid beeswax protectant to protect the paint from dirt.