Deux moteurs pas à pas

moteur pas à pas arduino

Voici un programme permettant de piloter deux moteurs pas à pas ; il a été écrit pour animer un cargo à deux mats de déchargement conçu et réalisé par Willy DEWULF CAM 0590.

Le but du mouvement est de décharger une caisse contenue dans la cale et de la déposer sur le quai. Les deux moteurs pas à pas travaillent simultanément pour entraîner deux treuils visibles sur la photo. Le mouvement est complexe, Willy l’a découpé en 52 étapes et pour chaque étape, il a calculé le nombre de pas à réaliser pour chaque moteur.

Un shield DRI0023 V2 est monté sur Arduino Uno, il permet de raccorder les deux moteurs. Les moteurs sont alimentés par une alimentation externe 12 V branchée sur le shield.

Attention
– les moteurs sont gourmands : il faut compter 1,2 A pour l’ensemble des 2 moteurs
– bien repérer le + et le – de l’alimentation externe et ne pas se tromper dans le branchement sur le shield (Il est détruit en cas d’erreur de branchement).

Le DRI0023 permet de passer les moteurs en mode disable ce qui permet de couper l’alimentation des moteurs quand on n’en n’a plus besoin.

Si les moteurs sont alimentés et immobiles, ils maintiennent leur position avec un certain couple.

Le programme envoie ses ordres aux moteurs mais ne sait pas s’ils ont vraiment changé de position : c’est au mécanicien de s’assurer que le mouvement n’est pas bloqué ou trop difficile.

La librairie standard stepper n’est pas utilisée. J’ai utilisé l’excellente librairie Accelstepper qui peut gérer plusieurs moteurs. La librairie Multistepper permet de plus de les faire travailler simultanément et en synchronisation : à chaque étape, les moteurs démarrent en même temps et s’arrêtent en même temps. Ces mouvements s’effectuent en mode bloqué : l’arduino ne traite pas d’autre instruction.

Dernier point : la vitesse du port série, utilisé pour afficher des messages de contrôle a été portée à 115200 bauds car je me suis aperçu qu’à 9600, le mouvement des moteurs apparaissait saccadé.



// Willy-V2stepperF

// Commande de deux moteurs pas a pas
// fonctionnant de facon simultanée et coordonnée
// Ecrit pour un modele de Willy
// le cargo a deux mats de charge

// les librairies necessaires

#include <AccelStepper.h>
#include <MultiStepper.h>

// 1 shield controleur pas a pas
// DFRobot DRI0023 V2
// est monte sur un arduino Uno
// 2 moteurs bipolaires pas a pas
// Mercury SM-42BYG011-25

// declaration des deux moteurs et de leur pins associees

AccelStepper stepper1(1, 6, 7);//( controleur type 1, step pin, dir pin )
AccelStepper stepper2(1, 5, 4);//( controleur type 1, step pin, dir pin )

// le moteur 1 est du cote X sur la carte
// le moteur 2 est du coté Y sur la carte

// ils seront geres comme un ensemble de deux moteurs
// nomme steppers

MultiStepper steppers;

// La version 2 du DRI0023
// utilise 2 pins supplementaires par rapport a la V1
// pour mettre les moteurs en etat enable ou disable

const int M1enablePin=8;  
const int M2enablePin=12;

// positions absolues des deux moteurs 
long positions[2]; // tableau à deux valeurs positions[0] et positions[1]

const int max_etapes = 52 ; // le nombre total d'étapes;

int num_etape = 0; // l'etape courante de 1 a max_etapes

// les increments courants
int inc1 = 0;
int inc2 = 0;

// on definit une structure pour
// ranger les increments de chaque etape

typedef struct {
  int nb_pas_moteur1;
  int nb_pas_moteur2;
} Tableau_increments;

// Pour chaque etape, on indique
// le nb de pas que doit faire chaque moteur

