Arduino, Tutoriels

Comment construire un Plateau tournant pour Photographies à 360°

Comment construire un Plateau tournant pour Photographies à 360°
Plateau tournant pour Photographies à 360°

Introduction

Plateau tournant pour Photographies à 360° offrent une expérience interactive captivante, permettant aux utilisateurs d’explorer un objet sous tous les angles. Pour réaliser des images de haute qualité dans ce format. Dans cet article, nous allons vous guider à travers le processus de construction de cet appareil en mettant l’accent sur les aspects mécaniques, les matériaux et les outils nécessaires, les composants électroniques, le câblage et l’explication du code.

Caractéristiques du Plateau tournant pour Photographies à 360°

  1. Arrêt automatique et déclenchement de la caméra à chaque angle prédéfini.
  2. Contrôle précis de la vitesse et des angles grâce au moteur pas à pas.
  3. Utilisation d’une LED infrarouge pour le déclenchement sans fil de la caméra.
  4. Intégration d’un encodeur rotatif pour une navigation facile dans le menu.
  5. Possibilité de connecter un module Wi-Fi pour un contrôle sans fil et un tableau de bord IoT.

Matériel et outils nécessaire pour construire un Plateau tournant pour Photographies à 360°

  • Plexiglas :
    • Plateau rond
    • Les engrenages
    • Boîtier de base
  • Moteur pas à pas Nema 23
  • Pilote TB6600 pour moteur pas à pas
  • Transistor NPN BC337
  • Encodeur rotatif KY-40
  • Écran LCD 16×2 avec affichage I2C
  • LED infrarouge (IR)
  • Résistance de 470 ohms
  • Fils de raccordement et connecteurs
  • Outils de découpe (scie sauteuse ou découpe laser)
  • Perceuse et forets
  • Colle acrylique ou solvant acrylique (comme le chlorure de méthylène)
  • Vis, écrous et inserts filetés
Comment construire un Plateau tournant pour Photographies à 360°

Mécanique du Plateau tournant pour Photographies à 360°

La mécanique de notre Plateau tournant pour Photographies à 360° repose sur des éléments clés tels que le plateau rond, les engrenages et le boîtier de base. Nous avons opté pour des pièces en Plexiglas pour leur résistance, leur transparence et leur facilité de découpe. Voici les détails sur ces éléments mécaniques :

Plateau Rond

Le plateau rond constitue la base de notre Plateau tournant. Nous avons choisi une plaque en Plexiglas d’une épaisseur de 10 mm pour assurer sa solidité et sa stabilité. La taille du plateau est environ 40cm.

Engrenages

Les engrenages sont essentiels pour la rotation du plateau. Nous avons utilisé des engrenages en Plexiglas d’une épaisseur de 8 mm. Assurez-vous que les engrenages s’engrènent correctement avec l’arbre du moteur et assurent une rotation fluide.

Boîtier de Base

Le boîtier de base abrite les composants électroniques et offre une structure solide à notre Turntable Automatique. Nous avons utilisé du Plexiglas d’une taille de 40x25cm. Veillez à laisser suffisamment d’espace pour le montage et le câblage de ces composants.

Le role de chaque composants

  1. Moteur pas à pas Nema 23 : Entraîne la rotation du plateau en fonction des angles et de la vitesse, permettant une capture précise des images à 360 degrés. La programmation simple du moteur pas à pas facilite son utilisation et garantit des mouvements fluides.
  2. LED infrarouge : Envoie des signaux infrarouges pour déclencher sans fil la caméra à chaque angle prédéfini. Elle permet une synchronisation parfaite entre la rotation du plateau et la capture des images.
  3. Encodeur rotatif : Contrôle la navigation dans le menu du plateau tournant, offrant une interface conviviale pour ajuster les paramètres tels que la vitesse de rotation et les angles d’arrêt. Il permet une sélection facile des options et une navigation précise.
  4. Afficheur LCD 1602 avec I2C : Permet une visualisation claire des paramètres et des informations importantes, facilitant ainsi l’ajustement des réglages du plateau tournant.
  5. Module Wi-Fi (en option) : Permet de connecter le plateau tournant à un réseau sans fil et de créer un tableau de bord IoT pour un contrôle à distance. Il offre une flexibilité accrue et une gestion pratique des fonctionnalités du plateau tournant.

