ENIB 2022 - groupe B : Le booster

De Les Fabriques du Ponant
Aller à : navigation, rechercher

Pour notre projet sur le thème "fête foraine" nous avons décidé de réalisé une maquette d'une attraction bien connue : le booster (ou bomber max). Il se compose d'un bras attaché à un support, qui tourne à différentes vitesses et différents sens, d'effets lumineux réalisés par des LEDs et d'un fond sonore.


Photo de l'équipe

Photoenib2018.jpg


Caractéristiques techniques

L'attraction prend la forme d'un "pendule" en mouvement équipé d'un bras de 30 cm de long, d'un support de 22 cm de hauteur et d'une base. Le bras peut atteindre la vitesse de 100 tour/minute (théorique). La vitesse et le sens de rotation sont ajustables avec un potentiomètre. Le support dispose de chaque côté d'un bandeau de 10 LEDs RGB contrôlables électroniquement. Un interrupteur permet d'activer ou désactiver le fond sonore (également contrôlable électroniquement).

La totalité de l'attraction est contrôlée avec une carte Arduino. Un module de lecture de carte SD y a été ajouté pour le fond sonore.


Conception

Maquette 3D réalisée avec CATIA

Nous avons commencé par des recherches sur l'attraction choisie (estimation de la taille de notre maquette, fonctionnalités, style) à la suite desquelles nous avons décidé de concevoir notre maquette à l'échelle 1/100.

Nous avons utilisé le logiciel de conception assistée par ordinateur CATIA pour réaliser une version 3D de notre maquette. Cette étape nous a permis de choisir les dimensions et l'aspect de notre projet. Le logiciel nous a également permis d'obtenir facilement les plans 2D nécessaire à la fabrication des pièces.

L'intégralité de la structure (bras, support, base) a été réalisée avec une découpeuse laser dans du médium 3mm. Ce choix nous permet d'allier solidité, rigidité et légèreté. La grande précision de cette technique de fabrication nous permet de ne pas utiliser de colle lors du montage final : l'emboitement des pièces suffit à assurer l'intégrité de la structure. La découpe des pièces a duré environ 8 minutes, ce qui fait de la découpe laser un choix préférable à l'utilisation d'une imprimante 3D (pour ce projet).

Plan pour la découpe des pièces


Les sièges ont été réalisés avec un stylo 3D. Sa prise en main n'est pas évidente mais il permet de réaliser rapidement et à main levée des pièces 3D en plastique plutôt convaincantes. Notre maquette est équipée de 2 rangées de 2 sièges à chaque extrémité du bras. Les sièges sont mobiles autour d'un axe réalisé avec un pic à brochette et fixé au bras avec de la colle chaude.

Pour la mise en mouvement du bras nous avons utilisé un servomoteur (référence DM-S0090D) capable de fonctionner avec un courant continu 4,8 V et facilement contrôlable par Arduino et un potentiomètre. Celui-ci peut atteindre une vitesse de 100 tour/min et un couple de 1,5 kg.cm. Nous avons mesuré ses dimensions à l'avance pour les reporter sur la maquette 3D. Le moteur se fixe à la structure avec deux vis (les trous pour les vis ainsi que l'emplacement prévu pour le moteur sont visibles sur les plans).


Pour l'aspect esthétique de la maquette nous avons utilisé du film auto-collant sur les pièces de la structure (bras, support, base). L'utilisation d'une imprimante à stickers était possible mais pas vraiment appropriée au vu des dimensions des pièces. Nous avons donc appliqué et découpé manuellement le film auto-collant; le résultat obtenu est très satisfaisant et sûrement meilleur que si nous avions utilisé de la peinture. De plus nous avons décidé d'ajouter de la lumière à la maquette : nous avons collé deux bandeaux de 10 LEDs sur les côtés du support. Celles-ci sont également contrôlées par la carte Arduino (couleur, paterne, intensité).

Pour ajouter un fond sonore à notre attraction nous avons utilisé un simple haut-parleur contrôlé lui aussi par la carte Arduino (voir Arduino).


Arduino

Le codage de la carte Arduino Wemos s’est fait en trois parties. Premièrement, il s’agit de contrôler le servomoteur à l’aide d’un potentiomètre 10 kΩ. Pour cela nous avons utilisé la bibliothèque servo.h et nous nous sommes aidés de ce tutoriel qui explique parfaitement comment faire tourner le moteur dans les deux sens en régulant la vitesse jusqu’au maximum possible.

Dans une deuxième partie, il est nécessaire de commander les bandeaux de LED. Ce tutoriel nous a appris à le faire en important la bibliothèque FastLED.h et en proposant un dossier téléchargeable contenant plusieurs exemples de codes pour obtenir des cinématiques variées de pilotage de nos LED.

Enfin, nous avons souhaité faire une diffusion sonore à l’aide du module MP3-TF-16P et d’un haut-parleur simple. Pour apprendre à utiliser ce matériel avec notre carte Wemos nous avons suivi ce tutoriel qui demande l’importation de la bibliothèque DFRobotDFPlayerMini.h en n’oubliant pas d’importer le son souhaité sur la carte SD.

