Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Onderdelen en Benodigdheden

Onderdeel Aantal
Houten kist/doos 1
Arduino UNO 1
Adafruit Wave Shield 1
SainSmart 4-kanaals Relais Module 1
Ruitensproeier motor (12V) 1
Rode LED kerstverlichting (100 stuks) 1
Rookmachine 1
Versterker/Luidspreker 1

Over dit Project

*** Geüpdatet naar Versie 4 ***

Ik heb de Arduino-code voor dit project recentelijk herschreven. Hier is een overzicht van de wijzigingen:

  • Hoofd-lus is nu geïmplementeerd als een state machine
  • Alle timing is gebaseerd op gebeurtenistijd vs. huidige tijd evaluaties
  • Timing is niet langer afhankelijk van frames
  • Verwijdering van delay() in de hoofd-lus
  • Oplossing voor het 'poort bezet' probleem bij verbinding met Arduino IDE
  • Relais gebruiken nu Normaal Open (NO) in plaats van Normaal Gesloten (NC) verbindingen *** Werk je relaisverbindingen bij! ***
  • Toegevoegde 'Beweging Gedetecteerd' LED
  • Toegevoegde 'Klaar om te Waken' LED
  • Toegevoegde 'Gepauzeerd' LED
  • Actie Trigger Schakelaar verwijderd
  • Mogelijkheid toegevoegd om extra tijd toe te voegen aan rode lichten en rook
  • Veel commentaar toegevoegd

De meest recente code vind je op GitHub.

Monster in een Doos

Ik hou van Halloween-rekwisieten en heb het afgelopen jaar enkele geweldige Monster in een Doos builds gezien en gelezen. Ik besloot er zelf eentje te bouwen. Het concept is simpel: creëer de illusie dat een container een gevaarlijk monster vasthoudt dat op het punt staat te ontvluchten. De illusie kan gemaakt worden met elke combinatie van beweging, geluid, licht, rook en natuurlijk verrassing.

Wat zit er in de Doos?!

Je wilt een doos die groot genoeg is om te lijken op iets groot en eng te kunnen bevatten. Het versterkt de illusie als de doos oud, versleten en net net zo sterk genoeg lijkt om het monster tegen te houden. Ik keek eerst in kringloopwinkels en online, maar vond niets wat me beviel, dus bouwde ik er zelf een. Dat was niet moeilijk.

Ik gebruikte 15 houten palingpalen van 1,8 meter van de bouwmarkt om een doos van ongeveer 90 x 75 x 75 cm te maken. Ik zaagde alle planken op maat met een tafelzaag en montereerde de doos met een pneumatische 18-gauge nagelpistool. Dat leek goed te werken, maar later besefte ik dat de nagels niet sterkt genoeg waren voor al de kloppende en botsende beweging. Ik versterkte de doos daarom met 2,5 cm droogmuurschroeven (van binnen naar buiten zodat ze niet zichtbaar waren).

Na de bouw verleende ik het hout een oudere uitstraling met een proces van zwarte thee, azijn en staalwol. Daarna versierde ik het met sjablonen en labels die ik online vond of zelf ontwierp en printte.

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Hersenen!!!

De rekwiets heeft twee operationele toestanden: "Slapend" en "Wakker". Terwijl het slaapt is de doos rustig en maakt het alleen snurk- en knorgeluiden. Het monster wordt gewekt wanneer een trick-or-treater een bewegingssensor activeert. Wanneer het monster wakker wordt, brult het, blaast rook, laat het deksel stuiteren en glooit de binnenkant van de doos rood.

Ik gebruikte een Arduino Uno samen met een Wave Shield en een Relais Module om het gedrag van deze rekwiets te orchestreren. De Wave Shield is geladen met een kleine collectie slaperige en brullende geluiden. Een PIR-bewegingssensor geeft input aan de Arduino om de doos te schakelen tussen "slapende" en "wakke" modi. Tijdens de wakke modus activeert de Arduino relafkaanalen om de dekselmotor, rode lichten, de rookgenerator aan te sturen en geluiden af te spelen op de Wave Shield. Een extra functie die ik toevoegde was een Pauzeknop. Hiermee kon ik het monster tijdelijk dempen wanneer jongere kinderen voorbij kwamen.

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Het Leeft!

