Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Construisez votre propre monstre dans une boîte : Projet robotique Arduino

Composants et fournitures

Caisse/Boîte en bois × 1
Arduino UNO × 1
Adafruit Wave Shield × 1
Module relais 4 canaux SainSmart × 1
Moteur d'essuie-glace × 1
Guirlande LED rouge de Noël (100) × 1
Machine à fumée × 1
Ampli/Enceinte amplifiée × 1

À propos du projet

Mise à jour vers la version 4

J'ai récemment réécrit le code Arduino pour ce projet. Voici un résumé des changements :

Le timing n'est plus dépendant des frames ; l'utilisation de delay() dans la boucle principale a été supprimée, ce qui élimine le problème de « port occupé » lors de la connexion à l'IDE Arduino.

Cela permet à ces effets de durer un peu plus longtemps que le mouvement du couvercle. De nombreux commentaires ont été ajoutés dans le code.

Vous trouverez tout le code le plus récent sur GitHub.

Monstre dans une boîte

J'adore les accessoires d'Halloween et j'ai vu et lu de superbes constructions de « Monstre dans une boîte » l'année dernière. J'ai donc décidé de construire le mien. Le concept est simple : créer l'illusion qu'un conteneur retient un monstre dangereux sur le point de s'échapper. L'illusion combine mouvement, son, lumière, fumée et surprise.

Qu'y a-t-il dans la boîte ?

Il faut une boîte assez grande pour sembler capable de contenir quelque chose de gros et effrayant. L'aspect usé et ancien renforce l'illusion que la boîte ne tient le monstre qu'à peine. N'ayant rien trouvé de satisfaisant en brocante ou en ligne, je l'ai construite moi-même.

J'ai utilisé 15 piquets de clôture en pin de 1,80 m (Home Depot) pour faire une boîte d'environ 90 × 75 × 75 cm. Découpés à la scie à table, assemblés au cloueur pneumatique 18 gauge. Les clous n'étant pas assez solides face aux secousses, j'ai renforcé l'ensemble avec des vis à plâtre de 2,5 cm (de l'intérieur vers l'extérieur pour les cacher).

Le bois a été vieilli avec un mélange de thé noir, vinaigre et laine d'acier, puis décoré avec des pochoirs et étiquettes trouvés ou créés.

Construisez votre propre monstre dans une boîte : Projet robotique Arduino

Le cerveau

L'accessoire a deux états : « Endormi » et « Réveillé ». En mode sommeil, la boîte est calme, n'émettant que des ronflements et grognements légers. Le monstre se réveille quand un capteur PIR détecte un passant. En mode éveillé : rugissements, fumée, couvercle qui claque, lueur rouge à l'intérieur.

Un Arduino Uno, un Wave Shield et un module relais orchestrent le tout. Le Wave Shield contient une petite collection de sons de sommeil et de rugissements. Le capteur PIR bascule entre les deux modes. En mode éveillé, l'Arduino active les canaux du relais pour le moteur du couvercle, les lumières rouges, le générateur de fumée et les sons du Wave Shield. Un bouton Pause permet de couper temporairement le monstre pour les jeunes enfants.

Construisez votre propre monstre dans une boîte : Projet robotique Arduino

C'est vivant !

Un lève-couvercle fait claquer le couvercle comme si le monstre essayait de s'échapper. Les solutions populaires : vérins pneumatiques ou cames rotatives. J'ai choisi une came rotative, plus simple et moins chère.

J'ai acheté un moteur d'essuie-glace d'occasion en casse pour 15 $. Ces moteurs tournent en 12 V, ont un couple excellent et une vitesse raisonnable. Assurez-vous qu'il conserve son faisceau de fils, son bras de came et son excentrique ; sans eux, la came glissera.

Fixez le moteur sur une paroi intérieure, en laissant la came tourner librement. J'ai découpé une came de 30 cm de diamètre dans du contreplaqué 12 mm, puis taillé des « dents » aléatoires à la scie sauteuse pour un mouvement irrégulier. Un galet (rouleau en nylon sur boulon à carrosserie) fixé sous le couvercle suit les dents de la came.