Par ailleurs, ce site permet de connaître le numéro des différentes broches de la carte D1 mini pour le codage car certains des tutoriels que nous avons utilisés ont été faits sur des cartes Arduino Uno.

Code

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(5, 4); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);


#include <Servo.h> 
  
Servo servo;  // create servo object to control a servo 
int val;        // variable to read value from analog pin



#include <FastLED.h>

#define LED_PIN     16
#define BRIGHTNESS  255
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB

// Params for width and height
const uint8_t kMatrixWidth  = 16;
const uint8_t kMatrixHeight = 16;

// Param for different pixel layouts
const bool    kMatrixSerpentineLayout = true;



#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
#define MAX_DIMENSION ((kMatrixWidth>kMatrixHeight) ? kMatrixWidth : kMatrixHeight)

// The leds
CRGB leds[kMatrixWidth * kMatrixHeight];

// The 16 bit version of our coordinates
static uint16_t x;
static uint16_t y;
static uint16_t z;

// We're using the x/y dimensions to map to the x/y pixels on the matrix.  We'll
// use the z-axis for "time".  speed determines how fast time moves forward.  Try
// 1 for a very slow moving effect, or 60 for something that ends up looking like
// water.
uint16_t speed = 20; // speed is set dynamically once we've started up

// Scale determines how far apart the pixels in our noise matrix are.  Try
// changing these values around to see how it affects the motion of the display.  The
// higher the value of scale, the more "zoomed out" the noise iwll be.  A value
// of 1 will be so zoomed in, you'll mostly see solid colors.
uint16_t scale = 30; // scale is set dynamically once we've started up

// This is the array that we keep our computed noise values in
uint8_t noise[MAX_DIMENSION][MAX_DIMENSION];

CRGBPalette16 currentPalette( PartyColors_p );
uint8_t       colorLoop = 1;

void setup() {

  mySoftwareSerial.begin(9600);
  Serial.begin(115200);
  
  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
  
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  Serial.println(F("DFPlayer Mini online."));
  
  myDFPlayer.volume(30);  //Set volume value. From 0 to 30
  myDFPlayer.play(1);  //Play the first mp3



  
  servo.attach(13);  // attaches servo on D7 to the servo object
  
  //:delay(3000);
  FastLED.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds,NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);

  // Initialize our coordinates to some random values
  x = random16();
  y = random16();
  z = random16();
}



// Fill the x/y array of 8-bit noise values using the inoise8 function.
void fillnoise8() {
  // If we're runing at a low "speed", some 8-bit artifacts become visible
  // from frame-to-frame.  In order to reduce this, we can do some fast data-smoothing.
  // The amount of data smoothing we're doing depends on "speed".
  uint8_t dataSmoothing = 0;
  if( speed < 50) {
    dataSmoothing = 200 - (speed * 4);
  }
  
  for(int i = 0; i < MAX_DIMENSION; i++) {
    int ioffset = scale * i;
    for(int j = 0; j < MAX_DIMENSION; j++) {
      int joffset = scale * j;
      
      uint8_t data = inoise8(x + ioffset,y + joffset,z);

      // The range of the inoise8 function is roughly 16-238.
      // These two operations expand those values out to roughly 0..255
      // You can comment them out if you want the raw noise data.
      data = qsub8(data,16);
      data = qadd8(data,scale8(data,39));

      if( dataSmoothing ) {
        uint8_t olddata = noise[i][j];
        uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing);
        data = newdata;
      }
      
      noise[i][j] = data;
    }
  }
  
  z += speed;
  
  // apply slow drift to X and Y, just for visual variation.
  x += speed / 8;
  y -= speed / 16;
}

void mapNoiseToLEDsUsingPalette()
{
  static uint8_t ihue=0;
  
  for(int i = 0; i < kMatrixWidth; i++) {
    for(int j = 0; j < kMatrixHeight; j++) {
      // We use the value at the (i,j) coordinate in the noise
      // array for our brightness, and the flipped value from (j,i)
      // for our pixel's index into the color palette.

      uint8_t index = noise[j][i];
      uint8_t bri =   noise[i][j];

      // if this palette is a 'loop', add a slowly-changing base value
      if( colorLoop) { 
        index += ihue;
      }

      // brighten up, as the color palette itself often contains the 
      // light/dark dynamic range desired
      if( bri > 127 ) {
        bri = 255;
      } else {
        bri = dim8_raw( bri * 2);
      }

      CRGB color = ColorFromPalette( currentPalette, index, bri);
      leds[XY(i,j)] = color;
    }
  }
  
  ihue+=1;
}

void loop() {
  val = analogRead(0);               // reads potentiometer value (between 0 and 1023)
  val = map(val, 0, 1023, 0, 180);   // scale it to use it with the servo (between 0 and 180)
  servo.write(val);                      // waits for servo to get there
  
  // Periodically choose a new palette, speed, and scale
  ChangePaletteAndSettingsPeriodically();

  // generate noise data
  fillnoise8();
  
  // convert the noise data to colors in the LED array
  // using the current palette
  mapNoiseToLEDsUsingPalette();

  FastLED.show();
  // delay(10);
}