Een dekseltiler is een apparaat dat het deksel snel omhoog en omlaag beweegt om het te laten knallen en stuiteren alsof het monster probeert te ontsnappen. Er zijn verschillende manieren om dit te doen; de meest populaire zijn pneumatische actuatoren en roterende kamen. Hoewel ik denk dat een elektronisch bestuurde pneumatische actuator meer willekeurige dekselbewegingen had toegestaan, koos ik voor een roterende kam omdat het simpeler en goedkoper leek.

Ik kocht een gebruikte ruitensproei motor van een lokale autosloperij voor $15. Dat was grappig. Ik liep binnen en vroeg om een motor. De man achter de toonbank vroeg "voor welk merk en model auto?" toen ik zei "maakt niet uit" kantelde hij zijn hoofd iets scheef en keek me schuins aan. Nadat ik uitlegde wat ik van plan was wilde hij er zelf eentje bouwen :)

Deze motoren, ongeacht merk/model, draaien op 12 volt, hebben een redelijke snelheid en een geweldig koppel: perfect! Let op: zorg dat er nog een deel van de oude kabelboom aan zit, dat maakt het veel gemakkelijker om je draden aan te sluiten. Zorg ook dat de kraagarm en de versetzte pen nog zitten. Als de hoofdas de enige fysieke verbinding is, zal je kam waarschijnlijk glijden.

Monteer de motor ergens in je doos. Ik plaatste de mijn aan een van de zijwanden. Onthoud dat er een grote roterende kam aan verbonden zal zijn en dat deze vrij moet kunnen draaien zonder hindering door andere items, vooral draden, die je in de doos plaatst. Er zijn diverse goede tutorials op YouTube over het werken met deze motoren.

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Ik zaagde een kam van 30 cm diameter uit een stuk 12 mm multiplex. Eerst zaagde ik een perfecte cirkel. Ik montereerde hem op de motor en gebruikte dit om de benodigde hoogte van de motor in de doos te bepalen. Ik wilde dat het deksel ongeveer 5 cm omhoog ging. Na deze fitting zaagde ik met een Stichzaag willekeurig 'tanden' in de kam, mijn best doend om ze willekeurige breedtes en diepten te geven.

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Ten slotte montereerde ik een rol aan de onderkant van het deksel met 2 metalen L-beschläge, een 2,5 cm nylon afstandsbus en een wapenbout. De rol is net boven de kam gepositioneerd zodat hij langs de tanden van de kam rijdt.

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Ik gebruikte de 12 volt rail van een ATX voeding om de motor via het relais te voeden dat door de Arduino wordt bestuurd. Ja, alles uitlijnen vereist wat proberen en fouten. Na het herpositioneren van de rol een of twee keer... ok, drie keer... stond alles goed en begon het deksel te stuiteren zoals gepland!

Adem van Vuur: Rook en Lichten

Ik gebruikte een goedkope 400 Watt rookgenerator voor rookeffecten. Uit de doos was dit radio bestuurd. Om het met de Arduino te besturen, opende ik de ontvanger en soldeerde twee draden aan de contactpunten van de triggerknop. Dit gaf me draden die ik aan een door de Arduino bestuurd relafkaanaal kon koppelen. Het was een simpele hack die ik leerde door een paar YouTube filmpjes te bekijken. Ik voegde ook een oude stofzuigerslang toe om de rook als een straal te laten komen vanaf net onder het deksel. Ik vind het visuele effect leuk en het helpt om condensatie op de elektronica in de doos te verminderen.

Voor de lichten knipte ik simpelweg een verlengsnoer door en bedraadde het via een relafkaanaal. De snaar van 100 rode LED-lampjes die hieraan verbonden was, kon zo door de Arduino in- en uitgeschakeld worden.

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project
Bouw Je Eigen Monster in een Doos: Arduino Robotica Project
Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Gebruik Je Buikstem

De Wave Shield heeft een 3,5 mm hoofdtelefoonuitgang en 2 I/O pinnen voor een directe verbinding. Ik gebruikte een 3,5 mm patchkabel om te verbinden met een 30 Watt basgitaarversterker die ik uit mijn oefenruimte leende. Elk aantal versterkte luidsprekers zou werken - inclusief PC-luidsprekers. Maar iets met een stevig laagbereik is zeker een plus.

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Keten Er Omheen