TB6600 Driver moteur pas à pas et le transistor NPN BC337 complètent les autres composants en fournissant un contrôle précis du moteur pas à pas et de la LED infrarouge, respectivement.

Plateau tournant pour Photographies à 360°

Câblage

Encodeur rotatif KY-40

  • Connectez la broche CLK de l’encodeur rotatif KY-40 à la broche 2 de l’Arduino Uno.
  • Connectez la broche DT de l’encodeur rotatif KY-40 au broche 4 de l’Arduino Uno.
  • Connectez la broche SW de l’encodeur rotatif KY-40 au broche 5 de l’Arduino Uno.
  • Connectez la broche + de l’encodeur rotatif KY-40 à la broche 5V de l’Arduino Uno.
  • Connectez la broche GND de l’encodeur rotatif KY-40 à la broche de masse (GND) de l’Arduino Uno.

Transistor NPN BC337

  • Connectez la broche collecteur (C) du transistor BC337 à la borne GND de la LED .
  • Connectez une résistance de 470 ohms entre la broche base (B) du transistor BC337 et la broche 3 de l’Arduino Uno.
  • Connectez la broche émetteur (E) du transistor BC337 à la broche de masse (GND) de l’Arduino Uno.

Écran LCD 16×2 avec affichage I2C

  • Connectez la broche SDA de l’écran LCD 16×2 avec affichage I2C à la broche A4 (SDA) de l’Arduino Uno.
  • Connectez la broche SCL de l’écran LCD 16×2 avec affichage I2C à la broche A5 (SCL) de l’Arduino Uno.
  • Connectez la broche VCC de l’écran LCD 16×2 avec affichage I2C à la broche 5V de l’Arduino Uno.
  • Connectez la broche GND de l’écran LCD 16×2 avec affichage I2C à la broche de masse (GND) de l’Arduino Uno.

LED infrarouge

  • Connectez la patte la plus longue (anode) de la LED infrarouge à une résistance de limitation de courant, telle qu’une résistance de 220 ohms.
  • Connectez l’autre extrémité de la résistance à une broche de sortie numérique de l’Arduino Uno.
  • Connectez la patte la plus courte (cathode) de la LED infrarouge à la broche de masse (GND) de l’Arduino Uno.
Plateau tournant pour Photographies à 360°


Moteur pas à pas Nema 23

  • Connectez le fil A+ du moteur pas à pas Nema 23 à la sortie A+ du driver de moteur pas à pas TB6600.
  • Connectez le fil A- du moteur pas à pas à la sortie A- du driver TB6600.
  • Connectez le fil B+ du moteur pas à pas à la sortie B+ du TB6600.
  • Connectez le fil B- du moteur pas à pas à la sortie B- du driver de moteur pas à pas .

Pilote de moteur pas à pas TB6600

  • Connectez la broche ENA+ , DIR+ et PUL+ au +5V de l’Arduino.
  • Ne connectez pas la broche ENA-.
  • Connectez la broche DIR- à la broche 9 de l’Arduino.
  • Connectez la broche PUL- à la broche 8 de l’Arduino.
  • Connectez les broches A+ et A- du pilote de moteur pas à pas TB6600 aux fils correspondants du moteur pas à pas Nema 23.
  • Connectez les broches B+ et B- du pilote de moteur pas à pas TB6600 aux fils correspondants du moteur pas à pas Nema 23.

Pour alimenter les composants qui ne peuvent pas être alimentés directement par l’Arduino Uno, tels que le moteur pas à pas Nema 23 et le pilote de moteur pas à pas TB6600, vous devrez connecter une alimentation séparée de 12V 3A. Voici comment procéder :

  • Connectez la borne positive de l’alimentation 12V 3A à l’entrée VCC du pilote de moteur pas à pas TB6600.
  • Connectez la borne négative de l’alimentation à l’entrée GND du pilote de moteur pas à pas TB6600.
  • Assurez-vous que l’alimentation est capable de fournir la tension et le courant requis pour que le moteur pas à pas Nema 23 et le pilote de moteur pas à pas TB6600 fonctionnent correctement.
