Exemple: Pachislot

Base de départ pour un pachislot ou un bandit manchot. Il y a 3 moteurs représentant trois tambours. Chaque tambour est censé avoir 4 images. Un poussoir permet de lancer les 3 moteurs et de les arrêter un par un. Le logiciel reconnaît en direct la face du "tambour".

Liens

Pour faire fonctionner cet exemple, il faut soit télécharger QuickStepExemples.zip contenant tous les fichiers d'exemples, soit télécharger Pachislot.zip contenant cet exemple, soit créer un répertoire du nom de l'exemple et mettre dedans:
- le fichier Pachislot.ino de l'exemple
- le fichier de configuration QuickStepConf.h propre à cet exemple
- les trois fichiers (QuickStep.h, QuickStep.cpp et digitalWriteFast.h) pour avoir la bibliothèque (identiques pour toutes les applications)

QuickStepConf.h (extrait)

// Moteur hybride 200 pas/tr 16 µpas
#define UN_TOUR_X (200L*16) pas_ou_micro_pas
#define VITESSE_MAXI_X 8.0 RPS
#define STEP_X 2
#define DIR_X 5
#define ENABLE_X 8 // N° de la broche pour ENABLE. Si on la veut à l'état bas
#define NB_ORDRES_DANS_LA_PILE_X 31
#define NB_ORDRES_ACCELERATION_X 16

// Moteur hybride 200 pas/tr 8 µpas
#define UN_TOUR_Y (200L*8) pas_ou_micro_pas
#define VITESSE_MAXI_Y 8.0 RPS
#define STEP_Y 3
#define DIR_Y 6
#define NB_ORDRES_DANS_LA_PILE_Y 31
#define NB_ORDRES_ACCELERATION_Y 16

// Moteur hybride 200 pas/tr mode pas
#define UN_TOUR_Z 200L pas_ou_micro_pas
#define VITESSE_MAXI_Z 4.0 RPS
#define STEP_Z 12
#define DIR_Z 13
#define NB_ORDRES_DANS_LA_PILE_Z 31
#define NB_ORDRES_ACCELERATION_Z 16

Les trois moteurs ne sont pas gérés de la même façon pour montrer que l'on peut sans problème avoir des nombres de pas par tour ou des vitesses différentes sans aucun problème.

Vu les vitesses de rotation, il est nécessaire d'utiliser les comptage des pas sur 32 bits. Le premier moteur pourrait tourner pendant presque 24h sans perdre le comptage. Pour aller au dela, il faudrait de temps en temps rajouter une ligne comme:

quickStepSetPositionX(quickStepGetPositionX() % UN_TOUR_X);

Cette ligne doit être faite à l'arrêt car entre les deux appels à aux eux fonctions, le moteur peut éventuellement progresser.

Pachislot.ino

#
  $menu = ":QS";
  include "QuickStep.h"

//###########################################################################
//                          Constantes et variables                        ##
//###########################################################################

#define nombreDeFaces 4
const uint8_t bouton = 11; // Branchement du bouton
#define APPUYE LOW // Quand on appui sur le bouton, on a un état LOW



//###########################################################################
//                                   setup                                 ##
//###########################################################################
void setup()
{
  Serial.begin(115200);
  quickStepInit();
  pinMode(bouton, INPUT_PULLUP);
  // Ici positionnement de la face 0. Fait à la main dans la démo
}



//###########################################################################
//                                 affichage                               ##+-
//###########################################################################

word passages;
void affichage(void)
{
  if ((passages & 63) != 0) return; // Affichage une fois sur 64
  // Position du moteur X
  Serial.print(F("On est sur les faces "));
  Serial.print((quickStepGetPositionX() % UN_TOUR_X) / (UN_TOUR_X / nombreDeFaces));

  // Position du moteur Y
  Serial.print(F(" "));
  Serial.print((quickStepGetPositionY() % UN_TOUR_Y) / (UN_TOUR_Y / nombreDeFaces));

  // Position du moteur Z
  Serial.print(F(" "));
  Serial.println((quickStepGetPositionZ() % UN_TOUR_Z) / (UN_TOUR_Z / nombreDeFaces));
}



//###########################################################################
//                                    loop                                 ##
//###########################################################################