Ik kocht plastic ketten in een Halloweenwinkel en 3D-printte een hangslot. Het omwikkelen van deze ketten om de kist voegde diepte en gevoel aan de illusie toe.

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Halloween!!!

Zet de kist in de tuin en verstop de bewegingssensor in een nabijgelegen struik. Ik gebruikte een lange lengte luidsprekerdraad om de sensor te verbinden zodat ik kon experimenteren met de positionering, zodat het monster wakker zou worden als iemand zich naderde (ongeveer 1,5 meter) tot de kist.

Naarmate de avond donkerder werd, besefte ik dat alle details aan de buitenkant van de kist moeilijk zichtbaar werden. Uiteindelijk verlichte ik het met een stroboflitser en was erg tevreden over het effect.

Terwijl trick-or-treaters de oprit op liepen, bemerkten ze de knorrende kist: sommigen met nieuwsgierige blikken, anderen waren echt bang. Toen ze naderden en het monster tot leven ontwaakte, sprongen ze op, schreeuwden en sommigen applauderen zelfs. Het was een enorme hit.

Verbeteringen

Ik zat vol met manieren om mijn bewegingssensor in de struiken te verstoppen, dus ik lijmde er eentje in de buik van een plastic rat die ik ergens langs de oprit of onder die struik kon positioneren. Ik installeerde ook een RJ11 telefoonmodul aan de achterkant van de doos zodat ik de rat-bewegingssensor kon verbinden met een 15 meter telefoonkabel - wat veel beter is dan de twee luidsprekerdraden die ik eerder gebruikte.

Bouw Je Eigen Monster in een Doos: Arduino Robotica Project
Bouw Je Eigen Monster in een Doos: Arduino Robotica Project

Je zult zien dat ik ook een schakelaar en enkele indicator LEDs aan die nieuwe plaat toevoegde. De schakelaar PAUZEERT alle functies op de doos zonder hem uit te schakelen. Mijn hoofdstroomschakelaar is de stroomstrippinnetje binnenin en is lastig bereikbaar, plus met deze schakelaar gebruik ik alleen signaalspanning (5V) op deze externe schakelaar. Deze schakelaar is geweldig om het monster te stoppen voor jongere trick-or-treaters en anderen die om een kijkje in de doos vragen op Halloweenavond.

Oh! Ik draai plastic ketten over de doos voor effect en die kunnen onhandig zijn. Vooral als ik 's avonds in de doos moet. Om dit makkelijker te maken, bevestigde ik zwarte veerkarabijners met tyraps aan de uiteinden van de ketens. Hiermee kan ik de uiteinden snel los-/vastklikken aan oogjes die ik in de onderste hoeken van de doos draaide. Niet heel high-tech maar zeer handig.

De Toekomst

Er zijn een paar dingen die ik in de toekomst wil toevoegen. Misschien R/C-besturing zodat ik het monster op afstand kan pauzeren of activeren. Ik wil ook een soort feedback aan de dekseltiler toevoegen zodat de Arduino 'weet' wanneer het deksel open of dicht is. Verschillende keren stopte de tiler op een hoog punt in de cyclus waardoor de 'inweranden' van de doos zichtbaar bleven tot de volgende wakker-cyclus. Ten slotte wil ik misschien de externe verlichting/strobo's aan de Arduino koppelen om ze via het programma of de R/C-zender te kunnen besturen.

GitHub Repository

Je vindt de meest recente code en schema's hier op GitHub.

Code

Monster In A Box Sketch