Plateau tournant pour Photographies à 360°

Code

// Include Libraries
#include "Arduino.h"
#include "LiquidCrystal_PCF8574.h"
#include "IRremote.h"
#include "Encoder.h"
#include "Button.h"
#include "math.h"

// Pin Definitions
#define RotaryEncoder_PIN_D	4
#define RotaryEncoder_PIN_CLK	2
#define RotaryEncoder_PIN_S1	5
#define STEPPER_PIN_STEP	6
#define STEPPER_PIN_DIR	7

#define SLOW 5000
#define FAST 500

// set default parameters
int speed = 100;
int angles = 4;
const int fullRotation = 18300;

// Global variables and defines
// There are several different versions of the LCD I2C adapter, each might have a different address.
// Try the given addresses by Un/commenting the following rows until LCD works follow the serial monitor prints.
// To find your LCD address go to: http://playground.arduino.cc/Main/I2cScanner and run example.
#define LCD_ADDRESS 0x3F
//#define LCD_ADDRESS 0x27

// Define LCD characteristics
#define LCD_ROWS 2
#define LCD_COLUMNS 16
#define SCROLL_DELAY 150
#define BACKLIGHT 255
long rotaryEncDOldPosition  = 0;
// object initialization
Encoder rotaryEncD(RotaryEncoder_PIN_D, RotaryEncoder_PIN_CLK);
Button rotaryEncDButton(RotaryEncoder_PIN_S1);
LiquidCrystal_PCF8574 lcdI2C;
IRsend ir_led;

enum menuState {HOME, VIDEO, STILLS, VIDSTART, STILSTART, SPEED, ANGLES, VIDBACK, STILBACK, CHANGESPEED, CHANGEANGLES} state = VIDEO, oldState = 10;

// Setup the essentials for your circuit to work. It runs first every time your circuit is powered with electricity.
void setup()
{
  // Setup Serial which is useful for debugging
  // Use the Serial Monitor to view printed messages
  Serial.begin(9600);
  while (!Serial) ; // wait for serial port to connect. Needed for native USB
  Serial.println("start");

  // initialize the lcd
  lcdI2C.begin(LCD_COLUMNS, LCD_ROWS, LCD_ADDRESS, BACKLIGHT);
  rotaryEncDButton.init();
  pinMode(RotaryEncoder_PIN_S1, INPUT_PULLUP);

  lcdI2C.print("PHOTO BOOTH");
  delay(500);
  lcdI2C.print("");

  pinMode(STEPPER_PIN_STEP, OUTPUT);
}

