/***************************************************************************** ** COPYRIGHT (C) 2013, ADVANCER TECHNOLOGIES, ALL RIGHTS RESERVED. *****************************************************************************/ //*********************************************** // Muscle Controlled Iron Man Repulsor // // Developed by Brian E. Kaminski - Advancer Technologies, // www.AdvancerTechnologies.com // // Uses code from Lilypad MP3 Player "Trigger" example from // SparkFun Electronics (indicated below). // Uses the SdFat library by William Greiman, which is supplied // with this archive, or download from http://code.google.com/p/sdfatlib/ // Uses the SFEMP3Shield library by Bill Porter, which is supplied // with this archive, or download from http://www.billporter.info/ // License: CC BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0/ // Revision history: // 1.0 initial release BEK 26November2014 //*********************************************** //*************************************************************************** // Example code from Trigger.ino a sketch for Lilypad MP3 Player //*************************************************************************** // We'll need a few libraries to access all this hardware: #include // To talk to the SD card and MP3 chip #include // SD card file system #include // MP3 decoder chip // Constants for the trigger input pins, which we'll place // in an array for convenience: const int TRIG1 = A0; const int TRIG2 = A4; const int TRIG3 = A5; const int TRIG4 = 1; const int TRIG5 = 0; int trigger[5] = {TRIG1,TRIG2,TRIG3,TRIG4,TRIG5}; // And a few outputs we'll be using: const int ROT_LEDR = 10; // Red LED in rotary encoder (optional) const int EN_GPIO1 = A2; // Amp enable + MIDI/MP3 mode select const int SD_CS = 9; // Chip Select for SD card // Create library objects: SFEMP3Shield MP3player; SdFat sd; boolean interrupt = true; // set triggered file to be able to be interrupted. boolean interruptself = true; // set triggered file to interrupt itself. // We'll store the five filenames as arrays of characters. // "Short" (8.3) filenames are used, followed by a null character. char filename[9][13]; //*************************************************************************** //0 PWRDOWN / Muscle Sensor Trigger //1 Trigger 2 //2 Trigger 3 //3 Trigger 4 //4 Trigger 5 //5 IMPORT //6 ONLINE //7 PWRUP //8 FIRE // We need to setup a muscle sensor reading value which will be used to tell // at what level of muscle flexion we want the repulsor to be triggered. // Adjust higher to make less sensative, adjust lower to make more sensitive int iThreshold = 100; // Value to trigger repulsor power up const int RepulsorLEDPin = 5; // pin connected to the Glove bool bPreviousState = false; bool firstLoop = true; long POWERUP_SFX_LENGTH = 1080; //ms long POWERDWN_SFX_LENGTH = 1250; //ms long LED_MAX = 255; void setup() { //*************************************************************************** // Example code from Trigger.ino a sketch for Lilypad MP3 Player //*************************************************************************** int x, index; SdFile file; byte result; char tempfilename[13]; // Setup the five trigger pins for (x = 0; x <= 4; x++) { pinMode(trigger[x],INPUT); if(x > 0) digitalWrite(trigger[x],HIGH); } //*************************************************************************** // Setup the repulsor LED PWM pin pinMode(RepulsorLEDPin, OUTPUT); // SetupMP3Player(); delay(20); } void loop() { if(firstLoop) { // First time through we want the JARVIS SFXs to play // Play the JARVIS "Importing Preferences" SFX MP3player.playMP3(filename[5]); while (MP3player.isPlaying()) { //do nothing but wait! } delay(1000); //Play the JARVIS "Online and Ready" SFX MP3player.playMP3(filename[6]); while (MP3player.isPlaying()) { //do nothing but wait! } firstLoop = false; } // Read the muscle sensor value boolean bState = ReadMuscleSensor(TRIG1); // If the muscle sensor value is over the threshold (bState = true) // and the previous state was below the threshold, then play the // power up SFX. If the muscle sensor goes back below the threshold, // then play the fire SFX and turn the repulsor on while the SFX is // playing and the power down SFX afterwards. if(bState && !bPreviousState) { //digitalWrite(RepulsorLEDPin, HIGH); // Turn the repulsor on when flexing powerUp(); // Play the Repulsor Power Up SFX } else if(!bState && bPreviousState) { //digitalWrite(RepulsorLEDPin, LOW); // Turn the repulsor off when relaxed fire(); // Play the Repulsor Firing and Power Down SFXs } // Store state for next loop bPreviousState = bState; // Check to see ReadMP3PlayerTriggers(); delay(50); } //---------------------------------------------------------------------------- // /// powerUp /// /// @desc Plays the repulsor power up sound effect while reading the muscle sensor. /// The sound effect will be interupted if the muscle sensor signal drops below /// the threshold. This allows for rapid firing of the repulsor. /// //---------------------------------------------------------------------------- void powerUp() { MP3player.playMP3(filename[7]); // setup fade in variables int fadeValue = 0; long currTime = millis(); long prevTime = currTime; double brightnessLevel = 0.2; // 25% brightness -- Change this to increase or lower brightness for power-up phase long timeDivision = POWERUP_SFX_LENGTH/long(LED_MAX*brightnessLevel); // clip length in milliseconds divided by the desired LED value (25% brightness) while (MP3player.isPlaying()) { // fade in from min to max over length of clip: currTime = millis(); if(currTime-prevTime >= timeDivision) { fadeValue +=1; // update glove LEDs if(fadeValue<=long(LED_MAX*brightnessLevel)) analogWrite(RepulsorLEDPin, fadeValue); prevTime = currTime; } if(interrupt) { boolean bState = ReadMuscleSensor(TRIG1); if(!bState) MP3player.stopTrack(); ReadMP3PlayerTriggers(); } } } //---------------------------------------------------------------------------- // /// fire /// /// @desc Plays the repulsor firing sound effect while reading the muscle sensor. /// The sound effect will be interupted if the muscle sensor signal goes above /// the threshold (meaning another fire sequence is being initiated. If the firing /// sound effect is not interupted, the repulsor power down sound effect is played. /// The power down sound effect can also be interupted. This allows for rapid firing /// of the repulsor. /// //---------------------------------------------------------------------------- void fire() { double brightnessLevel = 1.0; int fadeValue = LED_MAX*brightnessLevel; // full brightness boolean bState = false; // turn on the glove LEDs analogWrite(RepulsorLEDPin, fadeValue); MP3player.playMP3(filename[8]); while (MP3player.isPlaying()) { if(interrupt) { bState = ReadMuscleSensor(TRIG1); if(bState) MP3player.stopTrack(); ReadMP3PlayerTriggers(); } } // turn LED brightness down by 50% after firing brightnessLevel = 0.5; fadeValue *= brightnessLevel; analogWrite(RepulsorLEDPin, fadeValue); // update glove LEDs brightness if(!bState) { // now power down MP3player.playMP3(filename[0]); //setup fade out variables long currTime = millis(); long prevTime = currTime; brightnessLevel = 0.0; long timeDivision = POWERDWN_SFX_LENGTH/long(fadeValue*(1-brightnessLevel)); // clip length in milliseconds divided by the desired LED brightness value while (MP3player.isPlaying()) { // fade out from max to min over length of clip: currTime = millis(); if(currTime-prevTime >= timeDivision) { fadeValue -=1; // update glove LEDs if(fadeValue>long(fadeValue*brightnessLevel)) analogWrite(RepulsorLEDPin, fadeValue); prevTime = currTime; } if(interrupt) { bState = ReadMuscleSensor(TRIG1); if(bState) MP3player.stopTrack(); ReadMP3PlayerTriggers(); } } } analogWrite(RepulsorLEDPin, 0); // turn off the glove LEDs } //----------------------------------------------------------------------------------------------------------------------------------- // /// ReadMuscleSensor /// /// @desc This method reads each game button's state. If a button is pressed, it will change the button's /// state to true. If not, it will change the button's state to false. /// /// @param iMuscleSensorPin // Analog pin reading muscle sensor output /// /// @return true if the muscle sensor value is greater than the threshold //----------------------------------------------------------------------------------------------------------------------------------- bool ReadMuscleSensor(int iMuscleSensorPin) { int val = analogRead(iMuscleSensorPin); if(val >= iThreshold) return true; else return false; } //*************************************************************************** // Example code from Trigger.ino a sketch for Lilypad MP3 Player //*************************************************************************** void SetupMP3Player() { byte result; // The board uses a single I/O pin to select the // mode the MP3 chip will start up in (MP3 or MIDI), // and to enable/disable the amplifier chip: pinMode(EN_GPIO1,OUTPUT); digitalWrite(EN_GPIO1,LOW); // MP3 mode / amp off result = sd.begin(SD_CS, SPI_HALF_SPEED); // 1 for success if (result != 1) // Problem initializing the SD card errorBlink(1); // Halt forever, blink LED if present. // Start up the MP3 library result = MP3player.begin(); // 0 or 6 for success // Check the result, see the library readme for error codes. if ((result != 0) && (result != 6)) // Problem starting up errorBlink(result); // Halt forever, blink red LED if present. FindAudioFilenames(); // Set the VS1053 volume. 0 is loudest, 255 is lowest (off): MP3player.setVolume(10,10); // Turn on the amplifier chip: digitalWrite(EN_GPIO1,HIGH); } void FindAudioFilenames() { SdFile file; char tempfilename[13]; int index; // Now we'll access the SD card to look for any (audio) files // starting with the characters '1' to '5': // Start at the first file in root and step through all of them: sd.chdir("/",true); while (file.openNext(sd.vwd(),O_READ)) { // get filename file.getFilename(tempfilename); // Does the filename start with char '1' through '10'? if (tempfilename[0] >= '1' && tempfilename[0] <= '10') { // Yes! subtract char '1' to get an index of 0 through 4. index = tempfilename[0] - '1'; // Copy the data to our filename array. strcpy(filename[index],tempfilename); } file.close(); } } void ReadMP3PlayerTriggers() { int t; // current trigger static int last_t; // previous (playing) trigger int x; byte result; // Step through the trigger inputs, looking for LOW signals. // The internal pullup resistors will keep them HIGH when // there is no connection to the input. Only check triggers 2-5. for(t = 2; t <= 5; t++) { // The trigger pins are stored in the inputs[] array. // Read the pin and check if it is LOW (triggered). if (digitalRead(trigger[t-1]) == LOW) { // Wait for trigger to return high for a solid 50ms // (necessary to avoid switch bounce on T2 and T3 // since we need those free for I2C control of the // amplifier) x = 0; while(x < 50) { if (digitalRead(trigger[t-1]) == HIGH) {x++;} else {x = 0;} delay(1); } // If a file is already playing, and we've chosen to // allow playback to be interrupted by a new trigger, // stop the playback before playing the new file. if (interrupt && MP3player.isPlaying() && ((t != last_t) || interruptself)) { MP3player.stopTrack(); } // Play the filename associated with the trigger number. // (If a file is already playing, this command will fail // with error #2). result = MP3player.playMP3(filename[t-1]); if (result == 0) last_t = t; // Save playing trigger } } } void errorBlink(int blinks) { // The following function will blink the repulsor a given number // of times and repeat forever. This is so you can see any startup // error codes without having to use the serial monitor window. int x; while(true) // Loop forever { for (x=0; x < blinks; x++) // Blink the given number of times { digitalWrite(RepulsorLEDPin,LOW); // Turn LED ON delay(250); digitalWrite(RepulsorLEDPin,HIGH); // Turn LED OFF delay(250); } delay(1500); // Longer pause between blink-groups } } //***************************************************************************