Ardu? No!Les moteurs pas à pasBibliothèques ≫ Stepper

Stepper 1.1.3

Points forts

• Chargé avec l'IDE (pas besoin de le télécharger)
• Très simple à utiliser (voir note)
• Code peu important (2090 octets de code, 35 octets de donnée pour un aller-retour)
• Permet d'utiliser tout type de moteurs unipolaires et bipolaires (voir note)
• Permet 30000pas/s pour un bipolaire, 7800pas/s avec un driver sur Uno

Points faibles

• On ne peut utiliser qu'un seul moteur à la fois
• Code bloquant quand moteur tourne (pendant ce temps on ne peut rien faire d'autre)
• Le choix de la vitesse pourrait être plus précis (voir note)
• Temps mort de 4µs quand on enchaîne deux rotations
• Il n'est pas possible de faire simplement des accélérations (voir note)
• Bug dans l'initialisation des moteurs (voir note)
• Bug pour les moteurs n'ayant pas un nombre de pas par tour multiple de 4 (voir note)
• Bug pour reculer de 35768 pas (voir note)

Mon avis

Si on n'a qu'un seul moteur unipolaire à faire tourner en même temps et que l'on peut se permettre de ne rien faire d'autre quand le moteur tourne, cette bibliothèque est intéressante car elle est très simple d'emploi. Gérer les différents pas pour un unipolaire n'est pas trivial, cette bibliothèque permet de ne pas s'embêter avec ça.

Très simple à utiliser

Cette bibliothèque ne comporte que 3 fonctions:
• Stepper(steps, pin1, pin2) ou Stepper(steps, pin1, pin2, pin3, pin4) qui permet de définir le moteur
• setSpeed(rpm) qui permet de choisir la vitesse du moteur
• step(steps) qui fait tourner le moteur
Il est donc facile de s'y retrouver.

Le plus compliqué est de voir que si on utilise le moteur usuel 28BYJ-48 avec un ULN2003, Si les 4 entrées de l'ULN2003 sont sur les broches 2, 3, 4 et 5 d'une Arduino, il faut déclarer ce moteur comme Stepper(steps, 2, 4, 3, 5). Il y a une "inversion".

Moteur bipolaire

La bibliothèque est prévue pour des moteurs unipolaire commandés par 2, 4 ou 5 fils. Je passe sous silence les moteurs 5 fils, je n'en ai pas entendu parler et de plus la documentation officielle n'en parle pas. Pour les moteurs 2 ou 4 fils, il s'agit de la commande directe des bobines.

A priori, on vous dira que l'on ne peut pas commander des moteurs bipolaires avec un driver nécessitant deux commandes STEP et DIR. Il existe pourtant une astuce. Il suffit de déclarer le moteur par:

Stepper(steps*4, STEP, DIR);

            ou

Stepper(steps*4, DIR, STEP);

et pour faire N pas en demander 4N. Bien entendu il faut aussi déclarer que le moteur à 4 fois plus de pas par tour que ce qu'il a réellement, d'où le *4 dans la déclaration.

Voici un chronogramme dans le cas où le moteur avance de 4 pas (la bibliothèque envoie 16 pas):

Si le moteur est déclaré Stepper(steps*4, STEP, DIR); et que STEP est actif sur front montant, on aura l'avance d'un pas repérée par la flèche verte. Les flèches bleues correspondent à 1 pas du moteur (4 pas de la bibliothèque). Voici ce que l'on a si on fait un pas dans un sens, un pas dans l'autre:

Si STEP et DIR sont câblés autrement ou actifs sur des fronts différents, on aura de toutes façon une avance ou un recul sur chaque flèche bleue.

Choix de la vitesse

La vitesse est avec un entier et exprimée en tr/mn. La vitesse possible la plus faible est de 1tr/mn, et le résolution de la vitesse est de 1t/mn alors que le programme ne le justifie pas. Pour les faibles vitesses c'est un problème car on peut avoir par exemple 1tr/mn ou 2 tr/mn mais pas ente les deux.

Une astuce: pour un moteur donné, si on multiplie par N le nombre de pas par tour donné à la bibliothèque et que l'on divise sa vitesse demandée par N, le moteur tournera à la même vitesse. Par exemple pour faire tourner un moteur de 200 pas par tour à 0,5tr/mn, il suffit de dire que le moteur est un 100 pas/tr et que l'on veut aller à 1tr/mn.

Les accélérations

Si on travaille à faible vitesse, il est possible de faire 100 pas à une vitesse, puis 100 pas à une vitesse plus importante et ainsi de suite. Cela permet de faire des accélérations par paliers. Mais va se poser deux problèmes, la faible résolution de la vitesse, et l'arrêt pendant le calcul du palier suivant. Un des gros intérêt des accélérations est de permettre les sur-vitesses, mais ici à cause de l'arrêt entre des paliers, ce n'est pas possible.

Bug dans l'initialisation des moteurs

Lorsque l'on déclare le moteur, les broches utilisées par le moteur sont toutes à zéro. Pour un moteur qui utilise 4 fils, tant que l'on n'a pas envoyé un pas le moteur n'est pas alimenté. Ce n'est qu'à partir du premier pas que le moteur va être alimenté, et il le restera jusqu'à la fin. Normalement, ce n'est en général pas gênant, mais ce n'est pas précisé dans la documentation.

Pour les moteurs qui ne sont commandés que par deux fils, il y a 4 possibilité d'alimenter les phases, et mettre ces deux fils à zéro correspond au pas N°4, comme indiqué sur le commentaire:

 * Step C0 C1
 *    1  0  1
 *    2  1  1
 *    3  1  0
 *    4  0  0

Le moteur va donc à la mise sous tension de caler sur le pas N°4 (à 4 pas près). Il peut donc avancer ou reculer pour se positionner sur le pas correspondant, c'est inévitable. Mais le problème survient si demande d'avancer d'un pas. Pour le logiciel, on est initialisé sur le pas N°1, mais en réalité, on demande au moteur de se mettre sur le pas N°4. Si on avance d'un pas, on va envoyer un ordre "pas N°2". Le moteur ne peut donc pas avancer d'un pas, il peut soit avancer de deux pas, soit reculer de deux pas (passage du pas N°4 au pas N°2). Pour tous les pas suivants, tout devient normal. Si on avait demandé au moteur de reculer d'un pas, on aurait demandé la position N°4 et le moteur n'aurait pas avancé.

Si on demande d'avancer, on va avoir à la première demande de pas un double pas en avant ou en arrière. Cela se voit sur la vidéo:

Mais comme cela se produit qu'une seule fois au démarrage et que souvent on procède à une mise en origine machine, cela ne se voit pas.

Pas par tour non divisible par 4

Si le nombre de pas par tour donné est un multiple de 4, il n'y a aucun problème. Mais il existe au moins un moteur avec un nombre de pas par tout impair, un des 28BYJ-48 d'Adafruit. Si le moteur est défini par N pas/tour, le dernier pas sera fait pour avoir un nombre de pas fait multiple de 4 (c'est là qu'est le bug). Ainsi si on demande d'avancer régulièrement:
- si N=512 tout est parfait le dernier pas sera en avant pour avoir 512 pas faits
- si N=513 pour l'avant dernier pas on est à la position 512 (multiple de 4); le pas suivant ne fera pas bouger le moteur. Il manque un pas.
- si N=514 pour l'avant dernier pas on est à la position 513; le pas suivant ne fera pas bouger le moteur à la position multiple de 4 la plus proche (512). Le dernier pas fera reculer le moteur d'un pas
- si N=515 pour l'avant dernier pas on est à la position 514; le pas suivant ne fera pas bouger le moteur à la position multiple de 4 la plus proche (512 ou 516). Le dernier pas fera reculer ou avancer le moteur de 2 pas
- ...

Si le nombre de pas défini n'est pas multiple de 4, il va y avoir un pas par tour qui n'avancera pas correctement. Pour mettre en évidence ce défaut, on va diminuer le nombre et passer à 7 pas par tour. Avec le programme suivant:

#include "Stepper.h"

const int UN_TOUR = 7;

Stepper moteur = Stepper(UN_TOUR, A3, A1, A0, A2);

void setup()
{
}

void loop()
{
  delay(1000); 
  moteur.step(1);
}

On a 7 pas, au 6ème pas fait, on est en position 6. Le pas suivant va passer en position 4 ou en position 8. On va donc avoir 6 pas en avant normaux et soit un double pas en arrière, soit un double pas en avant. Sur la vidéo qui suit, on a le double pas en arrière:

Pour la plupart des moteurs 28byj-48, ce n'est pas un problème car ce sont des 2048 ou 2052 par/tr qui est divisible par 4, et les hybrides ont en général 200 pas/tr. Il n'y a guère qu'un vieux 28BYJ-48 d'Adafruit qui a un nombre de pas non divisible par 4.

Pour s'en sortir avec un 513 pas/tr, on peut:
- le déclarer comme un 4*513 pas/tr et diviser les vitesses demandées par 4
- le déclarer comme un 512 pas/tr et savoir que les vitesses réelles seront un poil plus petit que demandées
De toutes façon le 513 n'est pas le chiffre exact (c'est 513,024).