Construisez votre propre monstre dans une boîte : Projet robotique Arduino
Construisez votre propre monstre dans une boîte : Projet robotique Arduino
Construisez votre propre monstre dans une boîte : Projet robotique Arduino

Le moteur est alimenté par le rail 12 V d'une alimentation ATX via le relais commandé par l'Arduino. Après quelques ajustements de position du galet, le couvercle rebondissait comme prévu.

Souffle de feu : fumée et lumières

J'ai utilisé un générateur de fumée 400 W bon marché, à commande radio. Pour le piloter par l'Arduino, j'ai ouvert le récepteur et soudé deux fils sur les plots du bouton de déclenchement, reliés à un canal de relais. J'ai ajouté un tuyau d'aspirateur pour diriger la fumée en jet juste sous le couvercle, améliorant l'effet visuel et réduisant la condensation sur l'électronique.

Pour les lumières, j'ai coupé une rallonge et l'ai câblée sur un canal de relais ; la guirlande de 100 LED rouges est ainsi commutée par l'Arduino.

Construisez votre propre monstre dans une boîte : Projet robotique Arduino
Construisez votre propre monstre dans une boîte : Projet robotique Arduino
Construisez votre propre monstre dans une boîte : Projet robotique Arduino

Utilisez votre voix d'extérieur

Le Wave Shield sort sur jack 3,5 mm (et deux broches I/O). J'ai utilisé un câble patch vers un ampli basse 30 W emprunté à ma salle de répétition. Toute enceinte amplifiée ferait l'affaire, mais un bon grave est un plus.

Construisez votre propre monstre dans une boîte : Projet robotique Arduino

Enchaînez-le

J'ai acheté des chaînes en plastique dans un magasin d'Halloween et imprimé un cadenas en 3D. Les enrouler autour de la caisse renforce l'illusion.

Construisez votre propre monstre dans une boîte : Projet robotique Arduino

Halloween !!!

Placez la caisse dans le jardin, cachez le capteur PIR dans un buisson à proximité. J'ai utilisé un long câble haut-parleur pour tester le positionnement : le monstre se réveille à environ 1,5 m.

À la tombée de la nuit, les détails de la caisse devenaient invisibles. Un projecteur stroboscopique a résolu le problème avec un super effet.

Les enfants approchaient, intrigués ou effrayés par les grognements. Au rugissement, ils sautaient, criaient, certains applaudissaient. Un énorme succès.

Améliorations

Fatigué de cacher le capteur dans les buissons, j'en ai collé un dans le ventre d'un rat en plastique, positionnable le long de l'allée. J'ai ajouté une prise RJ11 à l'arrière de la boîte pour connecter le rat via un cordon téléphonique de 15 m, bien plus pratique que les fils d'enceinte.

Construisez votre propre monstre dans une boîte : Projet robotique Arduino
Construisez votre propre monstre dans une boîte : Projet robotique Arduino

J'ai aussi ajouté un interrupteur et des LEDs indicatrices sur cette plaque. L'interrupteur met en pause toutes les fonctions sans couper l'alimentation (le coupe-circuit principal reste la multiprise à l'intérieur, difficile d'accès). Ce bouton pause a été très utile pour arrêter le monstre devant les tout-petits ou pour montrer l'intérieur.

Les chaînes en plastique sont encombrantes quand il faut ouvrir la boîte. J'ai attaché des mousquetons à ressort noirs aux extrémités des chaînes, qui s'accrochent à des pitons vissés dans les coins inférieurs. Pas high-tech, mais très pratique.

L'avenir

Dépôt GitHub

Le code le plus récent et les schémas de câblage sont disponibles sur GitHub.

Code

Monster In A Box Sketch (C/C++)