// Main logic of your circuit. It defines the interaction between the components you selected. After setup, it runs over and over again, in an eternal loop.
void loop()
{
  //Read encoder new position
  long rotaryEncDNewPosition = rotaryEncD.read() / 2;
  bool select = rotaryEncDButton.onPress();
  char menuDir = ' ';
  if (rotaryEncDNewPosition != rotaryEncDOldPosition) {
    //Serial.println(rotaryEncDNewPosition);
    if (rotaryEncDNewPosition < rotaryEncDOldPosition)
    {
      menuDir = 'L';
    }
    else if (rotaryEncDNewPosition >= rotaryEncDOldPosition)
    {
      menuDir = 'R';
    }
    rotaryEncDOldPosition = rotaryEncDNewPosition;
  }

  if (state != oldState)
  {
    lcdI2C.clear();

    oldState = state;
  }


  lcdI2C.selectLine(1);
  lcdI2C.print(printState(state));

  switch (state)
  {
    case VIDEO:
      if (menuDir == 'L' || menuDir == 'R')
        state = STILLS;

      if (select)
        state = VIDSTART ;

      break;

    case STILLS:
      if (menuDir == 'L' || menuDir == 'R')
        state = VIDEO;

      if (select)
        state = STILSTART;

      break;

    case VIDSTART:
      if (menuDir == 'R')
        state = SPEED;

      else if (menuDir == 'L')
        state = VIDBACK;

      if (select) {
        video();

      }
      break;

    case SPEED:
      if (menuDir == 'L')
        state = VIDSTART;

      else if (menuDir == 'R')
        state = VIDBACK;

      if (select)

        state = CHANGESPEED;

      break;

    case CHANGESPEED:
      if (menuDir == 'L')
      {
        speed-=5;
        lcdI2C.selectLine(2);
        lcdI2C.print("     ");
      }
      else if (menuDir == 'R')
      {
        speed+=5;
        lcdI2C.selectLine(2);
        lcdI2C.print("     ");
      }
      speed=constrain(speed,0,100);
      lcdI2C.selectLine(2);
      lcdI2C.print(speed);
      lcdI2C.print("%");


      if (select)
        state = VIDSTART;

      break;
    case VIDBACK:
      if (menuDir == 'L')
        state = SPEED;

      else if (menuDir == 'R')
        state = VIDSTART;


      if (select)
        state = VIDEO;

      break;


    case STILSTART:
      if (menuDir == 'R')
        state = ANGLES;

      else if (menuDir == 'L')
        state = STILBACK;

      if (select)
        stills();
      break;

    case ANGLES:
      if (menuDir == 'L')
        state = STILSTART;

      else if (menuDir == 'R')
        state = STILBACK;


      if (select)
        state = CHANGEANGLES;

      break;

    case CHANGEANGLES:
      if (menuDir == 'L')
      {
        angles--;
        lcdI2C.selectLine(2);
        lcdI2C.print("     ");
      }
      else if (menuDir == 'R')
      {
        angles++;
        lcdI2C.selectLine(2);
        lcdI2C.print("     ");
      }

      lcdI2C.selectLine(2);
      lcdI2C.print(angles);

      if (select)
        state = STILSTART;
      break;

    case STILBACK:
      if (menuDir == 'L')
        state = ANGLES;

      else if (menuDir == 'R')
        state = STILSTART;

      if (select)
        state = STILLS;
      break;
  }




}

String printState(int curstate)
{
  switch (curstate) {
    case 0:
      return "HOME";
    case 1:
      return "VIDEO";
    case 2:
      return "STILLS";
    case 3:
      return "VIDEO START";
    case 4:
      return "STILLS START";
    case 5:
      return "SET SPEED";
    case 6:
      return "SET ANGLES";
    case 7:
      return "BACK";
    case 8:
      return "BACK";
    case 9:
      return "SET SPEED:";
    case 10:
      return "SET ANGLES:";
  }

}


void stills() {

  for (int i = 0 ; i < angles ; i++) {
    delay(300);
    irStillsShot();
    delay(750);
    int delay_time = SLOW;
    int numOfSteps = fullRotation / angles;
    float accSteps = 600;
    for (int i = 0; i < numOfSteps; i++ )
    {

      if (i < accSteps)
      {
        delay_time = (SLOW - FAST) * pow(float(i - accSteps), 2) / float(accSteps * accSteps) + FAST;
      }
      else if (i > numOfSteps - accSteps)
      {
        delay_time = (SLOW - FAST) * pow(float(i - numOfSteps + accSteps), 2) / float(accSteps * accSteps) + FAST;
      }
      else
      {
        delay_time = FAST;
      }

      digitalWrite(STEPPER_PIN_STEP, HIGH);   // turn the LED on (HIGH is the voltage level)
      delayMicroseconds(delay_time);                       // wait for a second
      digitalWrite(STEPPER_PIN_STEP, LOW);    // turn the LED off by making the voltage LOW
      delayMicroseconds(delay_time);                       // wait for a second

    }
  }
}