/* Wave Shield Pins in Use: 2, 3, 4, 5, 10, 11, 12 & 13 Pins 13, 12, 11 zijn altijd gebruikt door de SD-kaart (ze zijn de enige pinnen met een high-speed SPI interface). Dan zijn er 5 andere pinnen die gebruikt worden om met de DAC en SD-kaart te communiceren, maar ze kunnen ingesteld worden om met elke Arduino-pin te verbinden. Standaard is de geconfigureerd om pinnen 10 (voor SD-kaart) en pinnen 2, 3, 4 en 5 voor de DAC te gebruiken. Het wijzigen van deze pinnen vereist aanpassing van de bibliotheek - de pinnen worden gerefereerd door hun 'hardware' pinnamen (bijv. PORTD, etc) niet door Arduino-pinnen. Dat betekent dat pinnen 6, 7, 8, 9 en de 6 analoge in pinnen (ook bekend als digitale I/O pinnen 14-20) beschikbaar zijn. https://learn.adafruit.com/adafruit-wave-shield-audio-shield-for-arduino/faq */
#include "MonsterSounds.h"
#define RESERVED_00 0 // Gereserveerd voor Serial RX
#define RESERVED_01 1 // Gereserveerd voor Serial TX
#define RESERVED_02 2 // Gereserveerd voor Wave Shield
#define RESERVED_03 3 // Gereserveerd voor Wave Shield
#define RESERVED_04 4 // Gereserveerd voor Wave Shield
#define RESERVED_05 5 // Gereserveerd voor Wave Shield
#define FOG_MACHINE 6 // Verbinden Digital Pin op Arduino met Relais Module
#define RED_LEDS 7 // Verbinden Digital Pin op Arduino met Relais Module
#define LID_BOUNCER 8 // Verbinden Digital Pin op Arduino met Relais Module
#define RESERVED_09 9 // Verbinden Digital Pin op Arduino met Relais Module
#define RESERVED_10 10 // Gereserveerd voor Wave Shield
#define RESERVED_11 11 // Gereserveerd voor Wave Shield
#define RESERVED_12 12 // Gereserveerd voor Wave Shield
#define RESERVED_13 13 // Gereserveerd voor Wave Shield
#define PIR_SENSOR A0 // PIR Input
#define MOTION_LED A1 // LED: brandt wanneer beweging gedetecteerd wordt (onafhankelijk van pauze/slaap/wakker staat)
#define PAUSED_LED A2 // LED: brandt wanneer systeem gepauzeerd is
#define READY_LED A3 // LED: brandt wanneer monster in READY_TO_WAKE staat
#define PAUSE_BUTTON A4 // Pauze Schakelaar Input
#define DEBUG_BUTTON A5 // Debug Schakelaar Input
// Effect Timer Instellingen - in Seconden (BEWERK DEZE)
#define WAKE_DELAY 30 // Minimum tijd tussen 'wakker' gebeurtenissen in Seconden
#define WAKE_DELAY_DEBUG 10 // WAKE_DELAY override wanneer DEBUG schakelaar ingedrukt is
#define SLEEP_SOUND_DELAY 1 // Aantal seconden te wachten tussen pogingen om volgende 'slaap' geluid af te spelen
#define WAKE_MIN 3 // Minimum 'wakke' tijd in Seconden
#define WAKE_MAX 5 // Maximum 'wakke' tijd in Seconden
#define RED_LIGHT_EXTRA_TIME 1 // Laat rode lichten iets langer lopen dan dekselstuiter, indien gewenst
#define SMOKE_EXTRA_TIME 2 // Laat rook iets langer lopen dan dekselstuiter, indien gewenst
// Effect Timer Instellingen - in Milliseconden (NIET BEWERKEN)
#define WAKE_DELAY_MILLIS WAKE_DELAY * 1000
#define WAKE_DELAY_DEBUG_MILLIS WAKE_DELAY_DEBUG * 1000
#define SLEEP_SOUND_DELAY_MILLIS SLEEP_SOUND_DELAY * 1000
#define WAKE_MIN_MILLIS WAKE_MIN * 1000
#define WAKE_MAX_MILLIS WAKE_MAX * 1000
#define RED_LIGHT_EXTRA_TIME_MILLIS RED_LIGHT_EXTRA_TIME * 1000
#define SMOKE_EXTRA_TIME_MILLIS SMOKE_EXTRA_TIME * 1000
MonsterSounds sounds;
static unsigned long timeSinceLastSnore= 0;
static unsigned long wakeAllowedTimer = 0;
static unsigned long lidBounceTimer = 0;
static unsigned long lidBounceDuration = 0;
static unsigned long smokeTimer = 0;
static unsigned long smokeDuration = 0;
static unsigned long redLightTimer = 0;
static unsigned long redLightDuration = 0;
enum States {
  STATE_INITIALIZE, // Alleen tijdens setup() en eerste keer in loop()
  STATE_PAUSED, // Schakel alle geluiden en effecten uit
  STATE_SLEEPING, // Geen effecten, slaapgeluiden, staat niet toe wakker te worden getriggerd
  STATE_READY_TO_WAKE, // Geen effecten, slaapgeluiden, staat toe wakker te worden getriggerd
  STATE_AWAKE}; // Activeert effecten en monster wakker geluiden