/* Wave Shield Pins in Use: 2, 3, 4, 5, 10, 11, 12 & 13 
Pins 13, 12, 11 are always used by the SD card (they are the only pins that have a high speed SPI interface). 
Then there are 5 other pins used to talk to the DAC and SD card, but they can be set to connect to any arduino pin. 
However, by default, the library is configured to use pins 10 (for SD card) and pins 2, 3, 4 and 5 for the DAC. 
To change these pins requires modifying the library - the pins are referenced by their 'hardware' pin names (ie PORTD, etc) not by arduino pins. 
That means pins 6, 7, 8, 9 and the 6 analog in pins (also known as digital i/o pins 14-20) are available. 
https://learn.adafruit.com/adafruit-wave-shield-audio-shield-for-arduino/faq */ 
#include "MonsterSounds.h" 
#define RESERVED_00 0 // Reserved for Serial RX 
#define RESERVED_01 1 // Reserved for Serial TX 
#define RESERVED_02 2 // Reserved for Wave Shield 
#define RESERVED_03 3 // Reserved for Wave Shield 
#define RESERVED_04 4 // Reserved for Wave Shield 
#define RESERVED_05 5 // Reserved for Wave Shield 
#define FOG_MACHINE 6 // Connect Digital Pin on Arduino to Relay Module 
#define RED_LEDS 7 // Connect Digital Pin on Arduino to Relay Module 
#define LID_BOUNCER 8 // Connect Digital Pin on Arduino to Relay Module 
#define RESERVED_09 9 // Connect Digital Pin on Arduino to Relay Module 
#define RESERVED_10 10 // Reserved for Wave Shield 
#define RESERVED_11 11 // Reserved for Wave Shield 
#define RESERVED_12 12 // Reserved for Wave Shield 
#define RESERVED_13 13 // Reserved for Wave Shield 
#define PIR_SENSOR A0 // PIR Input 
#define MOTION_LED A1 // LED: lights when motion is detected (regardless of pause/sleep/wake state) 
#define PAUSED_LED A2 // LED: lights when system is paused 
#define READY_LED A3 // LED: lights when monster is in READY_TO_WAKE state 
#define PAUSE_BUTTON A4 // Pause Switch Input 
#define DEBUG_BUTTON A5 // Debug Switch Input 
// Effects Timer Settings - in Seconds (EDIT THESE) 
#define WAKE_DELAY 30 // Minimum amount of time between 'awake' occurencs in Seconds 
#define WAKE_DELAY_DEBUG 10 // WAKE_DELAY override when DEGUB switch is engaged 
#define SLEEP_SOUND_DELAY 1 // Number of seconds to wait between attempting to fire the next 'sleep' sound 
#define WAKE_MIN 3 // Minimum amount of 'awake' time in Seconds 
#define WAKE_MAX 5 // Maximum amount of 'awake' time in Seconds 
#define RED_LIGHT_EXTRA_TIME 1 // Allows the red lights to run a bit longer than the lid bouncer, if desired 
#define SMOKE_EXTRA_TIME 2 // Allows the smoke to run a bit longer than the lid bouncer, if desired 
// Effects Timers Settings - in Milliseconds (DO NOT EDIT THESE) 
#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, // Only while running setup() and first time into loop() 
  STATE_PAUSED, // Turn off all sounds and effects 
  STATE_SLEEPING, // No effects, sleeping sounds, does not allow awake to be triggered 
  STATE_READY_TO_WAKE, // No effects, sleeping sounds, allows awake to be triggered 
  STATE_AWAKE 
}; // Fires effects and monster awake sounds 
States state = STATE_INITIALIZE; 
void setup() { 
  Serial.begin(9600); 
  pinMode(LID_BOUNCER, OUTPUT); 
  pinMode(RED_LEDS, OUTPUT); 
  pinMode(FOG_MACHINE, OUTPUT); 
  pinMode(PAUSED_LED, OUTPUT); 
  pinMode(MOTION_LED, OUTPUT); 
  pinMode(READY_LED, OUTPUT); 
  stopAllEffects(); 
  pinMode(PIR_SENSOR, INPUT); 
  pinMode(PAUSE_BUTTON, INPUT_PULLUP); 
  pinMode(DEBUG_BUTTON, INPUT_PULLUP); 
  sounds.initialize(); 
  sounds.playSystemReady(); 
  delay(1000); 
  Serial.println(); 
  Serial.print("*** System Ready ***"); 
  Serial.println(); 
} 
/* 
 * NOTE: All buttons are using pullups, thus LOW means the button is PRESSED 
 * Keep in mind the pull-up means that switch logic is inverted. 
 * It goes HIGH when it's open, and LOW when it's pressed. 
 * 
 * The PIR motion sensor does NOT behave this way. 
 */ 