const Tableau_increments tab_pas[] = { 
// etapes 1 a 5
{18,36}, {18,36} , {18,36} , {18,36}, {14,36},
// etapes 6 a 10
{14,36}, {14,36} , {11,36} , {11,36}, {11,36},
// etapes 11 a 15
{7,36}, {7,36} , {36,-4} , {32,-14}, {36,-18},
// etapes 16 a 20
{36,-25}, {36,-25} , {36,-29} , {32,-32}, {36,-29},
// etapes 21 a 25
{36,-32}, {32,-36} , {36,-32} , {36,-32}, {32,-36},
//etapes 26 a 30
{32,-36}, {36,-32} , {32,-36} , {29,-36}, {32,-32},
//etapes 31 a 35
{29,-36}, {25,-36} , {25,-36} , {18,-36}, {14,-32},
//etapes 36 a 40
{4,-36}, {-36,-7} , {-36,-7} , {-36,-11}, {-36,-11},
//etapes 41 a 45
{-36,-11}, {-36,-14} , {-36,-14} , {-36,-14}, {-36,-18},
//etapes 46 a 50
{-36,-18}, {-36,-18} , {-36,-22} , {-36,-18}, {-36,-22},
//etapes 51 a 52
{-36,-22}, {-36,-22} ,

};


//**************
// bouton GO
//**************

// L'appui sur le bouton GO
// lance la boucle principale.
// Une fois que les moteurs ont effectue
// la serie complete on revient
// en attente d'appui sur ce bouton

int bouton_GO = A0;

boolean APPUI_BOUTON = 1 ;

// Doit-on afficher sur le port serie 
// les traces d'execution ?

const boolean AFFICHE = 0;

//////////////////
void setup()
//////////////////
{
  
  Serial.begin(115200);
  
  pinMode(bouton_GO,INPUT);
  
// Faire gerer les deux steppers par Multistepper
  
  steppers.addStepper(stepper1);
  steppers.addStepper(stepper2);  
  
// Faut-il inverser l'etat des pin direction, step, enable ?
// oui il faut inverser les pin enable
// car sur le DRV8825 (DR0023 V2)  un etat bas correspond a l'etat enable
// c'etait le contraire avec le A4988 qui equipait la V1 du DRI0023

  stepper1.setPinsInverted(false,false,true);
  stepper2.setPinsInverted(false,false,true);


// Informer la librairie des pins
// utilisees pour mettre les moteurs enable

  stepper1.setEnablePin(M1enablePin);
  stepper2.setEnablePin(M2enablePin);

// Mettre les moteurs en mode enable
// en fait ils sont deja dans ce mode
// automatiquement

 stepper1.enableOutputs();
 stepper2.enableOutputs();  

  
// Configurer vitesses maxi
  
  stepper1.setMaxSpeed(80); 
  stepper2.setMaxSpeed(80);   
  
  
// initialisation des positions a zero
  
  positions[0]= 0; 
  positions[1]= 0;  
   
}

//////////////
void loop(){  
//////////////  

  Serial.println("\n * * * * * En attente appui 1 s sur bouton GO * * * * *");

  while  (digitalRead(bouton_GO) != APPUI_BOUTON )  {            
   
  }  

  alimente_moteurs();
  
  cale_vers_quai ();

  Serial.println("\n********** Attente 10 s puis mvt de retour a la position initiale ");
  
  delay(10000);

  quai_vers_cale ();

  Serial.println("\n************** Fin d'un cycle cale => quai suivi de quai => cale");

  // Couper les moteurs pour eviter
  // qu'ils ne chauffent

  coupe_moteurs();  
   
} // fin loop


///////////////////////////////////////////////////////////
// Fonctions
//////////////////////////////////////////////////////////