States state = STATE_INITIALIZE;
void setup() {
  // initialiseer seriële communicatie:
  Serial.begin(9600);
  // Stel alle relais pinnen in
  pinMode(LID_BOUNCER, OUTPUT);
  pinMode(RED_LEDS, OUTPUT);
  pinMode(FOG_MACHINE, OUTPUT);
  pinMode(PAUSED_LED, OUTPUT);
  pinMode(MOTION_LED, OUTPUT);
  pinMode(READY_LED, OUTPUT);
  // Dwing alle effecten UIT
  stopAllEffects();
  pinMode(PIR_SENSOR, INPUT);
  pinMode(PAUSE_BUTTON, INPUT_PULLUP);
  pinMode(DEBUG_BUTTON, INPUT_PULLUP);
  sounds.initialize(); // Monster Geluiden
  sounds.playSystemReady();
  delay(1000);
  Serial.println();
  Serial.print("*** Systeem Klaar ***");
  Serial.println();
}
/*
 * OPMERKING: Alle knoppen gebruiken pull-ups, dus LAAG betekent dat de knop INGEDRUKT is
 * Houd er rekening mee dat de pull-up betekent dat schakelaar logica geïnverteerd is.
 * Het gaat HOOG als het open is, en LAAG als het ingedrukt is.
 *
 * De PIR bewegingssensor gedraagt zich NIET op deze manier.
 */
/*
 * Hoofd verwerkingslus
 * - Beheert de Monster's State Machine
 */
void loop() {
  boolean pauseSwitchClosed = digitalRead(PAUSE_BUTTON) == LOW;
  boolean motionDetected = digitalRead(PIR_SENSOR) == HIGH;
  digitalWrite(MOTION_LED, digitalRead(PIR_SENSOR));
  switch (state) {
    case STATE_INITIALIZE:
      if (pauseSwitchClosed) {
        goToPause();
      } else {
        goToSleep();
      }
      break;
    case STATE_PAUSED:
      if (!pauseSwitchClosed) {
        goToSleep();
        digitalWrite(PAUSED_LED, LOW);
      } else {
        digitalWrite(PAUSED_LED, HIGH);
      }
      break;
    case STATE_SLEEPING:
      if (pauseSwitchClosed) {
        goToPause();
      } else if ( isAllowedToWake() ) {
        goToReadyToWake();
      } else {
        processSleeping();
      }
      break;
    case STATE_READY_TO_WAKE:
      if (pauseSwitchClosed) {
        goToPause();
        digitalWrite(READY_LED, LOW);
      } else if (motionDetected) {
        goToAwake();
        digitalWrite(READY_LED, LOW);
      } else {
        processSleeping();
      }
      break;
    case STATE_AWAKE:
      if (pauseSwitchClosed){
        goToPause();
      } else if ( processAwakeAnimation() ) {
        goToSleep();
      } // processAwakeAnimation() retourneert true wanneer alle animaties compleet zijn
      break;
    default:
      Serial.println("ONBEKENDE STATE");
      break; // We zouden hier nooit moeten komen
  }
}
/*
 * Transitie naar de Pauze State
 */
inline void goToPause() {
  Serial.println("GEPAUZEERD");
  state = STATE_PAUSED;
  stopAllEffects();
  sounds.stopAll();
}
/*
 * Transitie naar de Slaap State
 */
inline void goToSleep() {
  Serial.println("GAAT SLAPEN");
  state = STATE_SLEEPING;
  wakeAllowedTimer = millis();
}
/*
 * Transitie naar de Klaar Om Te Waken State
 * Dit is een speciaal geval van de slaap state
 */