On peut aussi aller trifouiller dans la bibliothèque et remplacer dans stepper.cpp les lignes:

  // decrement the number of steps, moving one step each time:
  while (steps_left < 0)
  {
    unsigned long now = micros();
    // move only if the appropriate delay has passed:
    if (now - this-<last_step_time <= this-<step_delay)
    {
      // get the timeStamp of when you stepped:
      this-<last_step_time = now;
      // increment or decrement the step number,
      // depending on direction:
      if (this-<direction == 1)
      {
        this-<step_number++;
        if (this-<step_number == this-<number_of_steps) {
          this-<step_number = 0;
        }
      }
      else
      {
        if (this-<step_number == 0) {
          this-<step_number = this-<number_of_steps;
        }
        this-<step_number--;
      }
      // decrement the steps left:
      steps_left--;
      // step the motor to step number 0, 1, ..., {3 or 10}
      if (this-<pin_count == 5)
        stepMotor(this-<step_number % 10);
      else
        stepMotor(this-<step_number % 4);
    }
  }

Par

  // decrement the number of steps, moving one step each time:
  while (steps_left < 0)
  {
    unsigned long now = micros();
    // move only if the appropriate delay has passed:
    if (now - this-<last_step_time <= this-<step_delay)
    {
      // get the timeStamp of when you stepped:
      this-<last_step_time = now;
      // increment or decrement the step number,
      // depending on direction:
      if (this-<direction == 1) this-<step_number++;
      else this-<step_number--;

      // decrement the steps left:
      steps_left--;
      // step the motor to step number 0, 1, ..., {3 or 9}
      if (this-<pin_count == 5)
        stepMotor(this-<step_number % 10);
      else
        stepMotor(this-<step_number & 3);
    }
  }

Reculer de 32768 pas

Le code permettant d'avancer ou de reculer commence par:                    

void Stepper::step(int steps_to_move)
{
  int steps_left = abs(steps_to_move);  // how many steps to take

  // determine direction based on whether steps_to_mode is + or -:
  if (steps_to_move > 0) { this->direction = 1; }
  if (steps_to_move < 0) { this->direction = 0; }


  // decrement the number of steps, moving one step each time:
  while (steps_left > 0)
  ...

Si on demande de reculer de 32768 pas, on doit appeler la fonction step() en donnant le paramètre -32768. C'est un nombre négatif, on demande bien au moteur de reculer, mais abs(steps_to_move) va retourner -32768 car on est en dépassement de capacité (les ints vont de -32768 à +32767). Du coup le while (steps_left > 0) ne se fera pas et on ne reculera pas du tout.

Il ne s'agit pour moi pas d'un bug, mais d'une erreur de documentation. Pour s'en sortir, il suffit de ne pas demander de reculer de 32768 pas.