////////////////////////
void cale_vers_quai() {
////////////////////////
  
// mouvement aller de la cale vers le quai
  
  
for (num_etape = 1 ; num_etape <= max_etapes ; num_etape++) {
  
  // aller chercher les increments de l'etape
  
  inc1 = tab_pas[num_etape -1].nb_pas_moteur1;
  inc2 = tab_pas[num_etape -1].nb_pas_moteur2;
   
  
  if (AFFICHE) { Serial.print("\n=========== Debut etape etape : "); Serial.println(num_etape);}
  
  if (AFFICHE) { Serial.print("Position avant mvt Moteur 1 : ") ; Serial.print(positions[0]);}
  if (AFFICHE) { Serial.print(" === Increment a faire : "); Serial.println(inc1);}
  

  if (AFFICHE) { Serial.print("Position avant mvt Moteur 2 : ") ; Serial.print(positions[1]);}
  if (AFFICHE) {Serial.print(" === Increment a faire : "); Serial.println(inc2);}
  
  // nouvelles positions a atteindre
  
  positions[0]+= inc1;
  positions[1]+= inc2; 
  
  steppers.moveTo(positions);
  // On ne fait rien d'autre que de positionner 
  // correctement les deux steppers 
  // aucune autre instruction ne se déroule (mode bloque)
  // les deux steppers finissent en meme temps leur positionnement
  
  steppers.runSpeedToPosition();
  
  if (AFFICHE) { Serial.print("Position apres mvt Moteur 1 : ") ; Serial.println(positions[0]); }
  if (AFFICHE) { Serial.print("Position apres mvt Moteur 2 : ") ; Serial.println(positions[1]); }
  if (AFFICHE) { Serial.print("=========== Fin etape : "); Serial.println(num_etape); }   
  
 } // for

// fin mouvement cale vers quai

} // fin cale_vers_quai

/////////////////////////
void quai_vers_cale() {
/////////////////////////  

// mouvement retour du quai vers la cale
// on decrit les etapes en commencant par la derniere
// on inverse les sens de rotation de chaque etape
  
for (num_etape = max_etapes ; num_etape >= 1 ; num_etape--) {
  
  // aller chercher les increments de l'etape
  // et inverser le sens de rotation (signe -)
  
  inc1 = - tab_pas[num_etape -1].nb_pas_moteur1;
  inc2 = - tab_pas[num_etape -1].nb_pas_moteur2;
   
  
  if (AFFICHE) { Serial.print("\n=========== Debut etape etape : "); Serial.println(num_etape);}
  
  if (AFFICHE) { Serial.print("Position avant mvt Moteur 1 : ") ; Serial.print(positions[0]);}
  if (AFFICHE) { Serial.print(" === Increment a faire : "); Serial.println(inc1);}
  

 if (AFFICHE) { Serial.print("Position avant mvt Moteur 2 : ") ; Serial.print(positions[1]);}
 if (AFFICHE) { Serial.print(" === Increment a faire : "); Serial.println(inc2);}
 
 // nouvelles positions a atteindre
  
  positions[0]+= inc1; 
  positions[1]+= inc2;
  
  steppers.moveTo(positions);
  // On ne fait rien d'autre que de positionner 
  // correctement les deux steppers 
  // aucune autre instruction ne se déroule (mode bloque)
  // les deux steppers finissent en meme temps leur positionnement
  
  
  steppers.runSpeedToPosition();
  
  if (AFFICHE) { Serial.print("Position apres mvt Moteur 1 :") ; Serial.println(positions[0]); }
  if (AFFICHE) { Serial.print("Position apres mvt Moteur 2 :") ; Serial.println(positions[1]); }
  if (AFFICHE) { Serial.print("=========== Fin etape : "); Serial.println(num_etape); }
  
 
   
 } // for

// fin mouvement quai vers cale
// on est revenu a la position d'origine

} // fin quai_vers_cale

/////////////////////////
void coupe_moteurs() {
///////////////////////// 

  stepper1.disableOutputs();
  stepper2.disableOutputs();  
}



//////////////////////////
void alimente_moteurs() {
//////////////////////////  
 stepper1.enableOutputs();
 stepper2.enableOutputs();  
}