inline void goToReadyToWake() {
  Serial.println("KLAAR OM TE WAKKER TE WORDEN");
  state = STATE_READY_TO_WAKE;
}
/*
 * Transitie naar de Wakker State
 * - Wekt het monster en verwerkt de effecten & geluiden
 *
 * Roep dit EENMAAL aan om de WAKKER state te starten.
 */
inline void goToAwake() {
  Serial.println("WAKKER");
  state = STATE_AWAKE;
  wakeMonster();
}
/*
 * Verwerk een cyclus van de SLAPEN activiteit
 * - Speel Slaap Geluiden
 * - Update slaap timer
 */
inline void processSleeping() {
  if ((millis() - timeSinceLastSnore) > SLEEP_SOUND_DELAY_MILLIS) {
    sounds.playSnore();
    timeSinceLastSnore = millis();
  }
}
/*
 * Bepaalt of monster op dit moment mag wakker worden.
 * - Controleer debug schakelaar, als deze gesloten is gebruiken we een kortere Wake Allowed Timer
 * - Monster moet een vooraf gedefinieerde minimum tijd slapen voordat het gewekt mag worden
 * - Verlicht LED wanneer het gewekt mag worden
 */
inline boolean isAllowedToWake() {
  boolean isDebug = digitalRead(DEBUG_BUTTON) == LOW;
  unsigned long requiredDelay = WAKE_DELAY_MILLIS;
  if ( isDebug ) {
    requiredDelay = WAKE_DELAY_DEBUG_MILLIS;
  }
  boolean isAllowed = (millis() - wakeAllowedTimer ) > requiredDelay;
  if (isAllowed ) {
    digitalWrite(READY_LED, HIGH);
  }
  return isAllowed;
}
/*
 * Wek Monster
 * Start de Wakker Animaties
 * Speel de Wakker Geluiden
 *
 * Roep dit EENMAAL aan om de WAKKER state te starten.
 */
void wakeMonster() {
  int activityDuration = random(WAKE_MIN_MILLIS, WAKE_MAX_MILLIS); // dit is hoe lang het monster actief zal zijn
  Serial.print(" wakker duur: ");
  Serial.print(activityDuration);
  Serial.println(" ms ");
  bounceLid(activityDuration);
  flashRedLight(activityDuration + RED_LIGHT_EXTRA_TIME_MILLIS);
  activateSmoke(activityDuration + SMOKE_EXTRA_TIME_MILLIS);
  sounds.playRoar();
}
/*
 * Beheert de voortgang van de WAKKER animaties
 * Roep dit ELKE CYCLUS aan tijdens de WAKKER state.
 * Retourneert TRUE wanneer alle animaties compleet zijn
 */
boolean processAwakeAnimation() {
  printTimersToLog();
  boolean done1 = false;
  boolean done2 = false;
  boolean done3 = false;
  if (millis() - lidBounceTimer > lidBounceDuration) {
    bounceLid(0);
    done1 = true;
  }
  if (millis() - redLightTimer > redLightDuration ) {
    flashRedLight(0);
    done2 = true;
  }
  if (millis() - smokeTimer > smokeDuration ) {
    activateSmoke(0);
    done3 = true;
  }
  return done1 && done2 && done3;
}
/*
 * Beheer Effect: Laat het doosdeksel stuiteren
 * - duur is het aantal milliseconden dat het effect moet lopen
 * - duur van 0 betekent dat het effect gestopt moet worden
 */
inline void bounceLid(unsigned long duration) {
  if (duration <= 0) {
    energizeRelay(LID_BOUNCER);
    lidBounceDuration = 0;
  } else {
    // start het deksel stuiteren
    de_energizeRelay(LID_BOUNCER);
    lidBounceTimer = millis();
    lidBounceDuration = duration;
  }
}
/*
 * Beheer Effect: Knipper Rode Lichten
 * - duur is het aantal milliseconden dat het effect moet lopen
 * - duur van 0 betekent dat het effect gestopt moet worden
 */