/* 
 * Main processing loop 
 * - Manages the 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(); } 
      break; 
    default: 
      Serial.println("UNKNOWN STATE"); 
      break; 
  } 
} 
/* Transition to the Pause State */ 
inline void goToPause() { 
  Serial.println("PAUSED"); 
  state = STATE_PAUSED; 
  stopAllEffects(); 
  sounds.stopAll(); 
} 
/* Transition to the Sleep State */ 
inline void goToSleep() { 
  Serial.println("GOING TO SLEEP"); 
  state = STATE_SLEEPING; 
  wakeAllowedTimer = millis(); 
} 
/* Transition to the Ready To Awake State */ 
inline void goToReadyToWake() { 
  Serial.println("READY TO WAKE"); 
  state = STATE_READY_TO_WAKE; 
} 
/* Transition to the Awake State */ 
inline void goToAwake() { 
  Serial.println("AWAKE"); 
  state = STATE_AWAKE; 
  wakeMonster(); 
} 
/* process a cycle of the SLEEP activity */ 
inline void processSleeping() { 
  if ((millis() - timeSinceLastSnore) > SLEEP_SOUND_DELAY_MILLIS) { 
    sounds.playSnore(); 
    timeSinceLastSnore = millis(); 
  } 
} 
/* Determines if monster is allowed to wake up at this time */ 
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; 
} 
/* Wake Monster - Starts the Awake Animations & Plays the Awake Sounds */ 
void wakeMonster() { 
  int activityDuration = random(WAKE_MIN_MILLIS, WAKE_MAX_MILLIS); 
  Serial.print(" wake duration: "); 
  Serial.print(activityDuration); 
  Serial.println(" ms "); 
  bounceLid(activityDuration); 
  flashRedLight(activityDuration + RED_LIGHT_EXTRA_TIME_MILLIS); 
  activateSmoke(activityDuration + SMOKE_EXTRA_TIME_MILLIS); 
  sounds.playRoar(); 
} 
/* Manages the progress of the AWAKE animations */ 
boolean processAwakeAnimation() { 
  printTimersToLog(); 
  boolean done1 = false, done2 = false, 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; 
} 
/* Manage Effect: Bounce the box lid */ 
inline void bounceLid(unsigned long duration) { 
  if (duration <= 0) { energizeRelay(LID_BOUNCER); lidBounceDuration = 0; } 
  else { de_energizeRelay(LID_BOUNCER); lidBounceTimer = millis(); lidBounceDuration = duration; } 
} 
/* Manage Effect: Flash Red Lights */ 
inline void flashRedLight(unsigned long duration) { 
  if (duration <= 0) { energizeRelay(RED_LEDS); redLightDuration = 0; } 
  else { de_energizeRelay(RED_LEDS); redLightTimer = millis(); redLightDuration = duration; } 
} 
/* Start/Stop Effect: Activate Smoke */ 
inline void activateSmoke(unsigned long duration) { 
  if (duration <= 0) { energizeRelay(FOG_MACHINE); smokeDuration = 0; } 
  else { de_energizeRelay(FOG_MACHINE); smokeTimer = millis(); smokeDuration = duration; } 
} 
/* Stop all of the Effects */ 
inline void stopAllEffects() { 
  bounceLid(0); flashRedLight(0); activateSmoke(0); 
} 
/* Prints the Awake Animation timers to the log once per second */ 
inline void printTimersToLog() { 
  static unsigned long timeofLastTimerLog = 0; 
  if (millis() - timeofLastTimerLog >= 1000) { 
    Serial.print(" lid: "); 
    Serial.print( (millis()-lidBounceTimer) > lidBounceDuration ? 0 : (lidBounceDuration -(millis()-lidBounceTimer) ) ); 
    Serial.print(" lights: "); 
    Serial.print( (millis()-redLightTimer) > redLightDuration ? 0 : (redLightDuration -(millis()-redLightTimer) ) ); 
    Serial.print(" smoke: "); 
    Serial.println( (millis()-smokeTimer) > smokeDuration ? 0 : (smokeDuration -(millis()-smokeTimer) ) ); 
    timeofLastTimerLog = millis(); 
  } 
} 
/* Energize Relay - Sets the Normally Open (NO) terminal to OPEN */ 
inline void energizeRelay(int channel) { digitalWrite(channel, HIGH); } 
/* De-Energize Relay - Sets the Normally Open (NO) terminal to CLOSED */ 
inline void de_energizeRelay(int channel) { digitalWrite(channel, LOW); } 

