Introduction: Talking Pumpkin Costume
Thank you for viewing my Instructable!
Today you will learn how I made a "Pumpkin Halloween Costume" It may seem like a tough task but if you are patient you to can achieve this build. How ever if you think this project is not for you than maybe some of the aspects you learn will help you create your own project. Either way please feel free to leave a comment of ask questions you may have. If you build this or it inspires your build please post the link or project in the comments section and don't forget to mention me in your project. Thank you and enjoy!
Today you will learn how I made a "Pumpkin Halloween Costume" It may seem like a tough task but if you are patient you to can achieve this build. How ever if you think this project is not for you than maybe some of the aspects you learn will help you create your own project. Either way please feel free to leave a comment of ask questions you may have. If you build this or it inspires your build please post the link or project in the comments section and don't forget to mention me in your project. Thank you and enjoy!
Step 1: Parts and Tools
The parts you will need are;
The Tools you will need are;
- An Arduino
- A wave shield from Adafruit
- 2 Blue mini 8x8 matrix from Adafruit
- 3 Red mini 8x8 matris from Adafruit
- an SD card
- Pref board
- Header pins breakaway get it here
- 5 small momentary buttons ( I sourced mine from my parts bin ) spark fun sells these
- Small on off switch ( found in my parts bin ) or you can get it from here
- Hook up wire ( Parts Bin ) I used old computer hard drive cables
- Styrofoam Pumpkin ( I used Black )
- Stand offs
- Small amplified mp3 speaker
- T-Shirt ( I used orange )
- Velcro with a sticky back
- Some one (if not you) with a sewing machine
The Tools you will need are;
- Solder iron and solder
- Styrofoam pumpkin carving knife ( or Dremel )
- High temp glue gun ( and extra glue sticks
- Spray paint ( same color of pumpkin )
Step 2: Start the Build
Start of by gathering all of the supplies and tools listed on step 1.
IMPORTANT !!! Make sure you read and understand any instructions that come with or are related to the hardware you will be using. If you have limited knowledge of electronics be sure you make and test each component separately to make sure they work as intended. Once you have each component working then you can move on to the build.
Matrix assembling:
Assemble all of the led matrix following the Adafruit instructions provided here and view the following " Adafruit LED Backpacks" read through the whole segment. It will help you solder the matrix to the controller and you will learn how they work. Be sure you follow the 8x8 mini section when soldering.
Wave shield assembling:
Assemble the wave shield following the Adafruit instructions found here. Be sure to read and understand the whole thing! It has the assembly instructions, the arduino library, the code, formatting, converting wav files, testing and more. With out all of this you will have issues!
IMPORTANT !!! Make sure you read and understand any instructions that come with or are related to the hardware you will be using. If you have limited knowledge of electronics be sure you make and test each component separately to make sure they work as intended. Once you have each component working then you can move on to the build.
Matrix assembling:
Assemble all of the led matrix following the Adafruit instructions provided here and view the following " Adafruit LED Backpacks" read through the whole segment. It will help you solder the matrix to the controller and you will learn how they work. Be sure you follow the 8x8 mini section when soldering.
Wave shield assembling:
Assemble the wave shield following the Adafruit instructions found here. Be sure to read and understand the whole thing! It has the assembly instructions, the arduino library, the code, formatting, converting wav files, testing and more. With out all of this you will have issues!
Step 3: The Code and Wav Files
The code Is from Adafruit and it's respectable parties and has been modified. I added a 4th button and sound byte. I changed the sound bytes to my own and I changed the eyes from round to triangle.
This Instructable assumes you already know how to work with arduino, ( Installing code, Library, etc )
THE CODE.
You can either copy and paste the code below in to the arduino ide or click on the file.
// Pumpkin face Costume
// This sketch has been slightly changed from the original
// creator as seen below. Enjoy!!
// 'wavface' example sketch for Adafruit I2C 8x8 LED backpacks
// and Wave Shield:
//
// www.adafruit.com/products/870 www.adafruit.com/products/1049
// www.adafruit.com/products/871 www.adafruit.com/products/1050
// www.adafruit.com/products/872 www.adafruit.com/products/1051
// www.adafruit.com/products/959 www.adafruit.com/products/1052
// www.adafruit.com/products/94
//
// Requires Adafruit_LEDBackpack, Adafruit_GFX libraries and WaveHC
// libraries.
//
// This sketch shows animation roughly synchronized to prerecorded
// speech. It's fairly complex and may be overwhelming to novice
// programmers, who may want to start with the 'matrix8x8' example
// and then 'roboface' before working through this code. Also, much
// of the comments relating to the face animation have been stripped
// here for brevity...refer to the 'roboface' sketch if you have any
// questions how that part works.
//
// Additional hardware required: sounds are triggered using three
// normally-open momentary buttons connected to Digital pins 6, 7, 8
// and GND. (e.g. www.adafruit.com/products/1009 )
//
// Adafruit invests time and resources providing this open source code,
// please support Adafruit and open-source hardware by purchasing
// products from Adafruit!
//
// Written by P. Burgess for Adafruit Industries, parts adapted from
// 'PiSpeakHC' sketch included with WaveHC library.
// BSD license, all text above must be included in any redistribution.
#include <Arduino.h>
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include <WaveHC.h>
#include <WaveUtil.h>
// These WAV files should be in the root level of the SD card:
PROGMEM char
wav0[] = "HALLOW~1.wav",
wav1[] = "LOOKIN~1.wav",
wav2[] = "THISPM~1.wav",
wav3[] = "TRKORTRT.wav", // added this line 8/3/13
*wavname[] = { wav0, wav1, wav2, wav3 }; // added wav3 to this line 8/3/13
// PROGMEM makes frequent appearances throughout this code, reason being that
// the SD card library requires gobs of precious RAM (leaving very little to
// our own sketch). PROGMEM lets us put fixed data into program flash memory,
// which is considerably more spacious. String tables are paritcularly nasty.
// See www.arduino.cc/en/Reference/PROGMEM for more info.
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 volumes root directory
FatReader file; // This object represent the WAV file for a phrase
WaveHC wave; // A single wave object -- only one sound is played at a time
// Macro to put error messages in flash memory
#define error(msg) error_P(PSTR(msg))
// Because the two eye matrices share the same address, only four
// matrix objects are needed for the five displays:
#define MATRIX_EYES 0
#define MATRIX_MOUTH_LEFT 1
#define MATRIX_MOUTH_MIDDLE 2
#define MATRIX_MOUTH_RIGHT 3
Adafruit_8x8matrix matrix[4]; // Array of Adafruit_8x8matrix objects
// Rather than assigning matrix addresses sequentially in a loop, each
// has a spot in this array. This makes it easier if you inadvertently
// install one or more matrices in the wrong physical position --
// re-order the addresses in this table and you can still refer to
// matrices by index above, no other code or wiring needs to change.
const uint8_t PROGMEM matrixAddr[] = { 0x70, 0x71, 0x72, 0x73 };
const uint8_t PROGMEM // Bitmaps are stored in program memory
blinkImg[][8] = { // Eye animation frames
{ B00000001, // Fully open eye
B00000011,
B00000111,
B00001111,
B00011111,
B00111111,
B01111111,
B11111111 },
{ B00000000,
B00000001,
B00000011,
B00000111,
B00001111,
B00011111,
B00111111,
B01111111 },
{ B00000000,
B00000000,
B00000001,
B00000011,
B00000111,
B00001111,
B00011111,
B00111111 },
{ B00000000,
B00000000,
B00000000,
B00000001,
B00000011,
B00000111,
B00001111,
B00011111 },
{ B00000000,
B00000000,
B00000000,
B00000000,
B00000001,
B00000011,
B00000111,
B00001111 },
{ B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000001,
B00000011,
B00000111 },
{ B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000001,
B00000011 },
{ B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000001 },
{ B00000000, // Fully closed eye
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000 } },
mouthImg[][24] = { // Mouth animation frames
{ B00000000, B00000000, B00000000, // Mouth position A
B00000000, B00000000, B00000000,
B01111111, B11111111, B11111110,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position B
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00000111, B00000000, B11100000,
B00000000, B11111111, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position C
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00001000, B00000000, B00010000,
B00000110, B00000000, B01100000,
B00000001, B11000011, B10000000,
B00000000, B00111100, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position D
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00100000, B00000000, B00000100,
B00010000, B00000000, B00001000,
B00001100, B00000000, B00110000,
B00000011, B10000001, B11000000,
B00000000, B01111110, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position E
B00000000, B00111100, B00000000,
B00011111, B11000011, B11111000,
B00000011, B10000001, B11000000,
B00000000, B01111110, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00111100, B00000000, // Mouth position F
B00000000, B11000011, B00000000,
B00001111, B00000000, B11110000,
B00000001, B00000000, B10000000,
B00000000, B11000011, B00000000,
B00000000, B00111100, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 } };
// Animation sequences corresponding to each WAV. First number in
// each pair is a mouth bitmap index. Second number is the hold
// time (in frames). 255 marks end of list.
// There is no 'magic' here, the software is NOT deriving mouth
// position from the sound...the tables were determined by hand,
// just as animators do it. Further explanation here:
// http://www.idleworm.com/how/anm/03t/talk1.shtml
const uint8_t PROGMEM
seq1[] = { 0, 2, 2, 5, 5, 3, 3, 7, // "Happy Halloween" // connected to wav 0 above
4, 5, 3, 4, 2, 5, 4, 3, 255 },
seq2[] = { 0, 1, 3, 5, 1, 5, 4, 2, // "Hay, What are you looking at?" // connected to wav 1 above
3, 2, 1, 2, 4, 4, 1, 3,
4, 2, 255 },
seq3[] = { 0, 1, 1, 2, 3, 6, 2, 5, // "Who has two thumbs and wants candy, This pumpkin" // connected to wav 2 above
0, 1, 4, 4, 5, 2, 1, 5,
3, 6, 1, 4, 5, 3, 4, 2,
3, 6, 4, 2, 255 },
seq4[] = { 3, 2, 2, 5, 5, 3, 3, 7, // "Trick Or Treat" // connected to wav 3 above
4, 5, 255 },
*anim[] = { seq1, seq2, seq3, seq4 }; // added seq 4 here 8/3/13
uint8_t
blinkIndex[] PROGMEM = { 1, 2, 3, 4, 3, 2, 1 }, // Blink bitmap sequence
blinkCountdown = 100, // Countdown to next blink (in frames)
gazeCountdown = 75, // Countdown to next eye movement
gazeFrames = 50, // Duration of eye movement (smaller = faster)
mouthPos = 0, // Current image number for mouth
mouthCountdown = 10, // Countdown to next mouth change
newPos = 255, // New mouth position for current frame
*seq, // Animation sequence currently being played back
idx, // Current array index within animation sequence
prevBtn = 99, // Button # pressed on last loop() iteration
btnCount = 0; // Number of iterations same button has been held
int8_t
eyeX = 3, eyeY = 3, // Current eye position
newX = 3, newY = 3, // Next eye position
dX = 0, dY = 0; // Distance from prior to new position
void setup() {
Serial.begin(9600);
PgmPrintln("WAV face");
if(!card.init()) error("Card init. failed!");
if(!vol.init(card)) error("No partition!");
if(!root.openRoot(vol)) error("Couldn't open dir");
PgmPrintln("Files found:");
root.ls();
// Seed random number generator from an unused analog input:
randomSeed(analogRead(A0));
// Instantiate and initialize each matrix object:
for(uint8_t i=0; i<4; i++) {
matrix[i] = Adafruit_8x8matrix();
matrix[i].begin(pgm_read_byte(&matrixAddr[i]));
}
// Enable pull-up resistors on four (changed to four) button inputs.
// Other end of each button then connects to GND.
for(uint8_t i=6; i<=9; i++) { //i<= 8 changed to 9 8/3/13
pinMode(i, INPUT);
digitalWrite(i, HIGH); // Enable pullup
}
}
void loop() {
uint8_t i;
// Draw eyeball in current state of blinkyness (no pupil).
matrix[MATRIX_EYES].clear();
matrix[MATRIX_EYES].drawBitmap(0, 0,
blinkImg[
(blinkCountdown < sizeof(blinkIndex)) ? // Currently blinking?
pgm_read_byte(&blinkIndex[blinkCountdown]) : // Yes, look up bitmap #
0 // No, show bitmap 0
], 8, 8, LED_ON);
// Decrement blink counter. At end, set random time for next blink.
if(--blinkCountdown == 0) blinkCountdown = random(5, 180);
if(--gazeCountdown <= gazeFrames) {
// Eyes are in motion - draw pupil at interim position
matrix[MATRIX_EYES].fillRect(
newX - (dX * gazeCountdown / gazeFrames),
newY - (dY * gazeCountdown / gazeFrames),
2, 2, LED_OFF);
if(gazeCountdown == 0) { // Last frame?
eyeX = newX; eyeY = newY; // Yes. What's new is old, then...
do { // Pick random positions until one is within the eye circle
newX = random(7); newY = random(7);
dX = newX - 3; dY = newY - 3;
} while((dX * dX + dY * dY) >= 10); // Thank you Pythagoras
dX = newX - eyeX; // Horizontal distance to move
dY = newY - eyeY; // Vertical distance to move
gazeFrames = random(3, 15); // Duration of eye movement
gazeCountdown = random(gazeFrames, 120); // Count to end of next movement
}
} else {
// Not in motion yet -- draw pupil at current static position
matrix[MATRIX_EYES].fillRect(eyeX, eyeY, 2, 2, LED_OFF);
}
// Scan buttons 6, 7, 8, 9 looking for first button pressed... added #9 8/3/13
for(i=0; (i<4) && (digitalRead(i+6) == HIGH); i++); // (i<3 changed to 4 8/3/13
if(i < 4) { // Anything pressed? Yes! // (i < 3 changed to 4 8/3/13
if(i == prevBtn) { // Same as last time we checked? Good!
if(++btnCount == 4) { // 3 passes to 'debounce' button input // == changed from 3 to 4
playfile((char *)pgm_read_word(&wavname[i])); // Start WAV
// Look up animation sequence # corresponding to this WAV...
seq = (uint8_t *)pgm_read_word(&anim[i]);
idx = 0; // Begin at first byte of data
newPos = pgm_read_byte(&seq[idx++]); // Initial mouth pos
mouthCountdown = pgm_read_byte(&seq[idx++]); // Hold time for pos
}
} else btnCount = 0; // Different button than before - start count over
prevBtn = i;
} else prevBtn = 99; // No buttons pressed
if(newPos != 255) { // Is the mouth in motion?
if(--mouthCountdown == 0) { // Count down frames to next position
newPos = pgm_read_byte(&seq[idx++]); // New mouth position
if(newPos == 255) { // End of list?
mouthPos = 0; // Yes, set mouth to neutral position
} else {
mouthPos = newPos; // Set mouth to new position
mouthCountdown = pgm_read_byte(&seq[idx++]); // Read hold time
}
}
} else mouthPos = 0; // Mouth not in motion -- set to neutral position
drawMouth(mouthImg[mouthPos]);
// Refresh all matrices in one quick pass
for(uint8_t i=0; i<4; i++) matrix[i].writeDisplay();
delay(20);
}
// Draw mouth image across three adjacent displays
void drawMouth(const uint8_t *img) {
for(uint8_t i=0; i<3; i++) {
matrix[MATRIX_MOUTH_LEFT + i].clear();
matrix[MATRIX_MOUTH_LEFT + i].drawBitmap(i * -8, 0, img, 24, 8, LED_ON);
}
}
void error_P(const char *str) {
PgmPrint("Error: ");
SerialPrint_P(str);
sdErrorCheck();
while(1);
}
// print error message and halt if SD I/O error
void sdErrorCheck(void) {
if (!card.errorCode()) return;
PgmPrint("\r\nSD I/O error: ");
Serial.print(card.errorCode(), HEX);
PgmPrint(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
// Open and start playing a WAV file
void playfile(const char *name) {
char filename[13]; // 8.3+NUL
if(wave.isplaying) wave.stop(); // Stop any currently-playing WAV
strcpy_P(filename, name); // Copy name out of PROGMEM into RAM
if(!file.open(root, filename)) {
PgmPrint("Couldn't open file ");
Serial.print(filename);
return;
}
if(!wave.create(file)) {
PgmPrintln("Not a valid WAV");
return;
}
wave.play();
}
This Instructable assumes you already know how to work with arduino, ( Installing code, Library, etc )
THE CODE.
You can either copy and paste the code below in to the arduino ide or click on the file.
// Pumpkin face Costume
// This sketch has been slightly changed from the original
// creator as seen below. Enjoy!!
// 'wavface' example sketch for Adafruit I2C 8x8 LED backpacks
// and Wave Shield:
//
// www.adafruit.com/products/870 www.adafruit.com/products/1049
// www.adafruit.com/products/871 www.adafruit.com/products/1050
// www.adafruit.com/products/872 www.adafruit.com/products/1051
// www.adafruit.com/products/959 www.adafruit.com/products/1052
// www.adafruit.com/products/94
//
// Requires Adafruit_LEDBackpack, Adafruit_GFX libraries and WaveHC
// libraries.
//
// This sketch shows animation roughly synchronized to prerecorded
// speech. It's fairly complex and may be overwhelming to novice
// programmers, who may want to start with the 'matrix8x8' example
// and then 'roboface' before working through this code. Also, much
// of the comments relating to the face animation have been stripped
// here for brevity...refer to the 'roboface' sketch if you have any
// questions how that part works.
//
// Additional hardware required: sounds are triggered using three
// normally-open momentary buttons connected to Digital pins 6, 7, 8
// and GND. (e.g. www.adafruit.com/products/1009 )
//
// Adafruit invests time and resources providing this open source code,
// please support Adafruit and open-source hardware by purchasing
// products from Adafruit!
//
// Written by P. Burgess for Adafruit Industries, parts adapted from
// 'PiSpeakHC' sketch included with WaveHC library.
// BSD license, all text above must be included in any redistribution.
#include <Arduino.h>
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include <WaveHC.h>
#include <WaveUtil.h>
// These WAV files should be in the root level of the SD card:
PROGMEM char
wav0[] = "HALLOW~1.wav",
wav1[] = "LOOKIN~1.wav",
wav2[] = "THISPM~1.wav",
wav3[] = "TRKORTRT.wav", // added this line 8/3/13
*wavname[] = { wav0, wav1, wav2, wav3 }; // added wav3 to this line 8/3/13
// PROGMEM makes frequent appearances throughout this code, reason being that
// the SD card library requires gobs of precious RAM (leaving very little to
// our own sketch). PROGMEM lets us put fixed data into program flash memory,
// which is considerably more spacious. String tables are paritcularly nasty.
// See www.arduino.cc/en/Reference/PROGMEM for more info.
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 volumes root directory
FatReader file; // This object represent the WAV file for a phrase
WaveHC wave; // A single wave object -- only one sound is played at a time
// Macro to put error messages in flash memory
#define error(msg) error_P(PSTR(msg))
// Because the two eye matrices share the same address, only four
// matrix objects are needed for the five displays:
#define MATRIX_EYES 0
#define MATRIX_MOUTH_LEFT 1
#define MATRIX_MOUTH_MIDDLE 2
#define MATRIX_MOUTH_RIGHT 3
Adafruit_8x8matrix matrix[4]; // Array of Adafruit_8x8matrix objects
// Rather than assigning matrix addresses sequentially in a loop, each
// has a spot in this array. This makes it easier if you inadvertently
// install one or more matrices in the wrong physical position --
// re-order the addresses in this table and you can still refer to
// matrices by index above, no other code or wiring needs to change.
const uint8_t PROGMEM matrixAddr[] = { 0x70, 0x71, 0x72, 0x73 };
const uint8_t PROGMEM // Bitmaps are stored in program memory
blinkImg[][8] = { // Eye animation frames
{ B00000001, // Fully open eye
B00000011,
B00000111,
B00001111,
B00011111,
B00111111,
B01111111,
B11111111 },
{ B00000000,
B00000001,
B00000011,
B00000111,
B00001111,
B00011111,
B00111111,
B01111111 },
{ B00000000,
B00000000,
B00000001,
B00000011,
B00000111,
B00001111,
B00011111,
B00111111 },
{ B00000000,
B00000000,
B00000000,
B00000001,
B00000011,
B00000111,
B00001111,
B00011111 },
{ B00000000,
B00000000,
B00000000,
B00000000,
B00000001,
B00000011,
B00000111,
B00001111 },
{ B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000001,
B00000011,
B00000111 },
{ B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000001,
B00000011 },
{ B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000001 },
{ B00000000, // Fully closed eye
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000 } },
mouthImg[][24] = { // Mouth animation frames
{ B00000000, B00000000, B00000000, // Mouth position A
B00000000, B00000000, B00000000,
B01111111, B11111111, B11111110,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position B
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00000111, B00000000, B11100000,
B00000000, B11111111, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position C
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00001000, B00000000, B00010000,
B00000110, B00000000, B01100000,
B00000001, B11000011, B10000000,
B00000000, B00111100, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position D
B00000000, B00000000, B00000000,
B00111111, B11111111, B11111100,
B00100000, B00000000, B00000100,
B00010000, B00000000, B00001000,
B00001100, B00000000, B00110000,
B00000011, B10000001, B11000000,
B00000000, B01111110, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position E
B00000000, B00111100, B00000000,
B00011111, B11000011, B11111000,
B00000011, B10000001, B11000000,
B00000000, B01111110, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00111100, B00000000, // Mouth position F
B00000000, B11000011, B00000000,
B00001111, B00000000, B11110000,
B00000001, B00000000, B10000000,
B00000000, B11000011, B00000000,
B00000000, B00111100, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 } };
// Animation sequences corresponding to each WAV. First number in
// each pair is a mouth bitmap index. Second number is the hold
// time (in frames). 255 marks end of list.
// There is no 'magic' here, the software is NOT deriving mouth
// position from the sound...the tables were determined by hand,
// just as animators do it. Further explanation here:
// http://www.idleworm.com/how/anm/03t/talk1.shtml
const uint8_t PROGMEM
seq1[] = { 0, 2, 2, 5, 5, 3, 3, 7, // "Happy Halloween" // connected to wav 0 above
4, 5, 3, 4, 2, 5, 4, 3, 255 },
seq2[] = { 0, 1, 3, 5, 1, 5, 4, 2, // "Hay, What are you looking at?" // connected to wav 1 above
3, 2, 1, 2, 4, 4, 1, 3,
4, 2, 255 },
seq3[] = { 0, 1, 1, 2, 3, 6, 2, 5, // "Who has two thumbs and wants candy, This pumpkin" // connected to wav 2 above
0, 1, 4, 4, 5, 2, 1, 5,
3, 6, 1, 4, 5, 3, 4, 2,
3, 6, 4, 2, 255 },
seq4[] = { 3, 2, 2, 5, 5, 3, 3, 7, // "Trick Or Treat" // connected to wav 3 above
4, 5, 255 },
*anim[] = { seq1, seq2, seq3, seq4 }; // added seq 4 here 8/3/13
uint8_t
blinkIndex[] PROGMEM = { 1, 2, 3, 4, 3, 2, 1 }, // Blink bitmap sequence
blinkCountdown = 100, // Countdown to next blink (in frames)
gazeCountdown = 75, // Countdown to next eye movement
gazeFrames = 50, // Duration of eye movement (smaller = faster)
mouthPos = 0, // Current image number for mouth
mouthCountdown = 10, // Countdown to next mouth change
newPos = 255, // New mouth position for current frame
*seq, // Animation sequence currently being played back
idx, // Current array index within animation sequence
prevBtn = 99, // Button # pressed on last loop() iteration
btnCount = 0; // Number of iterations same button has been held
int8_t
eyeX = 3, eyeY = 3, // Current eye position
newX = 3, newY = 3, // Next eye position
dX = 0, dY = 0; // Distance from prior to new position
void setup() {
Serial.begin(9600);
PgmPrintln("WAV face");
if(!card.init()) error("Card init. failed!");
if(!vol.init(card)) error("No partition!");
if(!root.openRoot(vol)) error("Couldn't open dir");
PgmPrintln("Files found:");
root.ls();
// Seed random number generator from an unused analog input:
randomSeed(analogRead(A0));
// Instantiate and initialize each matrix object:
for(uint8_t i=0; i<4; i++) {
matrix[i] = Adafruit_8x8matrix();
matrix[i].begin(pgm_read_byte(&matrixAddr[i]));
}
// Enable pull-up resistors on four (changed to four) button inputs.
// Other end of each button then connects to GND.
for(uint8_t i=6; i<=9; i++) { //i<= 8 changed to 9 8/3/13
pinMode(i, INPUT);
digitalWrite(i, HIGH); // Enable pullup
}
}
void loop() {
uint8_t i;
// Draw eyeball in current state of blinkyness (no pupil).
matrix[MATRIX_EYES].clear();
matrix[MATRIX_EYES].drawBitmap(0, 0,
blinkImg[
(blinkCountdown < sizeof(blinkIndex)) ? // Currently blinking?
pgm_read_byte(&blinkIndex[blinkCountdown]) : // Yes, look up bitmap #
0 // No, show bitmap 0
], 8, 8, LED_ON);
// Decrement blink counter. At end, set random time for next blink.
if(--blinkCountdown == 0) blinkCountdown = random(5, 180);
if(--gazeCountdown <= gazeFrames) {
// Eyes are in motion - draw pupil at interim position
matrix[MATRIX_EYES].fillRect(
newX - (dX * gazeCountdown / gazeFrames),
newY - (dY * gazeCountdown / gazeFrames),
2, 2, LED_OFF);
if(gazeCountdown == 0) { // Last frame?
eyeX = newX; eyeY = newY; // Yes. What's new is old, then...
do { // Pick random positions until one is within the eye circle
newX = random(7); newY = random(7);
dX = newX - 3; dY = newY - 3;
} while((dX * dX + dY * dY) >= 10); // Thank you Pythagoras
dX = newX - eyeX; // Horizontal distance to move
dY = newY - eyeY; // Vertical distance to move
gazeFrames = random(3, 15); // Duration of eye movement
gazeCountdown = random(gazeFrames, 120); // Count to end of next movement
}
} else {
// Not in motion yet -- draw pupil at current static position
matrix[MATRIX_EYES].fillRect(eyeX, eyeY, 2, 2, LED_OFF);
}
// Scan buttons 6, 7, 8, 9 looking for first button pressed... added #9 8/3/13
for(i=0; (i<4) && (digitalRead(i+6) == HIGH); i++); // (i<3 changed to 4 8/3/13
if(i < 4) { // Anything pressed? Yes! // (i < 3 changed to 4 8/3/13
if(i == prevBtn) { // Same as last time we checked? Good!
if(++btnCount == 4) { // 3 passes to 'debounce' button input // == changed from 3 to 4
playfile((char *)pgm_read_word(&wavname[i])); // Start WAV
// Look up animation sequence # corresponding to this WAV...
seq = (uint8_t *)pgm_read_word(&anim[i]);
idx = 0; // Begin at first byte of data
newPos = pgm_read_byte(&seq[idx++]); // Initial mouth pos
mouthCountdown = pgm_read_byte(&seq[idx++]); // Hold time for pos
}
} else btnCount = 0; // Different button than before - start count over
prevBtn = i;
} else prevBtn = 99; // No buttons pressed
if(newPos != 255) { // Is the mouth in motion?
if(--mouthCountdown == 0) { // Count down frames to next position
newPos = pgm_read_byte(&seq[idx++]); // New mouth position
if(newPos == 255) { // End of list?
mouthPos = 0; // Yes, set mouth to neutral position
} else {
mouthPos = newPos; // Set mouth to new position
mouthCountdown = pgm_read_byte(&seq[idx++]); // Read hold time
}
}
} else mouthPos = 0; // Mouth not in motion -- set to neutral position
drawMouth(mouthImg[mouthPos]);
// Refresh all matrices in one quick pass
for(uint8_t i=0; i<4; i++) matrix[i].writeDisplay();
delay(20);
}
// Draw mouth image across three adjacent displays
void drawMouth(const uint8_t *img) {
for(uint8_t i=0; i<3; i++) {
matrix[MATRIX_MOUTH_LEFT + i].clear();
matrix[MATRIX_MOUTH_LEFT + i].drawBitmap(i * -8, 0, img, 24, 8, LED_ON);
}
}
void error_P(const char *str) {
PgmPrint("Error: ");
SerialPrint_P(str);
sdErrorCheck();
while(1);
}
// print error message and halt if SD I/O error
void sdErrorCheck(void) {
if (!card.errorCode()) return;
PgmPrint("\r\nSD I/O error: ");
Serial.print(card.errorCode(), HEX);
PgmPrint(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
// Open and start playing a WAV file
void playfile(const char *name) {
char filename[13]; // 8.3+NUL
if(wave.isplaying) wave.stop(); // Stop any currently-playing WAV
strcpy_P(filename, name); // Copy name out of PROGMEM into RAM
if(!file.open(root, filename)) {
PgmPrint("Couldn't open file ");
Serial.print(filename);
return;
}
if(!wave.create(file)) {
PgmPrintln("Not a valid WAV");
return;
}
wave.play();
}
Step 4: Testing!
Testing:
See pic for wiring layout for the Arduino, matrix wav sheild and buttons. Make sure to connect exactly like the pic. Mainly the power wires. Do not connect the power supply to the arduino then the matrix from the arduino output power. This will put to much strain on the arduino. Instead connect a splitter to the battery pack connect one line to the matrix group and one line to the arduino gnd and vcc line.
Once you are happy with the results move on to the next step!
See pic for wiring layout for the Arduino, matrix wav sheild and buttons. Make sure to connect exactly like the pic. Mainly the power wires. Do not connect the power supply to the arduino then the matrix from the arduino output power. This will put to much strain on the arduino. Instead connect a splitter to the battery pack connect one line to the matrix group and one line to the arduino gnd and vcc line.
Once you are happy with the results move on to the next step!
Step 5: Some Assembly Required
It's time to put it all together!
Cut the pumpkin.
Start off by cutting the pumpkin in half ( See pic ) Take some masking tape and mark the out line of the eye matrix x2 and the outline of the moth matrix. Use theses to help you layout the face. Once you are happy with the layout cut the opening out for the matrix be sure to cut the hole slightly smaller then the lines you drew. You want a tight fit.
Cut the holes for the switch and buttons ( See pic )
Once all the holes are cut, paint the lighter areas from the cuts and any nicks you might have made.
Solder the components.
Solder the mouth to the pref board MAKE SURE YOU HAVE THEM LINED UP CORRECTLY. They are addressed if you solder them in wrong it will look funny and you will make more work for yourself, Trust me!
Solder 4 wires to each eye matrix ( be sure they are a few inches longer then a close fit )
Solder both eye matrix wires to the pref board, in the same order solder each eye and all 3 mouth matrix together just as you had them laid out on the bread board.
Solder wires to the on/off switch, solder 1 long wire and 1 short wire to all of the buttons.
Add Velcro
Cut and glue small strips of Velcro along the edge of the pumpkin.(see pic) It's best to cut the Velcro with both fuzzy side and hook side together. Once glue has dried remove the plastic layer from the Velcro (exposing the sticky) Now place this on the shirt and press firmly. Carefully separate the Velcro so you have half on the pumpkin and half on the shirt. Now find someone who can use a sewing machine well and have them sew the Velcro.
Cut the pumpkin.
Start off by cutting the pumpkin in half ( See pic ) Take some masking tape and mark the out line of the eye matrix x2 and the outline of the moth matrix. Use theses to help you layout the face. Once you are happy with the layout cut the opening out for the matrix be sure to cut the hole slightly smaller then the lines you drew. You want a tight fit.
Cut the holes for the switch and buttons ( See pic )
Once all the holes are cut, paint the lighter areas from the cuts and any nicks you might have made.
Solder the components.
Solder the mouth to the pref board MAKE SURE YOU HAVE THEM LINED UP CORRECTLY. They are addressed if you solder them in wrong it will look funny and you will make more work for yourself, Trust me!
Solder 4 wires to each eye matrix ( be sure they are a few inches longer then a close fit )
Solder both eye matrix wires to the pref board, in the same order solder each eye and all 3 mouth matrix together just as you had them laid out on the bread board.
Solder wires to the on/off switch, solder 1 long wire and 1 short wire to all of the buttons.
Add Velcro
Cut and glue small strips of Velcro along the edge of the pumpkin.(see pic) It's best to cut the Velcro with both fuzzy side and hook side together. Once glue has dried remove the plastic layer from the Velcro (exposing the sticky) Now place this on the shirt and press firmly. Carefully separate the Velcro so you have half on the pumpkin and half on the shirt. Now find someone who can use a sewing machine well and have them sew the Velcro.
Step 6: Final Assembly!
It's almost done!
Lay in the eyes and mouth parts and hot glue them into place.
TIP: Sand away any over-spray inside from any paint or the glue will not stick.
Slip in the buttons and switch.
Solder 1 wire from each button and switch together then add a long wire ( this will go to gnd )
Solder the other wire from each button to the pref board to a corresponding arduino pin for the audio.
Solder a second wire from the reset button to the pref board to Corresponding arduino (rst) see picture for wiring lay out
Lay in the eyes and mouth parts and hot glue them into place.
TIP: Sand away any over-spray inside from any paint or the glue will not stick.
Slip in the buttons and switch.
Solder 1 wire from each button and switch together then add a long wire ( this will go to gnd )
Solder the other wire from each button to the pref board to a corresponding arduino pin for the audio.
Solder a second wire from the reset button to the pref board to Corresponding arduino (rst) see picture for wiring lay out