inline void flashRedLight(unsigned long duration) {
  if (duration <= 0) {
    energizeRelay(RED_LEDS);
    redLightDuration = 0;
  } else {
    // start het licht knipperen
    de_energizeRelay(RED_LEDS);
    redLightTimer = millis();
    redLightDuration = duration;
  }
}
/*
 * Start/Stop Effect: Activeer Rook
 * - duur is het aantal milliseconden dat het effect moet lopen
 * - duur van 0 betekent dat het effect gestopt moet worden
 */
inline void activateSmoke(unsigned long duration) {
  // 'druk' de rookknop
  // duur moet een vast bedrag zijn tijd nodig voor de machine om te reageren op de actie
  // stel een timeout in om na duur te stoppen
  if (duration <= 0) {
    energizeRelay(FOG_MACHINE);
    smokeDuration = 0;
  } else {
    // start het licht knipperen
    de_energizeRelay(FOG_MACHINE);
    smokeTimer = millis();
    smokeDuration = duration;
  }
}
/*
 * Stop alle Effecten
 * - Dit schakelt het monster effectief uit
 */
inline void stopAllEffects() {
  bounceLid(0);
  flashRedLight(0);
  activateSmoke(0);
}
/*
 * Print de Wakker Animatie timers naar de log één keer per seconde
 */
inline void printTimersToLog() {
  static unsigned long timeofLastTimerLog = 0;
  if (millis() - timeofLastTimerLog >= 1000) {
    Serial.print(" deksel: ");
    Serial.print( (millis()-lidBounceTimer) > lidBounceDuration ? 0 : (lidBounceDuration -(millis()-lidBounceTimer) ) );
    Serial.print(" lichten: ");
    Serial.print( (millis()-redLightTimer) > redLightDuration ? 0 : (redLightDuration -(millis()-redLightTimer) ) );
    Serial.print(" rook: ");
    Serial.println( (millis()-smokeTimer) > smokeDuration ? 0 : (smokeDuration -(millis()-smokeTimer) ) );
    timeofLastTimerLog = millis();
  }
}
/*
 * Activeer Relais
 * Stelt de Normaal Open (NO) terminal op OPEN
 * Normaal Gesloten wordt Gesloten
 */
inline void energizeRelay(int channel) {
  digitalWrite(channel, HIGH);
}
/*
 * Deactiveer Relais
 * Stelt de Normaal Open (NO) terminal op GESLOTEN.
 * Normaal Gesloten wordt OPEN
 */
inline void de_energizeRelay(int channel) {
  digitalWrite(channel, LOW);
}

MonsterSounds.h

/* OPMERKING OVER ARDUINO PINNEN
 * Pinnen 13, 12, 11 worden altijd gebruikt door de SD-kaart (ze zijn de enige pinnen die een high-speed SPI interface hebben).
 * Dan zijn er 5 andere pinnen die gebruikt worden om met de DAC en SD-kaart te communiceren, maar ze kunnen ingesteld worden om met elke Arduino-pin te verbinden.
 * Standaard is de bibliotheek geconfigureerd om pinnen 10 (voor SD-kaart) en pinnen 2, 3, 4 en 5 voor de DAC te gebruiken.
 * Het wijzigen van deze pinnen vereist aanpassing van de bibliotheek - de pinnen worden gerefereerd door hun 'hardware' pinnamen (bijv. PORTD, etc) niet door Arduino-pinnen.
 * Dat betekent dat pinnen 6, 7, 8, 9 en de 6 analoge in pinnen (ook bekend als digitale I/O pinnen 14-20) beschikbaar zijn.
 * */
#include 
#include 
#include 
#include 
static const char roar0[] = "ROAR0000.wav";
static const char roar1[] = "ROAR0001.wav";
static const char roar2[] = "ROAR0002.wav";
static const char * const roarSounds[] = {roar0, roar1, roar2};
static const char sleep0[] = "SNORE000.wav";
static const char sleep1[] = "SNORE001.wav";
static const char sleep2[] = "SNORE002.wav";
static const char * const sleepSounds[] = {sleep0, sleep1, sleep2};
int previousRoarSound = -1;
class MonsterSounds {
private:
  SdReader card; // Dit object bevat de informatie voor de kaart
  FatVolume vol; // Dit bevat de informatie voor de partitie op de kaart
  FatReader root; // Dit bevat de informatie voor de root directory van de volume
  FatReader file; // Dit object vertegenwoordigt het WAV bestand voor een fragment
  WaveHC wave; // Een enkel wave object -- slechts één geluid wordt tegelijk gespeeld
  void playfile(char *name);
public:
  void initialize();
  void playSystemReady();
  void playRoar();
  void playSnore();
  void stopAll();
};

