Westernduino, arduino Tutoriel Jeu de Tir

Aujourd’hui on attaque un tuto un peu plus complexe, la fabrication d’un Jeu de Tir avec Arduino !

Je me suis lancé un défi en participant au challenge des makers (http://ouiaremakers.com/ ) de fabriquer un jeu et de vous donner les étapes nécessaires à sa réalisation.

Il y à certains composants que j’utilise pour lesquels je n’ai pas encore fait de tuto dessus pour leur fonctionnement mais j’y reviendrai plus tard.

Le niveau en programmation est plus élevé que le tuto du feu tricolore, je vous invite à regarder la vidéo pour comprendre le mécanisme pour vous aussi faire votre jeu à l’aide des instructions.

Timeline 00:36 – 02:32 Matériel , 02:32 – 08:06 Schéma , 08:06 – 27:27 Code explication , 27:07 – 35:29 Montage , 35:29 – 36:38 Démonstration , 36:38 – Fin Partager la vidéo

 

// PIN
int cible0=A0;
int cible1=A1;
int cible2=A2;
int pinServo1 = 5;
int pinServo2 = 6;
int pinServo3 = 7;
int pinBoutonStart = 8;
int pinBuzzer = 9;

// variable moyenne capteur lumiere
int moyennecible0=0;
int moyennecible1=0;
int moyennecible2=0;

// tableau pour savoir quelle cible est levee et peut etre toucher
int cibleCapteur[]={0,0,0};

int i = 0;
int start = 0;

// ronud de jeu tableau multi { temps en ms , numero servo , angle en degre } 15 pour plat et 90 pour levé , ajout valeur hors cadre a la fin
int round1[ ][ 3 ] = { { 1000, 0, 90 }, { 4000, 0, 15 } ,{ 4000, 2, 90 },{ 7000, 2, 15 },{ 7000, 1, 90 },{ 10000, 1, 15 },{ 11000, 0, 90 },{ 11000, 2, 90 },{ 14000, 0, 15 },{ 14000, 2, 15 },{ 15000, 1, 90 },{ 16000, 2, 90 },{ 18000, 1, 15 },{ 19000, 2, 15 },{ 20000, 2, 90 },{ 21000, 1, 90 },{ 22000, 0, 90 },{ 29000, 2, 15 },{ 29000, 1, 15 },{ 29000, 0, 15 },{ 61000, 0, 15 } };
int round2[ ][ 3 ] = { { 1000, 0, 90 },{ 3000, 1, 90 },{ 3000, 0, 15 },{ 5000, 1, 15 },{ 7000, 2, 90 },{ 7000, 0, 90 },{ 10000, 2, 15 },{ 10000, 0, 15 },{ 12000, 1, 90 },{ 13000, 0, 90 },{ 14000, 2, 90 },{ 15000, 1, 15 },{ 16000, 0, 15 },{ 17000, 2, 15 },{ 18000, 2, 90 },{ 19000, 1, 90 },{ 20000, 0, 90 },{ 20000, 2, 15 },{ 21000, 1, 15 },{ 22000, 0, 15 },{ 22000, 1, 90 },{ 23000, 0, 90 },{ 24000, 2, 90 },{ 29000, 0, 15 },{ 29000, 1, 15 },{ 29000, 2, 15 },{ 61000, 0, 15 } };
// temps des round , premier a 0 car se base sur la variable start ( start = 0 a l'init ) 
int tempsRound[]= {0,30000,30000};

// temps et step pour les sequences
long tempsdebut = 0;
long stepSequence = 0;

// points 
int points = 0;
int pointsManche = 0;

#include "pitches.h"
#include < Servo.h >

Servo monServo0;
Servo monServo1;
Servo monServo2;
Servo mesServos[]={monServo0,monServo1,monServo2};

// variable pour jouer les melodies
int numeroMelody = 0;
int numeroNote = 0;
int numeroNoteBefore = 9;
long tempsMelody = 0;
long pauseNotes;
bool boolMelody = 1;

// 2 melodies
int melody[][37] = {{
  NOTE_E4, NOTE_A4, NOTE_E4, NOTE_A4, NOTE_E4, NOTE_C4, NOTE_D4,NOTE_A3 ,0 
  ,NOTE_E4, NOTE_A4, NOTE_E4, NOTE_A4, NOTE_E4, NOTE_C4, NOTE_D4,NOTE_G4,0,
  NOTE_E4,NOTE_A4, NOTE_E4, NOTE_A4,NOTE_A4,NOTE_C5,NOTE_B4,NOTE_A4,NOTE_G4,0 
  ,NOTE_E4, NOTE_A4, NOTE_E4, NOTE_A4, NOTE_E4,0,NOTE_D4,NOTE_A3,NOTE_A3
},
{NOTE_E3,NOTE_A3,NOTE_E4,NOTE_C4,NOTE_G4,NOTE_G4,0}
}
;
// duree des notes des melodies
int noteDurations[][37] = {{
  16, 16, 16, 16, 2, 4, 4, 2,2 ,16, 16, 16, 16, 2, 4, 4, 2,2  ,16, 16, 16, 16,2,4,8,8,2,2,16,16,16,16,4,4,4,8,1
},{8,8,8,8,8,2,999} };

void setup() {

  Serial.begin(9600);
  pinMode(cible0,INPUT);
  pinMode(cible1,INPUT);
  pinMode(cible2,INPUT);  
  pinMode(pinBoutonStart,INPUT);

  // attacher les servos a leur pins
  unlockServos();

  delay(1000);
  // detache les servos de leur pins
  lockServos();

  // initialise les variables moyenne pour les capteur de luminosité
  //initSensorLight();
}

void loop() {

  // demarrer le jeu ?
  if(digitalRead(pinBoutonStart) == HIGH){
    start = 1;
    stopMusique();
    points = 0;

  }

  switch (start) {
    case 1:
    // round 1
        demarrerRound(tempsRound[start],round1);
      break;
    case 2:
    // round 2
        delay(2000);
        demarrerRound(tempsRound[start],round2);
      break;
    default: 
      // joue la melodie toutes les 60 scondes si le jeu n'est pas lancé
      if(millis() > tempsMelody+60000 ){
        numeroMelody=0;
        boolMelody = 1;
        numeroNote = 0;
        numeroNoteBefore = 9;       
      }
      // appelle jouer de la musique     
      jouerMusique();
    break;
  }

}

// initialisation des capteurs de lumiere pour capter le laser en phase de jeu
void initSensorLight(){
  int totalCible=0;
  //for each sensor catch 10 value for better aim
  for (i=0;i<10;i++) {
    totalCible+=analogRead(cible0);
  }
  moyennecible0=totalCible/10;
  totalCible=0;
  //for each sensor catch 10 value for better aim
  for (i=0;i<10;i++) {
    totalCible+=analogRead(cible1);
  }
  moyennecible1=totalCible/10;
  totalCible=0;
  //for each sensor catch 10 value for better aim
  for (i=0;i<10;i++) {
    totalCible+=analogRead(cible2);
  }
  moyennecible2=totalCible/10;
  totalCible=0; 

}

// avant de demarrer le jeu
void preStart(){

  pointsManche = 0;
  initSensorLight();

  Serial.println("3");
  tone(pinBuzzer,NOTE_FS4, 500);
  delay(1000);
  Serial.println("2");
  tone(pinBuzzer,NOTE_FS4, 500);
  delay(1000);
  Serial.println("1");
  tone(pinBuzzer,NOTE_FS4, 500);
  delay(1000);
  tone(pinBuzzer,NOTE_F5, 500);
}

// detacher les servo pour eviter les tremblements
void lockServos(){
  monServo0.detach();
  monServo1.detach();
  monServo2.detach();  
}
// attacher les servo pour les utiliser
void unlockServos(){
  monServo0.attach(pinServo1);
  monServo1.attach(pinServo2);
  monServo2.attach(pinServo3);

  monServo0.write(15);
  monServo1.write(15);
  monServo2.write(15);
}

// affiche le score de la manche( pour la v2 ) et jouer musique
void scoreManche(){

int tempsScore = millis ();
numeroMelody=1;
boolMelody = 1;
numeroNote = 0;
numeroNoteBefore = 9;
while(jouerMusique()== true){

}
// on joue la meoldie fin du stage

  Serial.print("Score Manche ");
  Serial.println(pointsManche);

}

// fonction qui gere les position des cible et les shots, an parametre le temps du round et le tableau des positions des servos 
void demarrerRound(int tempsTempo,int tempoRound[][3]){

      unlockServos();
      preStart();
      tempsdebut=millis();
      stepSequence = 0;
      while((millis()-tempsdebut) < tempsTempo){
        if(( millis() - tempsdebut ) >= tempoRound[ stepSequence ][ 0 ]){   

          mesServos[tempoRound[ stepSequence ][1]].write(tempoRound[ stepSequence ][2]);

          // autoriser un tir sur cible si valeur degré >89 ok pour cible sinon desactivé
          if(tempoRound[ stepSequence ][2]> 89){
            cibleCapteur[tempoRound[ stepSequence ][1]]=1;
          }
          else{
            cibleCapteur[tempoRound[ stepSequence ][1]]=0;
          }

          stepSequence++;
        }

        // sequence pour receptionner les signaux
        if(cibleCapteur[0] == 1 ){
            if(analogRead(cible0)> moyennecible0 + 50){
                monServo0.write(15); 
                pointsManche++;
                  // init cible pour eviter plusieurs tirs et points
                cibleCapteur[0] = 0;
                Serial.println(" Cible 0 Touche");
                tone(pinBuzzer,NOTE_DS8, 500);                
            }
        }

        if(cibleCapteur[1] == 1 ){
            if(analogRead(cible1)> moyennecible1 + 50){
                monServo1.write(15); 
                pointsManche++;
                  // init cible pour eviter plusieurs tirs et points
                cibleCapteur[1] = 0;
                Serial.println(" Cible 1 Touche");
                tone(pinBuzzer,NOTE_DS8, 500); 
            }
        }

        if(cibleCapteur[2] == 1 ){
            if(analogRead(cible2)> moyennecible2 + 50){
                monServo2.write(15); 
                pointsManche++;
                  // init cible pour eviter plusieurs tirs et points
                cibleCapteur[2] = 0;
              Serial.println("Cible 2 Touche");
              tone(pinBuzzer,NOTE_DS8, 500); 
            }
        }

      }

      start++;
      lockServos();
      scoreManche(); 

}

// fonction jouer de la musique pour jouer le theme hors jeu et pendant les phases de score
bool jouerMusique(){

  if( boolMelody == 1 ){

  // depart du temps de reference de la melodie au temps 0
        if(numeroNote == 0){
          tempsMelody=millis();
        }

          // durée de la note en cours
        int noteDuration = 1000 / noteDurations[numeroMelody][numeroNote];

        if(numeroNote != numeroNoteBefore){
            numeroNoteBefore=numeroNote;     
            tone(pinBuzzer, melody[numeroMelody][numeroNote], noteDuration);

        // ici on calcule le temps qu'il faut avant de passer a la step suivante ( note suivante )
        pauseNotes = (noteDuration * 1.30) ;
        pauseNotes+=tempsMelody;

        }

        if(millis() >= pauseNotes){
            numeroNote+=1;
            tempsMelody=millis();
        }
        if(numeroNote >= (sizeof(noteDurations[numeroMelody])/sizeof(int)) || noteDurations[numeroMelody][numeroNote] == 999 ){
           boolMelody = 0;
           numeroNote = 0;
           numeroMelody = 0;
           numeroNoteBefore = 9;
           noTone(pinBuzzer);
           return false;
        }
  }  
  return true;
}

// arrete la musique
void stopMusique(){
  boolMelody = 0;
  numeroNote = 0;
  numeroMelody = 0;
}

En matériel il nous faut :

– 2 arduino ( ici des mini pro 5v)

– 3 régulateurs de tension 5 V L7805

– 6 condensateurs 25v 10μF

– 1 condensateur 16V 470μF

– 3 résistances 1kΩ

– 3 résistances 220Ω

– 3 photorésistances

– 2 boutons

– 3 servo 9g S90

– 1 buzzer ( option )

– 1 transistor TIP120

– 1 module laser 5V

– 1 transformateur 12V

– 1 pile 9v et de quoi la connecter

– des fils de couleurs

Niveau câblage partie cibles

– A0 A1 A2 câblé sur les différentes photos résistances

– 5,6,7 câblé sur les 3 servo

– 8 câblé sur le bouton Start

– 9 câblé sur le buzzer

Partie pistolet

– 3 câblé sur le bouton de tir

– 4 câblé sur le transistor tip120 pour activer le laser

Je passe aux explications de câblage partie cibles.

Commençons par la partie alimentation, on reçoit ici du 12V avec un transformateur ( 1A minimum voir 2A quand on ajoutera de l’affichage pour la V2).

On transforme notre 12V en 5v avec nos régulateurs de tension L7805, j’en ai mis 2 car les servo demandent pas mal de puissance et donc chauffent beaucoup (je rajouterai sûrement des radiateurs plus tard dessus).

En vue de face la borne de gauche du régulateur récupère le 12V+ , le centre la masse et à droite le 5V+ , on y ajoute 2 condensateurs 25v 10μF pour lisser la tension.

Ensuite entre le 5V et la masse j’ai un condensateur pour les servo pour réguler les pics de tension lors de leurs utilisations.

Les bornes des servo son chacunes branchées sur le 5V et la masse.

J’ai un petit montage pull down pour mon bouton start, une résistance 1kΩ entre la masse et le bouton qui est aussi relié au pin 8 et l’autre côté du bouton est relié au 5V

Mon buzzer relié entre la masse et le pin 9 de l’arduino.

Et mes photorésistances relié au 5v d’un côté et de l’autre aux pin A0,A1,A2 ; chaque photo résistance sont reliées à la masse avec une résistance de 220Ω.

Et je n’oublie pas de relier l’arduino au 5V.

ATTENTION les arduino mini pro sont 5v ou 3.3V et ils n’ont pas d’entrée Vin donc on doit obligatoirement leur fournir la tension nécessaire ici 5V !

Le câblage du pistolet fonctionne sur le même principe niveau régulateur de tension, 5V en sortie.

Montage pull down pour le bouton de tir comme pour le bouton start mais ici pin 3 sur l’arduino.

Sur le pin 4 on connecte une résistance 1kΩ relié a la borne de gauche du transistor TIP120, la borne du millieu relié a la masse du laser et borne de droite a la masse du circuit et je n’oublie pas de relier le fil positif du laser au 5V.

On passe par l’explication du code !

Codes des cibles (à droite )

Au début de mon programme je défini mes pin avec les cibles ,servo bouton et buzzer (j’aurai du définir mes pin avec des #define et pas des int, cela prends moins de place, mais cela fonctionne quand même).

Des variables de moyenne pour mes photorésistances, un tableau pour contrôler quelle cible est levée et d’autres petites variables.

Les round sont les tableaux qui contiennent les ordres des servos et des séquences de jeu.

Trois informations à l’intérieur , le temps en ms , le numéro du servo et l’angle à atteindre.

La variable tempsRound contient la durée du round du jeu.

Encore 2 variable de temps et séquence pour le jeu.

Les points du jeu qui ne sont pas utilisé ici ( pour la v2 oui ) mais comptés quand même.

On inclus une bibliothèque pour les notes du buzzer et les commandes servo

J’appelle mes servo et je les insères dans un tableau.

J’ai ensuite mes différentes variables pour jouer des mélodies, puis des tableaux contenant actuellement 2 mélodies et un tableau contenant le temps des notes.

Partie setup ou j’ai activé le serial pour contrôler quelques informations et je défini mes pin en entrée.

J’ai une fonction unlockServos pour attacher mes servo et les positionner en position basse.

LockServos détache les servo pour éviter que les perturbations électrique fasse bouger les servos.

initSensorLight ici est commenté dans le setup car on l’utilise à chaque démarrage de round de jeu.

Partie loop je contrôle l’état du bouton start pour démarrer le jeu si il est à l’état HIGH et je défini start a 1, les points a 0 et j’arrête la musique si elle est en cours.

On continue avec un switch pour aiguiller le jeu, pour start égal a 1 on démarre le round1, même chose pour le 2 round2 et j’ai mon cas de défaut ou je joue la musique et je relance la musique toutes les 60 secondes si aucun round n’est choisi.

Venons en a nos fonctions , initSensorLight  sert à faire une moyenne sur nos photorésistances , on récupère 10 valeurs sur chaque photorésistance et on fait sa moyenne pour mieux détecter les variations de chaque capteur qui peut être différent.

La fonction preStart remet à 0 les point de la manche , appelle initSensorLight et fait un décompte avant de lancer la séquence de round.

Autre fonction scoreManche pour terminer la séquence de jeu avec une mélodie et l’affichage des score en V2.

Notre fonction demarrerRound est la plus importante car elle gère la séquence de jeu, en argument on a le temps du jeu et la séquence de jeu.

Je débloque les servo avec unlockServos puis un preStart pour lancer le décompte.

J’ai une boucle qui va tourner tant que le temps n’est pas écoulé et je vais activer mes actions au fur et à mesure de l’avancement du temps et faire bouger mes servos; j’autorise mes cibles quand elles montent pour que l’on puisse tirer dessus.

Puis j’ai mes différents contrôle des cibles quand elles sont activées je vérifie si leurs valeurs est supérieures à 50 par rapport a leur moyenne.

Si une cible est touchée elle redescend, un bip retenti et je compte 1 point.

Hors de ma boucle de temps on incrémente la valeur de start pour passer à la séquence de jeu suivante, je bloque mes servos et j’appelle scoreManche.

Encore une fonction cette fois ci pour jouer de la musique , jouerMusique lui retourne une valeur , true ou false pour me prévenir quand la musique est terminée.

boolMelody permet de lire la musique ou non , je récupère la durée de note de la melodie sélectionnée, je contrôle que je ne joue pas 2 fois la même note ( car ici je ne bloque pas mon arduino pendant le temps d’attente ). Je calcule mes temps de pause entre les notes et je progresse dans la mélodie suivant le temps .

A la fin si j’arrive au bout de mon tableau ou que une durée de note est égal a 999 alors je pourrai terminer la mélodie.

Et dernière fonction pour arrêter la musique avec stopMusique.

Code du pistolet (en dessous)

Idem que pour les cible on initialise les pin nécessaires pour notre arduino, le bouton pour tirer et la commande du laser.

Aprés quelques variables pour notre programme pour éviter que le laser soit constamment allumé shootLaser et multiShoot.

Deux variable de temps pour séquencer le laser avec tempsLaser et tempsPause.

Partie setup on initialise le pin du bouton en INPUT et le laser en OUTPUT.

Dans mon loop j’ai une condition qui contrôle que le bouton est appuyé et que multiShoot est supérieur à 2 car dans ma condition quand mon bouton est a l’état bas d’incrémente multishoot ( on doit passer pas l’état bas au moins 3 itérations pour pouvoir retirer ).

Puis dernière condition qui nous permet d’activer le laser, allume le laser un temps, puis l’éteint.

 

int pinBouton = 3;
int pinLaser = 4;

bool shootLaser = 0;
int multiShoot = 2;

long tempsLaser = 500;
long tempsPause = 100 ;

void setup() {
  pinMode(pinBouton,INPUT);
  pinMode(pinLaser,OUTPUT);
}

void loop() {
  if(digitalRead(pinBouton) == HIGH && multiShoot > 2){
    shootLaser = 1;
    multiShoot = 0;
  }
  else if(digitalRead(pinBouton) == LOW){
    shootLaser = 0;
    if(multiShoot < 3 ){
      multiShoot++;
    }
  }

  if(shootLaser == 1 ){
    digitalWrite(pinLaser,HIGH);
    delay(tempsLaser);
    digitalWrite(pinLaser,LOW);
    delay(tempsPause); 
    multiShoot = 0;
    shootLaser = 0;
  }

}

 

J’en ai terminé avec le fonctionnement du programme, c’est assez lourd à expliquer mais j’espère que vous avez compris l’essentiel.

Je vous met le code à télécharger pour réaliser votre jeu, vous allez pouvoir rajouter des niveaux, les modifier et faire ce que vous voulez avec.

Télécharger les codesWesternduino_V1

La fabrication :

Pour le support des cibles j’ai construit le base en bois de taille 50cm de long sur lesquels j’ai collé au pistolet à colle mes servo.

Pour lever les cibles j’ai utilisé des bâtons de glaces sur lesquels j’ai collé mes photorésistances; le tout est démontable ou non.

Et pour les cibles j’ai utilisé du carton plume sur lequel j’ai collé ce que je souhaite et j’ai découpé tout cela, j’ai crée 2 points d’encrage pour les bâtonnets de glace et c’est parti.

Je referai toute la structure pour que ce soit joli et pratique à utiliser dans une version 2.

Télécharger les cowboys :

Niveau pistolet j’ai acheté un pistolet que j’ai trouvé dans une boutique de déguisement, j’ai cherché un pistolet assez grand et vide a l’intérieur pour un mettre l’électronique.

Si tu souhaites réaliser ce même jeu libre à toi de trouver les matériaux nécessaires, on peut trouver différentes manières de fabriquer ce jeu.

Maintenant c’est à ton tour, partagez vos création de jeu de tir avec le hashtag #retroetgeek #westernduino et fais profiter la communauté .

Si tu pense que cette vidéo et tuto peut intéresser quelqu’un n’hésite pas à la partager, j’ai passé pas mal de temps à construire ce tuto autant que cela serve à un maximum de maker.

C’était ma contribution au challenge des makers pour ouiaremakers.com bonne chance à tous les participantes et participants.

N’hésitez pas à poser vos questions sur les réseaux sociaux de la chaîne instagramtwitter , facebook ,youtube ; si vous ne comprenez pas certaines parties du tutoriel, me dire ce que vous aimeriez que je crée pour en faire des vidéos tutoriel ,à partager les projets que vous aimeriez créer etc…

Comme toujours allez sur la page de C’est quoi Retro et Geek pour connaître tout ce que je recherche à faire sur la chaîne.

Merci les RetroGeeker et RetroGeekeuse