// There are several different palettes of colors demonstrated here.
//
// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
//
// Additionally, you can manually define your own color palettes, or you can write
// code that creates color palettes on the fly.

// 1 = 5 sec per palette
// 2 = 10 sec per palette
// etc
#define HOLD_PALETTES_X_TIMES_AS_LONG 1

void ChangePaletteAndSettingsPeriodically()
{
  uint8_t secondHand = ((millis() / 1000) / HOLD_PALETTES_X_TIMES_AS_LONG) % 60;
  static uint8_t lastSecond = 99;
  
  if( lastSecond != secondHand) {
    lastSecond = secondHand;
    if( secondHand ==  0)  { currentPalette = RainbowColors_p;         speed = 20; scale = 30; colorLoop = 1; }
    if( secondHand ==  5)  { SetupPurpleAndGreenPalette();             speed = 10; scale = 50; colorLoop = 1; }
    if( secondHand == 10)  { SetupBlackAndWhiteStripedPalette();       speed = 20; scale = 30; colorLoop = 1; }
    if( secondHand == 15)  { currentPalette = ForestColors_p;          speed =  8; scale =120; colorLoop = 0; }
    if( secondHand == 20)  { currentPalette = CloudColors_p;           speed =  4; scale = 30; colorLoop = 0; }
    if( secondHand == 25)  { currentPalette = LavaColors_p;            speed =  8; scale = 50; colorLoop = 0; }
    if( secondHand == 30)  { currentPalette = OceanColors_p;           speed = 20; scale = 90; colorLoop = 0; }
    if( secondHand == 35)  { currentPalette = PartyColors_p;           speed = 20; scale = 30; colorLoop = 1; }
    if( secondHand == 40)  { SetupRandomPalette();                     speed = 20; scale = 20; colorLoop = 1; }
    if( secondHand == 45)  { SetupRandomPalette();                     speed = 50; scale = 50; colorLoop = 1; }
    if( secondHand == 50)  { SetupRandomPalette();                     speed = 90; scale = 90; colorLoop = 1; }
    if( secondHand == 55)  { currentPalette = RainbowStripeColors_p;   speed = 30; scale = 20; colorLoop = 1; }
  }
}

// This function generates a random palette that's a gradient
// between four different colors.  The first is a dim hue, the second is 
// a bright hue, the third is a bright pastel, and the last is 
// another bright hue.  This gives some visual bright/dark variation
// which is more interesting than just a gradient of different hues.
void SetupRandomPalette()
{
  currentPalette = CRGBPalette16( 
                      CHSV( random8(), 255, 32), 
                      CHSV( random8(), 255, 255), 
                      CHSV( random8(), 128, 255), 
                      CHSV( random8(), 255, 255)); 
}

// This function sets up a palette of black and white stripes,
// using code.  Since the palette is effectively an array of
// sixteen CRGB colors, the various fill_* functions can be used
// to set them up.
void SetupBlackAndWhiteStripedPalette()
{
  // 'black out' all 16 palette entries...
  fill_solid( currentPalette, 16, CRGB::Black);
  // and set every fourth one to white.
  currentPalette[0] = CRGB::White;
  currentPalette[4] = CRGB::White;
  currentPalette[8] = CRGB::White;
  currentPalette[12] = CRGB::White;

}

// This function sets up a palette of purple and green stripes.
void SetupPurpleAndGreenPalette()
{
  CRGB purple = CHSV( HUE_PURPLE, 255, 255);
  CRGB green  = CHSV( HUE_GREEN, 255, 255);
  CRGB black  = CRGB::Black;
  
  currentPalette = CRGBPalette16( 
    green,  green,  black,  black,
    purple, purple, black,  black,
    green,  green,  black,  black,
    purple, purple, black,  black );
}


//
// Mark's xy coordinate mapping code.  See the XYMatrix for more information on it.
//
uint16_t XY( uint8_t x, uint8_t y)
{
  uint16_t i;
  if( kMatrixSerpentineLayout == false) {
    i = (y * kMatrixWidth) + x;
  }
  if( kMatrixSerpentineLayout == true) {
    if( y & 0x01) {
      // Odd rows run backwards
      uint8_t reverseX = (kMatrixWidth - 1) - x;
      i = (y * kMatrixWidth) + reverseX;
    } else {
      // Even rows run forwards
      i = (y * kMatrixWidth) + x;
    }
  }
  return i;
}

Liste des composants

  • médium 3mm
  • découpeuse laser
  • stylo 3D
  • film auto-collant
  • matériel de bricolage (visserie, cutter, pic à brochette, colle chaude)
  • servomoteur
  • carte Arduino
  • matériel électronique (breadboard, câbles, résistances, potentiomètre, fer à souder)
  • un ruban de leds
  • module carte SD (optionnel)
  • haut-parleur/speaker (optionnel)

Catégories