MonsterSounds.ino

/* OPMERKING OVER ARDUINO PINNEN
 * Pinnen 13, 12, 11 worden altijd gebruikt door de SD-kaart (ze zijn de enige pinnen die een high-speed SPI interface hebben).
 * Dan zijn er 5 andere pinnen die gebruikt worden om met de DAC en SD-kaart te communiceren, maar ze kunnen ingesteld worden om met elke Arduino-pin te verbinden.
 * Standaard is de bibliotheek geconfigureerd om pinnen 10 (voor SD-kaart) en pinnen 2, 3, 4 en 5 voor de DAC te gebruiken.
 * Het wijzigen van deze pinnen vereist aanpassing van de bibliotheek - de pinnen worden gerefereerd door hun 'hardware' pinnamen (bijv. PORTD, etc) niet door Arduino-pinnen.
 * Dat betekent dat pinnen 6, 7, 8, 9 en de 6 analoge in pinnen (ook bekend als digitale I/O pinnen 14-20) beschikbaar zijn.
 * */
void MonsterSounds::initialize() {
  Serial.println("Initialiseren Geluiden...");
  if(!card.init()) Serial.println(F("Kaart init mislukt!"));
  if(!vol.init(card)) Serial.println(F("Geen partitie!"));
  if(!root.openRoot(vol)) Serial.println(F("Kon dir niet openen"));
  Serial.println(F("Bestanden gevonden:"));
  root.ls();
  randomSeed(analogRead(0));
}
void MonsterSounds::playSystemReady() {
  this->playfile("WELCOME0.WAV");
}
void MonsterSounds::playRoar() {
  int index = random(3); // 0, 1, 2
  while (index == previousRoarSound) {
    index = random(3);
  }
  previousRoarSound = index;
  this->playfile(roarSounds[index]);
}
void MonsterSounds::playSnore() {
  if (!wave.isplaying) // Onderbreek geen bestaand geluid met snurken
  {
    int index = random(3); // 0, 1, 2
    this->playfile(sleepSounds[index]);
  }
}
void MonsterSounds::stopAll() {
  wave.stop(); // Stop eventueel spelend WAV
}
// -------------------------------------------------------------------
// playfile()
// Open en start het spelen van een WAV bestand
// -------------------------------------------------------------------
void MonsterSounds::playfile(char *name) {
  PgmPrint("Spelen geluid: ");
  Serial.println(name);
  if (wave.isplaying) {// speelt al iets, dus stop het!
    wave.stop(); // stop het
  }
  if (!file.open(root, name)) {
    PgmPrintln("Bestand niet gevonden ");
    return;
  }
  if (!wave.create(file)) {
    PgmPrintln("Geen geldig WAV");
    return;
  }
  // ok tijd om te spelen!
  wave.play();
}

Productieproces

  1. EEG-Apparaten: Ontwerp, Productie en Opkomende Toepassingen
  2. De Sapdoos Revolutie: Geschiedenis, Ontwerp en Milieueffect
  3. Automaatjes: Een Amerikaanse Industriemacht van $36,6 Mrd
  4. Expertgids voor Moderne Wisselgeldautomaten: Ontwerp, Componenten en Toekomsttrends
  5. De Evolutie en Productie van Naaimachines: Van 19e-Eeuwse Innovatie tot Moderne Automatisering
  6. Panty's: De Ultieme Gids voor Elegante Dameskousen
  7. Bouw je eigen DIY huiswerk-schrijfmachine thuis
  8. Giftduino: De Ultieme Arduino Cadeau-set voor Hobbyisten en Docenten
  9. Bouw een Ultrasonische Zweefapparaat met Arduino – Stap-voor-stap Handleiding
  10. Compact Weerstation: Arduino Nano & ESP8266 Met BMP280 Barometrische Sensor & OLED/Nokia LCD Display
  11. Bouw een Digitale Horloge op Arduino met een Finitie Toestandsmachine