void loop()
{ 
  // Serial.println(F("Attente du relâchement du bouton au cas où"));
  do affichage(); while (digitalRead(bouton) == APPUYE);
  delay(100); // Anti-rebond

  // Serial.println(F("Attente de l'appui de démarrage"));
  while (digitalRead(bouton) != APPUYE); // Etape d'attente, o n'affiche rien car rien n'évolue


  // Ici, le bouton vient d'être appuyé pour indiquer le lancement des roues


  // Serial.println(F("Démarrage de tous les moteurs: 1 tour pour accélérer, rotation infinie"));
  quickStepRotationX(2*UN_TOUR_X, VITESSE_MAXI_X, acceleration_sur 2*UN_TOUR_X);
  quickStepRotationY(2*UN_TOUR_Y, VITESSE_MAXI_Y, acceleration_sur 2*UN_TOUR_Y);
  quickStepRotationZ(2*UN_TOUR_Z, VITESSE_MAXI_Z, acceleration_sur 2*UN_TOUR_Z);
  delay(100); // Anti-rebond


  // Serial.println(F("Attente du relâchement du bouton"));
  while (digitalRead(bouton) == APPUYE)
  {
    // Progression d'une face; en mémoire progression d'une ou deux faces. 
    if (quickStepResteX() < 5) quickStepRotationX(UN_TOUR_X / nombreDeFaces, VITESSE_MAXI_X);
    if (quickStepResteY() < 5) quickStepRotationY(UN_TOUR_Y / nombreDeFaces, VITESSE_MAXI_Y);
    if (quickStepResteZ() < 5) quickStepRotationZ(UN_TOUR_Z / nombreDeFaces, VITESSE_MAXI_Z);
    affichage();
  }
  delay(100); // Anti-rebond

  // Serial.println(F("Attente de l'ordre d'arrêt du premier moteur"));
  while (digitalRead(bouton) != APPUYE)
  {
    // Progression d'une face; en mémoire progression d'une ou deux faces. 
    if (quickStepResteX() < 5) quickStepRotationX(UN_TOUR_X / nombreDeFaces, VITESSE_MAXI_X);
    if (quickStepResteY() < 5) quickStepRotationY(UN_TOUR_Y / nombreDeFaces, VITESSE_MAXI_Y);
    if (quickStepResteZ() < 5) quickStepRotationZ(UN_TOUR_Z / nombreDeFaces, VITESSE_MAXI_Z);
    affichage();
  }
  delay(100); // Anti-rebond


  // Ici, le bouton vient d'être appuyé pour indiquer que l'on veut arrêter la première roue

  
  // Serial.println(F("Ralentissement sur 4 tours du premier moteur"));
   quickStepRotationX(8*UN_TOUR_X, VITESSE_MAXI_X, acceleration_sur 0 pas_ou_micro_pas, deceleration_sur 8*UN_TOUR_X);

  // Serial.println(F("Attente du relâchement du bouton"));
  while (digitalRead(bouton) == APPUYE)
  {
    if (quickStepResteY() < 5) quickStepRotationY(UN_TOUR_Y / nombreDeFaces, VITESSE_MAXI_Y);
    if (quickStepResteZ() < 5) quickStepRotationZ(UN_TOUR_Z / nombreDeFaces, VITESSE_MAXI_Z);
    affichage();
  }
  delay(100); // Anti-rebond

  // Serial.println(F("Attente de l'ordre d'arrêt du deuxième moteur"));
  while (digitalRead(bouton) != APPUYE)
  {
    if (quickStepResteY() < 5) quickStepRotationY(UN_TOUR_Y / nombreDeFaces, VITESSE_MAXI_Y);
    if (quickStepResteZ() < 5) quickStepRotationZ(UN_TOUR_Z / nombreDeFaces, VITESSE_MAXI_Z);
    affichage();
  }
  delay(100); // Anti-rebond


  // Ici, le bouton vient d'être appuyé pour indiquer que l'on veut arrêter la deuxième roue

  
  // Serial.println(F("Ralentissement sur 4 tours du deuxième moteur"));
   quickStepRotationY(8*UN_TOUR_Y, VITESSE_MAXI_Y, acceleration_sur 0 pas_ou_micro_pas, deceleration_sur 8*UN_TOUR_Y);

  // Serial.println(F("Attente du relâchement du bouton"));
  while (digitalRead(bouton) == APPUYE)
  {
    if (quickStepResteZ() < 5) quickStepRotationZ(UN_TOUR_Z / nombreDeFaces, VITESSE_MAXI_Z);
    affichage();
  }
  delay(100); // Anti-rebond

  // Serial.println(F("Attente de l'ordre d'arrêt du troisième moteur"));
  while (digitalRead(bouton) != APPUYE)
  {
    if (quickStepResteZ() < 5) quickStepRotationZ(UN_TOUR_Z / nombreDeFaces, VITESSE_MAXI_Z);
    affichage();
  }
  delay(100); // Anti-rebond


  // Ici, le bouton vient d'être appuyé pour indiquer que l'on veut arrêter la troisième roue

  
  // Serial.println(F("Ralentissement sur 4 tours du troisième moteur"));
   quickStepRotationZ(8*UN_TOUR_Z, VITESSE_MAXI_Z, acceleration_sur 0 pas_ou_micro_pas, deceleration_sur 8*UN_TOUR_Z);


  // Serial.println(F("Attente tant qu'un moteur tourne encore"));
  while (!quickStepMoteurArretX() || !quickStepMoteurArretY() || !quickStepMoteurArretZ()) affichage();
}

La mise en initialisation est manuelle. Dans un vrai projet, il faudrait le faire automatiquement.