void video() {
  delay(300);
  irVideoShot();
  delay(750);
  int delay_time = SLOW;
  int fast = 300 + 12*(100-speed);
  int numOfSteps = fullRotation;
  float accSteps = 600;
  for (int i = 0; i < numOfSteps; i++ )
  {

    if (i < accSteps)
    {
      delay_time = (SLOW - fast) * pow(float(i - accSteps), 2) / float(accSteps * accSteps) + fast;
    }
    else if (i > numOfSteps - accSteps)
    {
      delay_time = (SLOW - fast) * pow(float(i - numOfSteps + accSteps), 2) / float(accSteps * accSteps) + fast;
    }
    else
    {
      delay_time = fast;
    }
    digitalWrite(STEPPER_PIN_STEP, HIGH);   // turn the LED on (HIGH is the voltage level)
    delayMicroseconds(delay_time);                       // wait for a second
    digitalWrite(STEPPER_PIN_STEP, LOW);    // turn the LED off by making the voltage LOW
    delayMicroseconds(delay_time);                       // wait for a second
  }
  delay(750);
  irVideoShot();
  delay(500);

}





void irVideoShot() {
  int khz = 33; // 33kHz frequency
  unsigned int irSignal[] = {488};
  ir_led.sendRaw(irSignal, sizeof(irSignal) / size of(irSignal[0]), khz);
  delayMicroseconds(5360);
  ir_led.sendRaw(irSignal, sizeof(irSignal) / size of(irSignal[0]), khz);
}

void irStillsShot() {
  int khz = 33; // 33kHz frequency
  unsigned int irSignal[] = {480};
  ir_led.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz);
  delayMicroseconds(7330);
  ir_led.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz);
}

Explication du code

Le code que nous utilisons implémente un menu de base à l’aide de l’écran LCD 16×2 et de l’encodeur rotatif avec un bouton poussoir intégré.

Dans le fichier Firmware.ino, vous trouverez :

  • Les déclarations de broches
  • Les réglages des composants
  • Les constructeurs
  • La fonction setup() fournie par circuito.io

La fonction loop() commence par la lecture de l’état de l’encodeur rotatif (gauche ou droite) et de son bouton.

Le menu est implémenté à l’aide d’une machine à états finis basée sur une structure switch-case, permettant de naviguer entre les différents états :

  • HOME : mode d’attente
  • VIDEO : mode vidéo
  • STILLS : mode photos
  • Vous pouvez basculer entre les états en utilisant la rotation de l’encodeur.
  • Vous pouvez sélectionner un état en appuyant sur le bouton.

Les deux états : SPEED (vitesse) et ANGLES (angles) vous permettent de modifier les variables responsables du nombre de points d’arrêt en mode photos et de la vitesse de rotation en mode vidéo.

VIDSTART (démarrage vidéo) – appelle la fonction video() :

  • Envoie le code infrarouge de démarrage d’enregistrement à la caméra en utilisant la LED infrarouge.
  • Démarre la rotation du plateau à la vitesse choisie pour une rotation complète.
  • Envoie le code infrarouge d’arrêt d’enregistrement à la caméra en utilisant la LED infrarouge.
  • Note : Pour un démarrage et un arrêt en douceur du plateau, nous avons mis en place une accélération et une décélération cubiques sur les 600 premiers et derniers pas.

STILSTART (démarrage photo) – appelle la fonction stills() :

  • Divise une rotation complète par le nombre d’angles définis.
  • Pour chaque angle, envoie le code infrarouge d’une seule photo à la caméra en utilisant la LED infrarouge.
  • Démarre la rotation du plateau jusqu’à atteindre le prochain angle.
  • Note : Pour un démarrage et un arrêt en douceur du plateau, nous avons mis en place une accélération et une décélération cubiques sur les 600 premiers et derniers pas.

Le code fournit un contrôle complet de notre Turntable Automatique, permettant de réaliser des photographies à 360 degrés et des vidéos avec facilité.

Video descriptif du tutoriel Plateau tournant pour Photographies à 360°

Lien outilles

Code du control IR sans fil du camera Canon : https://github.com/urbanij/IR-remote-Canon

Pour découvrir plus de tutoriel, vous pouvez consulter notre bloc : https://www.moussasoft.com/tutoriels-electroniques

Twitter: Moussa Lhoussaine (@Moussasoft_com) / Twitter