MonsterSounds.h (C/C++)

/* NOTE ABOUT ARDUINO PINS 
* Pins 13, 12, 11 are always used by the SD card... 
* That means pins 6, 7, 8, 9 and the 6 analog in pins (also known as digital i/o pins 14-20) are available. 
*/ 
#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; 
  FatVolume vol; 
  FatReader root; 
  FatReader file; 
  WaveHC wave; 
  void playfile(char *name); 
public: 
  void initialize(); 
  void playSystemReady(); 
  void playRoar(); 
  void playSnore(); 
  void stopAll(); 
}; 

MonsterSounds.ino (C/C++)

/* NOTE ABOUT ARDUINO PINS ... */ 
void MonsterSounds::initialize() { 
  Serial.println("Initializing Sounds..."); 
  if(!card.init()) Serial.println(F("Card init. failed!")); 
  if(!vol.init(card)) Serial.println(F("No partition!")); 
  if(!root.openRoot(vol)) Serial.println(F("Couldn't open dir")); 
  Serial.println(F("Files found:")); 
  root.ls(); 
  randomSeed(analogRead(0)); 
} 
void MonsterSounds::playSystemReady() { this->playfile("WELCOME0.WAV"); } 
void MonsterSounds::playRoar() { 
  int index = random(3); 
  while (index == previousRoarSound) { index = random(3); } 
  previousRoarSound = index; 
  this->playfile(roarSounds[index]); 
} 
void MonsterSounds::playSnore() { 
  if (!wave.isplaying) { 
    int index = random(3); 
    this->playfile(sleepSounds[index]); 
  } 
} 
void MonsterSounds::stopAll() { wave.stop(); } 
void MonsterSounds::playfile(char *name) { 
  PgmPrint("Playing sound: "); Serial.println(name); 
  if (wave.isplaying) { wave.stop(); } 
  if (!file.open(root, name)) { PgmPrintln("File not found "); return; } 
  if (!wave.create(file)) { PgmPrintln("Not a valid WAV"); return; } 
  wave.play(); 
} 

Pièces personnalisées et boîtiers

monstersounds_7vLZD3NU4t.zip

Schémas

Construisez votre propre monstre dans une boîte : Projet robotique Arduino

Processus de fabrication

  1. Machines EEG : conception, fabrication et applications émergentes
  2. La révolution de la brique de jus : histoire, conception et impact environnemental
  3. Les distributeurs automatiques : une industrie américaine de 36,6 milliards de dollars
  4. Guide expert des machines à rendre la monnaie modernes : conception, composants et tendances futures
  5. L'évolution et la fabrication des machines à coudre : de l'innovation du 19e siècle à l'automatisation moderne
  6. Le collant : guide ultime de l'élégance féminine en hosiery
  7. Construire sa propre machine à écrire les devoirs à la maison (Traceur à stylo)
  8. Giftduino : Boîte cadeau interactive Arduino pour makers et éducateurs
  9. Construire un dispositif de lévitation ultrasonique avec Arduino – Guide étape par étape