Problème Moteur Nema 17 (0.59nm) et driver Tb6600 sur arduino uno

Bonjour à tous !

Pour un projet artistique sur lequel je travaille, j'ai commencé à travailler avec des moteurs PAP nema 17 (0.59 nm) associés à des drivers TB6600 et des arduino uno, alimentés par des alims 12v 2A. Je n'en avais encore jamais utilisé. Je travaillais jusqu'à lors avec des moteurs DC et des motorshields mais aujourd'hui je souhaite apporté plus de précision à mes projets motorisés.

Le projet en question est le suivant :
Dans mon installation, il y a plusieurs ballons de baudruches attachés entre eux et recouvert d'un drap sur une surface de 2mx2m environ. Au plafond, j'ai fixé des moteur PAP nema 17 équipé de bobine de fil de nylon, et eux sont reliés à quatre points précis dans l'assemblage de ballons, passant à travers le drap.
Ce que je souhaite faire serait de "chorégraphier" chaque moteur pour qu'il fasse danser l'assemblage de ballon (comme une marionette) en faisant monter/descendre chaque points de fixation nylon/ballon à différentes hauteurs, jusqu'à 1m50 max.

J'ai donc commencé à chercher des codes simples qui conviendrais pour faire l'enchainement d'action suivant :

-pause de x temps
-rotation CW de y tours à z vitesse.
-pause de y temps

  • rotation CCW de z tours a x vitesse.
    -etc

J'ai trouver les deux suivant sur ce site qui semble convenir :

/* Example sketch to control a stepper motor with TB6600 stepper motor driver and Arduino without a library: number of revolutions, speed and direction. More info: https://www.makerguides.com */

// Define stepper motor connections and steps per revolution:
#define dirPin 2
#define stepPin 3
#define stepsPerRevolution 1600

void setup() {
  // Declare pins as output:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {
  // Set the spinning direction clockwise:
  digitalWrite(dirPin, HIGH);

  // Spin the stepper motor 1 revolution slowly:
  for (int i = 0; i < stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(2000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2000);
  }

  delay(1000);

  // Set the spinning direction counterclockwise:
  digitalWrite(dirPin, LOW);

  // Spin the stepper motor 1 revolution quickly:
  for (int i = 0; i < stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(1000);
  }

  delay(1000);

  // Set the spinning direction clockwise:
  digitalWrite(dirPin, HIGH);

  // Spin the stepper motor 5 revolutions fast:
  for (int i = 0; i < 5 * stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }

  delay(1000);

  // Set the spinning direction counterclockwise:
  digitalWrite(dirPin, LOW);

  // Spin the stepper motor 5 revolutions fast:
  for (int i = 0; i < 5 * stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }

  delay(1000);
}

Celui-ci me permet de faire ce que je veux il semblerait. Mais je ne comprend pas bien cette partie :

    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);

Pour moi les commandes HIGH et LOW signifiait Marche et Arret (ici pour 500 ms chacune).
Et quand je l'utilise le moteur tourne pendant 1000 ms.
Je ne comprend pas très bien.

et il y à le 2ème code :

// Include the AccelStepper library:
#include <AccelStepper.h>

// Define stepper motor connections and motor interface type. Motor interface type must be set to 1 when using a driver:
#define dirPin 2
#define stepPin 3
#define motorInterfaceType 1

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
  // Set the maximum speed and acceleration:
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(500);
}

void loop() {
  // Set the target position:
  stepper.moveTo(8000);
  // Run to target position with set speed and acceleration/deceleration:
  stepper.runToPosition();

  delay(1000);

  // Move back to zero:
  stepper.moveTo(0);
  stepper.runToPosition();

  delay(1000);
}

Celui-ci est encore mieux puisqu'il utilise la Accelsteppers Library et donc permet l'accélération et la décélération.
Toutefois quand je l'utilise, Le moteur opère des décalages très important dans les phases d'accélérations et de décélérations ce qui ne permet pas d'avoir des rotations de 200 pas parfaites.

Avez vous des informations ou des conseils concernant ce problème ?
Ou le cas échéant sauriez-vous comment je pourrais revoir le deuxième code pour enlever l'accélération/décélération et modifier à chaque rotation la vitesse, à la place ?

Merci de m'avoir lu

Dans un moteur à courant continu, quand on met une tension, il se met à tourner. Quand on met 0V, il s'arrête.

Dans un moteur pas à pas quand on met du courant, le moteur va s'aligner en face d'une bobine. Si on laisse le courant, il va rester en face et ne tourne pas. Pour avancer, il faut alors mettre du courant dans une deuxième bobine, il va alors s’aligner sur le deuxième bobine. Les moteurs actuels ont l'équivalent de 4 bobines et pour avancer, il faut donner des ordres bobine 1, bobine 2, bobine 3, bobine 4, bobine 1, bobine 2... Dans ton moteur, il n'y a que deux bobines (4 fils) il suffit de remplacer bobine 3 par bobine 1 à l'envers.

Comme c'est un peu pénible, des circuits spécialisés vont se charger de choisir les bonnes bobines, il suffit de leur donner deux ordres le premier la direction CW ou CCW, et le deuxième Step qui dit avance d'un pas. Avec ces drivers, pour avancer, il suffit d'envoyer des "avance" "avance" "avance" . Cela se fait en mettant un front sur le driver (ton TB6600)

Pour moi les commandes HIGH et LOW signifiait Marche et Arret (ici pour 500 ms chacune).
Et quand je l'utilise le moteur tourne pendant 1000 ms.

HIGH va mettre en marche STEP (donner l'information d'avancer d'un pas)
LOW va remettre Step à 0, pour pouvoir par la suite donner un autre ordre.
Entre les deux, il y a un temps minimum à respecter (2.5µs je crois) en fonction du driver.
Ici il y a une temporisation de 500µs (pas ms) après chaque niveau de step. Step va avoir un front montant toutes les millisecondes et va avancer d'un pas. Le nombre de vrais pas de ton moteur est 200, mais le TB6600 peut couper les pas en petits, et faire comme si le moteur avait 800 pas par tour (il fait alors un tour en 800ms), 1600 pas par tours...
Les lignes en question sont dans une boucle qui va se répéter 1600 fois, il y aura 1600 ordres d'avancer d'un pas, cela va durer 1600ms soit 1,6s

Pour gérer un moteur, on peut donner les ordres directement sur step comme le fait le premier programme. le nombre d'itération va donner le nombre de "crans" et donc le déplacement, les temporisations vont faire durer plus ou moins longtemps l'espace ente les pas et cela va donc donner la vitesse.

La deuxième méthode consiste à utiliser une bibliothèque qui va prendre en charge certaines fonctionnalités.

N'utilisant pas AccelStepper, je peux difficilement te conseiller.

Pour plus d'infos sur les moteurs pas à pas, j'ai écrit un tuto sur http://dansetrad.fr/Orgue_de_barbarie/Elec/Action/PasAPas/index.html La moité des choses sont d'un niveau avancé, mais tu peux éventuellement trouver ton bonheur.

Ok ! merci pour cette réponse très complète. Je comprend pas tout à la première lecture mais je saisi un peu mieux la subtilité de ces moteurs et de leurs fonctionnements.
Peux tu me préciser ce que tu veux dire par "µs (pas ms)" ?

Dommage que tu n'utilise pas Accelsteppers mais j'imagine que quelqu'un d'autre pourra me renseigner.

µs microseconde
ms milliseconde
1000µs = 1ms
1000ms = 1s
1µs = 0.001ms
dans le code on a deux tempos de 500µs (0,5ms) A elles deux cela fait 1ms. Si on fait la boucle 1600 fois, cela dure 1600ms soit 1,6s

D'AAAACORD

Donc tu es en train de me dire que par exemple dans un tour de 200 pas, il y a 200 HIGH de 500 microsecondes qui s'alternent avec 200 LOW de 500 microsecondes ?

Donc tu es en train de me dire que par exemple dans un tour de 200 pas, il y a 200 HIGH de 500 microsecondes qui s'alternent avec 200 LOW de 500 microsecondes ?

Exact.

Sur http://dansetrad.fr/Orgue_de_barbarie/QuickStep/Screenshoots.html, il y a quelques copies d'affichage des signaux pour gérer des moteurs. Quand il y a des petites impulsions sur step, elles durent moins de 2µs.

D'accord je vais approfondir mes connaissances avec ta documentation. Merci beaucoup !

Je dois avancer dans mon projet, et en attendant de trouver une solution pour ces étranges "sauts" que font les moteurs avec le 2eme code (celui avec AccelStepper), je continuer de travailler sur celui-ci.

J'ai essayé, pour me faciliter la vie, de faire un code pour controller deux nema 17 en simultané (avec deux drivers tb6600 et deux alim 12V 2A)

Mais les actions continuent de s'enchainer au lieu de fonctionner simultanément.

Le code :

#include <AccelStepper.h>
#define dirPin 4
#define stepPin 5
#define motorInterfaceType 1
#define dirPin2 2
#define stepPin2 3
#define motorInterfaceType2 1
#define tours 800
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);
AccelStepper stepper2 = AccelStepper(motorInterfaceType2, stepPin2, dirPin2);

void setup() {

}
void loop() {

nema1();
nema2();

}

void nema1() {
  

//1
  stepper.setMaxSpeed(2000);
  stepper.setAcceleration(1500);
  stepper.moveTo(2 * tours);
  stepper.runToPosition();
  delay(2000);

//2
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(500);
  stepper.moveTo(0 *tours);
  stepper.runToPosition();
  delay(2000);
}


void nema2() {
//1
  stepper2.setMaxSpeed(2000);
  stepper2.setAcceleration(1500);
  stepper2.moveTo(2 * tours);
  stepper2.runToPosition();
  delay(2000);

//2
  stepper2.setMaxSpeed(1000);
  stepper2.setAcceleration(500);
  stepper2.moveTo(0 *tours);
  stepper2.runToPosition();
  delay(2000);
}

Pourriez vous me dire ce qui cloche ?

et deux alim 12V 2A

Cela m'étonnerait que les moteurs aient besoin de plus de 12W chacun, et une seule alim doit suffire. Quel sont les moteurs utilisés Nema17 est la taille de la semelle. C'est un peu comme si pour décrire mon cousin, je te disais seulement qu'il chausse du 43. Il doit y avoir une référence sur le moteur, par exemple HS4400. Sinon une photo de la plaque signalétique.

Si les mouvements s'enchainent c'est parce que dans loop, tu demandes la rotation d'un moteur, puis de l'autre
Pour faire tourner deux moteurs, il faut regarder l'exemple MultipleSteppers.

Les moteurs en question sont des 17HS19-2004S1.

En ce qui concerne le code, je me suis dirigé vers l'exemple multiplesteppers d'accelstepper comme tu me l'as conseiller dont voici la base :

#include <AccelStepper.h>
AccelStepper stepper1(AccelStepper::DRIVER, 2, 3);
AccelStepper stepper2(AccelStepper::DRIVER, 8, 9);

void setup()
{  
    stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(100.0);
    stepper1.moveTo(24);
    
    stepper2.setMaxSpeed(300.0);
    stepper2.setAcceleration(100.0);
    stepper2.moveTo(1000000);

}
void loop()
{
    // Change direction at the limits
    if (stepper1.distanceToGo() == 0)
        stepper1.moveTo(-stepper1.currentPosition());
    stepper1.run();
    stepper2.run();

}

Effectivement, on arrive à faire fonctionner les deux moteurs simultanément. (Est-ce la différence avec le code, que j'ai testé avant tient au fait que j'utilisais runToPosition qui est une fonction blocante ?)
Toutefois quand j'essais de le modifier, je n'arrive pas à ce que je veux.
Premièrement je n'arrive pas enchainer avec une seconde rotation. J'imaginais que cela marcherait avec ces lignes de code, mais non :

#include <AccelStepper.h>
AccelStepper stepper1(AccelStepper::DRIVER, 2, 3);
AccelStepper stepper2(AccelStepper::DRIVER, 8, 9);

void setup()
{  
    stepper1.setMaxSpeed(200.0);
    stepper1.setAcceleration(100.0);
    
    stepper2.setMaxSpeed(300.0);
    stepper2.setAcceleration(100.0);

}
void loop()
{
        stepper1.moveTo(800);
    if (stepper1.distanceToGo() == 0)
        stepper1.moveTo(400);
    stepper1.run();
        stepper1.moveTo(1200);
    if (stepper1.distanceToGo() == 0)
        stepper1.moveTo(400);

        stepper2.moveTo(800);
    if (stepper2.distanceToGo() == 0)
        stepper2.moveTo(400);
    stepper2.run();
        stepper2.moveTo(1200);
    if (stepper2.distanceToGo() == 0)
        stepper2.moveTo(400);

}

De plus j'aimerais pouvoir faire des rotations de longueur, de vitesse et d'acceleration différentes chacune sur chaque moteurs. Notamment pour pouvoir les replacer en home position à la fin de leur chorégraphie.
Enfin je voudrais faire des pauses courtes entre les rotations et une longue pause en début ou fin de chorégraphie. mais le simple fait de mettre une fonction delay dans le void loop fait fonctionner les moteurs à l'extrême ralenti.

Je suis un perdu dans tout ca, mais je sens que je me rapproche du but

C'est un 2A, 2.8V soit 5,6W. L'alim suivant mon avis, tant que je n'ai vu personne en parler, est qu'il faut une alim qui délivre 40% en plus pour être large, soit 8W. Donc effectivement une seule alim de 12V/2A est suffisante pour 3 moteurs.

Pour pouvoir faire travailler plusieurs moteurs, il faut appeler la fonction run() tant qu'ils ne sont pas arrivés au bout. Je ne trouve pas ceci pratique, c'est pourquoi je suis en train d'écrire plusieurs bibliothèques pour les pas à pas. J'ai du mal à de conseiller n'aimant pas du tout cette bibliothèque. En fait tu arrives un mois trop tôt, il est probable que ce que je suis en train d'écrire soit ce dont tu as besoin. QuickStep ne peut gérer que deux moteurs avec une Uno pour l'instant.

la fonction run():
A chaque appel le gestionnaire du moteur regarde si il doit avancer ou non et fait progresser ou non le moteur d'un pas. Si on veut avancer de 1000 pas, il faut au moins l’appeler 1000 fois, mais dans la pratique on doit le faire plus souvent par exemple 100000 fois. Pour comprendre, imagine que tu doive prendre un médicament toutes les heures, mais que tu n'ai pas de montre. Tu demandes à ta fille sans arrêt "c'est l'heure?" et une fois de temps en temps elle va dire oui. Il faut donc demander souvent pour pendre le cacher à peu près au bon moment.


Concernant ce code, si on me menaçait pour que je l'écrive, je ferais ceci. Pour faire un mouvement, il faut donner le départ par exemple par moveTo, puis appeler le plus souvent possible run jusqu'a ce que le moteur soit arrivé.
Cela doit donner quelque chose comme:

// donner les ordres de départ pour le premier mouvement
stepper1.moveTo(par là);
stepper2.moveTo(par ici);
// faire avancer
while (moteursPasArrivésOuIlFaut)
{
  stepper1.run();
  stepper2.run();
 }// donner les ordres de départ pour le deuxième mouvement
stepper1.moveTo(par là);
stepper2.moveTo(par ici);
// faire avancer
while (moteursPasArrivésOuIlFaut)
{
  stepper1.run();
  stepper2.run();
 }// donner les ordres de départ pour le toisième mouvement
stepper1.moveTo(par là);
stepper2.moveTo(par ici);
// faire avancer
while (moteursPasArrivésOuIlFaut)
{
  stepper1.run();
  stepper2.run();
 }

Après l'idéal est de faire une boucle:

for(mouvement=0; mouvement < nombreDeMouvementsAFaire; mouvement++)
{
   // donner les ordres de départ pour le premier mouvement
   stepper1.moveTo(destination[1, mouvement]);
   stepper2.moveTo(destination[2, mouvement]i);
   // faire avancer
   while (moteursPasArrivésOuIlFaut)
   {
     stepper1.run();
     stepper2.run();
    }
}

Mainttenant pour bien choisir la bonne bibliothèque, il faut avoir un bon cahier des charges:
combien de moteurs?
Accélération ou pas?
enchainement des mouvements sans temps d'arrêt ou pas?
Vitesse maximale ou temps minimum entre pas
Vitesse minimale ou temps maximum entre pas (sans compter l'arrêt, ou le temps est "infini")
Nombre de micro-pas

Il est possible qu'il n'y ait aucune bibliothèque correspondante, il faut alors faire des concessions.

Ok alors

Du coup, pour avoir des branchement plus centralisé, j'ai une alim 12v 30A avec trois sorties +/- et, corrige moi si je me trompe, il n'y a pas de risque de faire cramer tout puisque les drivers et les moteur vont se limiter a l'amperage dont ils ont besoin, n'est-ce-pas ?

C'est si douloureux ce "tu arrives un mois trop tôt", hahaha. En tout cas c'est super, que quelqu'un se penche sur cette écriture, donc bravo.
Dans l'idée, j'ai 4 moteurs que j'aimerais faire tourné sur 2 arduinos, au mieux un seul. Mais je peux donc jeter un oeil à Quickstep. Si tu as de bonnes references, je prend.

D'après l'exemple de code que tu as écris sous la menace, j'ai essayé ça mais ca n'as pas marché (le moteur2 a tourné et le moteur 1 a fais quelque pas timides) :

EDIT : my bad, j'ai oublier oublié stepper1.setMaxSpeed et stepper1.setAcceleration. Du coup, les deux moteurs tournent et s'arrêtent après le premier mouvement.

#include <AccelStepper.h>
AccelStepper stepper1(AccelStepper::DRIVER, 2, 3);
AccelStepper stepper2(AccelStepper::DRIVER, 8, 9);

void setup()
{   
    stepper2.setMaxSpeed(300.0);
    stepper2.setAcceleration(100.0);

}
void loop() {
  
// donner les ordres de départ pour le premier mouvement
stepper1.moveTo(1000);
stepper2.moveTo(500);
// faire avancer
while (stepper1.distanceToGo() != 0)
while (stepper2.distanceToGo() != 0)
{
  stepper1.run();
  stepper2.run();
  
 }// donner les ordres de départ pour le deuxième mouvement
stepper1.moveTo(500);
stepper2.moveTo(1000);
// faire avancer
while (stepper1.distanceToGo() != 0)
while (stepper2.distanceToGo() != 0)
{
  stepper1.run();
  stepper2.run();
 }
 
 // donner les ordres de départ pour le toisième mouvement
stepper1.moveTo(1500);
stepper2.moveTo(200);
// faire avancer
while (stepper1.distanceToGo() != 0)
while (stepper2.distanceToGo() != 0)
{
  stepper1.run();
  stepper2.run();
 }
}

C'est marrant j'avais penser a quelque chose comme ce que tu propose dans le deuxième code mais je n'aurais pas eu la moindre idée de comment l'écrire

Et donc voici mon cahier des charges (et ses concessions) :

  • 4 moteur pap nema 17 (`17HS19-2004S1)
  • J'aimerais qu'il y ai des accélérations pour chaque moteurs (et variables pour chaque mouvement) Je peux eventuellement faire une concession là dessus.
  • J'aimerais avoir des temps d'arrêt entre chaque mouvement et qu'il puissent être variable.
  • vitesse maximal = 5000
  • vitesse minimal = 100
  • Pour les pas J'ai d'abord passer mes drivers en 800 pulse/rev ce qui m'a permis d'enlever les sauts désagréables dans les accélérations, maintenant elle sont fluide. Je souhaite que mes mouvements ce tiennent entre 0 et 2000 mm. Ma bobine fait 8mm de diamètre, donc environs 25mm de circonférences. 2000/25 = 80 tours, 80 tours x 800 pas = 64 000
    Donc nombre de pas : entre 0 et 64 000

Du coup, pour avoir des branchement plus centralisé, j'ai une alim 12v 30A avec trois sorties +/- et, corrige moi si je me trompe, il n'y a pas de risque de faire cramer tout puisque les drivers et les moteur vont se limiter a l'amperage dont ils ont besoin, n'est-ce-pas ?

Exact. C'est comme la batterie de voiture qui peut donner 300A (pour le démarrage), mais quand on met les doigts dessus, il ne passe quasiment rien.
Avec ça tu peux commander environ 45 moteurs. Ya de la marge.

Dans l'idée, j'ai 4 moteurs que j'aimerais faire tourné sur 2 arduinos, au mieux un seul.

Il vaut mieux utiliser une seule Arduino, sinon il y des gros problèmes de synchros entre les deux. C'est un peu comme si tu achètes deux ordis, l'un pour les mails, l'autre pour faire tes comptes. C'est moins cher un seul.

while (stepper1.distanceToGo() != 0)
while (stepper2.distanceToGo() != 0)
{
  stepper1.run();
  stepper2.run();
 }

Que je peux écrire:

while (stepper1.distanceToGo() != 0)
{
  while (stepper2.distanceToGo() != 0)
  {
    stepper1.run();
    stepper2.run();
   }
}

Car le premier while fera (sous condition) l’instruction qui suit: le deuxième while.
Je traduis:

tant que le moteur 1 n'a pas fini je fais
tant que le moteur 2 n'a pas fini j'avance si besoin les deux moteurs.

Le moteur 2 finit avant le premier (500 pas à faire). Et à ce moment le deuxième while ne fait plus la boucle. Si on appelle
tant que le moteur 2 n'a pas fini j'avance si besoin les deux moteurs.
on ne fait rien car le moteur 2 a finit. Le programme devient:

tant que le moteur 1 n'a pas fini je fais
rien

Du coup le moteur 1 ne peut plus finir et on reste dans la boucle.

Tu voulais sans doute dire

tant que le moteur 1 n'a pas fini et que le moteur 2 n'a pas fini
j'avance si besoin les deux moteurs.

ce qui se traduit par:

while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0))
{
  stepper1.run();
  stepper2.run();
 }

L'informatique n'est pas aussi fin que nous. Si tu dis à une ménagère "va au marché, achète 1kg de pommes et tant que tu y est achète 1kg de poires", la ménagère revient avec les 2 kg de fruit. L'informaticien achète 1kg de pomme, puis 1kg de poires, et comme le "tant que tu y est" est encore bon, il achète un deuxième kg de poires... Il achète donc des poires kg par kg et se plante quand il n'y en a plus. C'est ça le while et la différence entre ce qu'on dit et ce que la machine comprend.

Si tu as de bonnes references, je prend.

C'est quoi ces références ? C'est comme quand on veut employer une bonne et qu'on lui demande où elle a travaillé avant? Il faut que je donnes un CV?
Si c'est pour la référence de QuickStep , il est disponible ici.

  • vitesse maximal = 5000

Il manque l'unité. si c'est des tr/mn, c'est pas la peine d'y penser. Si c'est des pas/s, abandonne accelStepper qui dit qu'il va jusqu'à 1000. Mais je ne sais pas ce qui se passe pour 2 moteurs. En principe on partage le code, et donc les vitesses. Je sais que je suis en train d'écrire un programme qui peut tourner à 16000 pas/s pour un seul moteur. Je sais que si j'en mets deux, c'est 16000 pas/s en tout, par exemple 10000 pas/s pour l'un et 6000 pas/s pour l'autre...

Oublie aussi Stepper car il est prévu pour un autre type de commande (moteurs bipolaires). On peut quand même piloter avec un TB6600, mais pour avancer d'un pas, il faut en demander 4. Cela peut poser des problèmes dans le comptage des pas quand on va dans les deux sens.

Evidemment, je peux te proposer QuickStep qui peut répondre à ton besoin, mais pour 4 moteurs il ne tourne pour l'instant que sur Mega (2 moteurs max sur uno). En dernier ressort ce ne serait pas impossible.

Ce que je suis en train d'écrire maintenant permet sur Uno 16000 pas/s, soit 4000 pas/s pour 4 moteurs qui tournent en même temps, mais c'est pas encore abouti. Mais je ne suis pas sûr de pouvoir y mettre les accélérations. Cela ralentit le code de façon considérable (il y a une racine carrée à calculer). C'est pour cela qu'accelStepper est un peu lent.

Bonjour ! désolé j'ai pris un petit break pour noël. d'ailleurs : bonne fêtes de fin d'année.

Merci pour la commande :while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0))
Ca marche bien, j'ai pu bien avancer.
Voici un brouillon du code qui pour l'instant devrai être satisfaisant. Normalement je devrais pouvoir :

  • Controller plusieurs moteurs
  • Controller la distance, la vitesse et l'accélération de chacun a chaque mouvement
  • Dire à a certain moteur ayant fini leur mouvements d'attendre les autres avant d'enchainer le prochain mouvement.
  • les arrêté tous une fois la chorégraphie fini et de recommencer dans X temps.

J'y ai ajouté aussi un chrono qui me dis combien de temps dure la choré

#include <AccelStepper.h>
#define tours 800
AccelStepper stepper1(AccelStepper::DRIVER, 2, 3);
AccelStepper stepper2(AccelStepper::DRIVER, 8, 9);

unsigned long MS;
unsigned long start;


void setup()
{
  Serial.begin (9600);                  // Serial.begin (115200);
  start=millis();
}

void loop() {

//chrono

  MS = millis()-start;
/*
  centitot1 = (MS % 1000) / 10 ;        // centieme to display
  secotot1 = (MS / 1000) % 60 ;         // second to display
  minutot1 = (MS / 1000) / 60 ;         // minute to display
*/
  Serial.print ((MS / 1000) / 60);      // minutes
  Serial.print ("' ");
  Serial.print ((MS / 1000) % 60);      // secondes
  Serial.print ("'' ");
  Serial.println (MS % 10);           // millièmes
}  
stepper1.setMaxSpeed(300.0);
stepper1.setAcceleration(500.0);
stepper2.setMaxSpeed(300.0);
stepper2.setAcceleration(500.0);


//chorégraphie


stepper1.moveTo(1*tours);
stepper2.moveTo(2*tours);
while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0))
{
  stepper1.run();
  stepper2.run();
 }
while (stepper2.distanceToGo() != 0)
{stepper1.stop();
stepper2.run();}
if (stepper2.distanceToGo() == 0)

//mouv2


stepper1.setMaxSpeed(600.0);
stepper1.setAcceleration(500.0);
stepper2.setMaxSpeed(600.0);
stepper2.setAcceleration(100.0);
stepper1.moveTo(3 *tours);
stepper2.moveTo(2000);
// faire avancer
while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0))
{
  stepper1.run();
  stepper2.run();
 }
 
 // donner les ordres de départ pour le toisième mouvement
stepper1.moveTo(4000);
stepper2.moveTo(5000);
// faire avancer
while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0))
{
  stepper1.run();
  stepper2.run();

 }
while (stepper2.distanceToGo() != 0)
{stepper1.stop();
stepper2.run();}
if (stepper2.distanceToGo() == 0)
{stepper1.stop();
stepper2.stop();}
delay (5000);
}

Maintenant il faut que je le teste IRL une fois que mon installation sera en place, en commençant la composé cette chorégraphie des moteurs.

vileroi:
C'est quoi ces références ? C'est comme quand on veut employer une bonne et qu'on lui demande où elle a travaillé avant? Il faut que je donnes un CV?
Si c'est pour la référence de QuickStep , il est disponible ici.

Hahaha. Non en fait je n'avais pas saisis que tu avais composé Quickstep. Mais du coup ca concerne la vitesse des moteurs ?

vileroi:
Il manque l'unité. si c'est des tr/mn, c'est pas la peine d'y penser.

Non c'est le nombre que je met dans setMaxSpeed(); mais je n'ai aucune idée de l'unité. Serait-ce des pas par seconde ?

désolé j'ai pris un petit break pour noël

Il n'y a pas a être désolé. On ne pointe pas, c'est un hobby.

Ca marche bien, j'ai pu bien avancer.

Cela fait plaisir.

void loop() {
//chrono
  MS = millis()-start;
/*
  centitot1 = (MS % 1000) / 10 ;        // centieme to display
  secotot1 = (MS / 1000) % 60 ;         // second to display
  minutot1 = (MS / 1000) / 60 ;         // minute to display
*/
  Serial.print ((MS / 1000) / 60);      // minutes
  Serial.print ("' ");
  Serial.print ((MS / 1000) % 60);      // secondes
  Serial.print ("'' ");
  Serial.println (MS % 10);           // millièmes
}  
stepper1.setMaxSpeed(300.0);

Bizarre: derrière loop l'accolade ouvrante correspond à celle qui se ferme après millièmes. Du coup
stepper1.setMaxSpeed(300.0); n'est plus dans loop. Le compilateur devrait râler.

Dans ton programme, il faudrait commencer par faire une fonction du style
mouvement(MaxSpeed1, Acceleration1, toGo1, MaxSpeed1, Acceleration2, toGo2, attente)
Cela permettra plus facilement de rajouter des mouvements sans avoir des copies du code. Voir après ou pas de mettre tout ceci dans un tableau.

Quickstep. Mais du coup ca concerne la vitesse des moteurs ?

QuickStep est un équivalent de AccelStepper, mais avec quelques différences. Pour moi il est mieux, sinon je ne l'aurais pas écrit. Il y a trois grosses différences:

  • pour un seul moteur, il tourne 150 fois plus vite. C'est important si on passe en micros-pas. Mes moteurs ont des phénomènes de bruit et de résonances en mode pas. Et si je veut passer en mode 16 micro-pas, il faut donner 16 fois plus d'ordres. Je ne sais pas si on peut garder les 1000pas/s pour 4 moteurs avec accelstepper, mais si c'est le cas, pour 4 moteurs QuickStep est encore 30 fois plus rapide.
  • QuickStep utilise des interruptions. Une fois un ordre donné, il tourne sans avoir besoin d'appeler une fonction run(). Inconvénient, il faut un timer. Pour l'instant il faut un timer par moteur, et il n'y en a qu'un sur une uno. Dans un mois peut être, avec un timer je ferai tourner plusieurs moteurs. Je sais le faire, mais il faut encore l'écrire.
  • Comme je connais bien l'auteur, si il y a une modification à faire, c'est possible.

Serait-ce des pas par seconde ?

Oui, ou plutôt des impulsions par seconde. Si on est en mode demi-pas c'est des demi-pas par seconde...

vileroi:
Bizarre: derrière loop l'accolade ouvrante correspond à celle qui se ferme après millièmes. Du coup
stepper1.setMaxSpeed(300.0); n'est plus dans loop. Le compilateur devrait râler.

Oui, je l'ai corrigé après coup. De toute façon le chrono est seulement la a titre informatif. Je ne compte pas le laisser dans le code final.

vileroi:
Dans ton programme, il faudrait commencer par faire une fonction du style
mouvement(MaxSpeed1, Acceleration1, toGo1, MaxSpeed1, Acceleration2, toGo2, attente)
Cela permettra plus facilement de rajouter des mouvements sans avoir des copies du code. Voir après ou pas de mettre tout ceci dans un tableau.

C'est clair. Mais il faut que je commence à vraiment travailler sur cette chorégraphie maintenant que le code est a peu près comme je le veux. Mon échéance est le 14 janvier pour ce projet et j'ai encore un tas d'autre choses à faire.
J'ai commencer à regarder l'écriture en tableaux et ca peut être très utile, mais pareil je commence à manquer de temps. Pareil pour Quickstep et la fonction Millis(), j'ai vraiment envie d'en savoir plus, je prendrais ce temps-là plus tard. Ca te laissera le temps d'écrire la suite.
Après si malgré tout je bloque pendant mon montage, j'approfondirais en urgence, bien évidemment.

Par ailleurs ce dispositif n'est qu'une partie (la plus compliquée) d'une installation qui automatise toute une pièce.
Une installation qui alterne tour à tour motorisation (nema 17 + tb6600), lumière (controlée par relai) et peut être musique (module YX5300 que je vais commencer à tester à sa reception mercredi). Tout ça va demander plus de kilooctets, de ram et de pins. Je pensais donc centraliser toute l'installation sur un arduino Méga, plutôt que sur plusieurs plusieurs Uno, ce qui améliorera sans doute la synchronisation, surtout au démarrage.

Pour ce qui est de l'unité de setMaxSpeed() j'aimerais comprendre un peu mieux, ainsi que setAcceleration et aussi la division de pas avec le driver.
par exemple, j'ai mis les switch123 du TB6600 pour lui faire divisé les pas par 800
Dans mon code, j'ai #DEFINE une rotation = 800 pas

Quelle serait la méthode ou un exemple de calcul pour faire disons une rotation (donc 800 pas) en une seconde en fonction de setMaxSpeed (qui s'exprime donc en pas/seconde) et l'acceleration (qui serais en pas/seconde carré) ?

Désolé pour cette demande de cours de physique de 5ème

Heu... Si j'ai écris QuickStep c'est aussi parce que je ne comprenais pas bien ces fonctions. Mais je vais quand même essayer de répondre.

j'ai mis les switch123 du TB6600 pour lui faire divisé les pas par 800

Incorrect, cela ne divise les pas que par 4. le moteur est un 200 pas par tour (sauf rares exceptions) et dire 200 pas, c'est travailler en pas entiers. 400 c'est pour le demi pas et 800 c'est le quart de pas. Dans la pratique, on se moque du rapport et du nombre de pas du moteur, ce qui importe c'est le nombre 800.

Quelle serait la méthode ou un exemple de calcul pour faire disons une rotation (donc 800 pas) en une seconde en fonction de setMaxSpeed (qui s'exprime donc en pas/seconde) et l'acceleration (qui serais en pas/seconde carré) ?

Si on n'avait pas d'accélération, c'est facile, il faut faire 800 pas, soit setMaxSpeed = 800 (pas/s).
Les accélérations exprimées en pas/s2 me rappellent toujours la consommation des voitures américaines en miles par gallons. Ça fait quoi en l/100kms? Mais c'est normalisé.
Pendant la phase d'accélération:
On a quand même la chance que presque tout le monde fait des accélérations linéaires (pas/s2 constants).
L'accélération A c'est la dérivée de la vitesse V par rapport au temps t. La vitesse est donc
V = A.t + V0
V0 étant la vitesse initiale, en partant de l'arrêt on a
V = A.t
Et on va parcourir
L = A.t2/2 (pas)
Je ne sais plus intéger, mais si on dérive la distance par rapport au temps on a la vitesse (V=dL/dt)
Dans cette équation, on a bien A en pas/s2, c'est une vérification

Pendant la phase à vitesse constante:
V = Vmax (choisi par setMaxSpeed)
L = Vmax.t
Il y a deux cas, je ne traite que le premier avec une accélération et une décélérations identiques (en pas/s2)

  • on accélère, on passe à une vitesse constante et on décélère
  • on accélère, on a pas le temps d'atteindre la vitesse de croisière qu'il faut déjà décélérer. On n'a pas atteint la vitesse de croisière au milieu.
    Le cas ou on arrive pile poil à la vitesse de croisière au moment de décélérer est le cas limite qui appartient aux deux cas.

Mouvement complet:
La distance parcourue est
L = 2x(A.tacc2/2) + Vmax.tconst (1)
tacc est le temps que dure l'accélération
tconst est le temps ou l'on navigue à vitesse constante
le 2x c'est parce que le temps d'accélération est le même que le temps de décélération (à priori)
Le temps total T c'est
T = tacc + tconst (2)
Pour la phase d'accélération, au bout d'un temps tacc, on a atteint Vmax:
Vmax = A.tacc (3)
3 équations, 2 inconnues à supprimer : tacc, tconst
On a alors une équation entre T, L, Vmax et A. Pour L=800pas en T=1s, on peut choisir la vitesse maxi et en déduire l'accélération ou l'inverse, dans la limite du possible. L'équation n'est pas simple. Je te laisse faire:

  • de (3), on tire tacc que l'on injecte dans (1) et (2)
  • du coup on peut tirer tconst de (2) que l'on injece dans (1)

C'est la solution mathématique, scolaire.

Désolé pour cette demande de cours de physique de 5ème

Je ne suis pas sûr que tu saches ce que l'on peut attendre des 5èmes. Pas sûr que cela passe en terminale!

Une autre solution, c'est le tableur. On rentre les équations (3) puis (2) puis (1) avec Vmax et A donnés, puis on fait varier ces valeurs pour que le tableur donne L=800.
Attention, il y a pleins de couples (Vmax, A) possible. Si on accélère peu, Vmax sera grand, si au contraire l'accélération est forte, Vmax diminuera.

Pour les cachets d'aspirine, c'est dans l’armoire à pharmacie.

WAAW ... c'est dense et complet ! Mille mercis !
Bon évidemment, ça fait une plombe que j'ai pas fait de maths et les temporalités sont trop courtes pour que je puisse mettre en place les calculs pour ce projet, donc j'imagine que je vais y aller à tâtons. Mais ça m'intéresse trop ! J'ai hate d'avoir un peu de temps pour approfondir tout ça, comme ça les prochains projets seront réglés au poil de c*l.
Merci beaucoup !

J'ai commencer à travailler la chorégraphie des moteurs, et j'ai chercher à faire des départs et des arrivés différés sur un mouvement. Par exemple, si chaque moteur fais 20 tours, dire au moteur 2 de démarrer quand le moteur 1 à fais 5 tours, au moteur 3 de démarrer quand le moteur 2 à fais 5 tours, au moteur 4 de démarrer quand le moteur 3 à fais 5 tours.

J'ai essayer de travailler autour de ce code mais, le résultat est jamais probant :

#include <AccelStepper.h>
#define turn 800
AccelStepper stepper1(AccelStepper::DRIVER, 53, 52);
AccelStepper stepper2(AccelStepper::DRIVER, 8, 28);

void setup()
{ }

void loop() {

stepper1.setMaxSpeed(800.0); stepper1.setAcceleration(1500.0); stepper1.moveTo(1*turn); 
stepper2.setMaxSpeed(800.0); stepper2.setAcceleration(1500.0); stepper2.moveTo(1*turn);

while ((stepper1.distanceToGo() != 0) && (stepper2.distanceToGo() != 0))
{
  stepper1.run(); stepper2.stop(); 
 }

 if ((stepper1.distanceToGo() == 0) && (stepper2.distanceToGo() != 0))
{
stepper2.run(); 
}
stepper1.setMaxSpeed(800.0); stepper1.setAcceleration(1500.0); stepper1.moveTo(2*turn); 

{
   stepper1.run(); 
}

}

Est ce qu'il n'y aurait pas une manière de dire, selon toi :

stepper1.moveTo(20turn);
stepper2.moveTo(20
turn);

if (stepper1.distance to go == 5*turn)
{
stepper 2 run
}

Sans forcement avoir recours à Millis(), histoire de pas complexifier plus le code.
Après si Millis() reste la méthode la plus simple...

Sans forcement avoir recours à Millis(), histoire de pas complexifier plus le code.
Après si Millis() reste la méthode la plus simple...

Dans ce que tu as fait, si tu devais rajouter le même mouvement deux fois, il faudrait recopier tout le code deux fois. Si il y a 10 mouvements, le code deviendra très long et il sera très difficile de voir ou on en est.

En donnant des ordres et en attendant le temps nécessaire, on n'a pas besoin de tester si il reste des pas à faire ou pas.

Si je devais le faire, je ferais certainement un tableau contenant les différents ordres. Si c'est pour faire un seul mouvement ou deux, on écrit directement le code? Pour un nombre d'ordres plus important, il vaut mieux faire un tableau. Cela permet aussi de rajouter, de modifier des mouvements plus facilement. Par exemple un tableau (ou plusieurs) contenant

  • l'heure à partir du début de la chorégraphie pour lequel il faut donner un mouvement.
  • pour chaque moteur un tableau contenant les paramètres du mouvement (vitesse, accélération, nombre de pas)
    cela peut donner avec plusieurs tableaux (plus simple à comprendre)
uint32_t temps[] = { <valeurs des temps> };
float vitesseMoteur1[] = { <valeurs des vitesses du moteur 1> };
float accelerationMoteur1[] = { <valeurs des accélération du moteur 1> };
uint8_t nbPasMoteur1[] = { <valeurs des nombre de tours du moteur 1> };
float vitesseMoteur2[] = { <valeurs des vitesses du moteur 2> };
...

for (mouvement = 0; mouvement < N; mouvement++)
{ 
  if (millis() - TempsDuDepart < temps[mouvement]; // attente de l'instant de début du mouvement
  {
     if (vitesseMoteur1[mouvement] > 0) // On demande à cet instant un départe de mouvement sur le moteur 1
       stepper1.setMaxSpeed(vitesseMoteur1[mouvement]); stepper1.setAcceleration(accelerationMoteur1[mouvement]); stepper1.moveTo(nbPasMoteur1[mouvement]*turn); 
     if (vitesseMoteur2[mouvement] > 0) // On demande à cet instant un départ de mouvement sur le moteur 2
       stepper2.setMaxSpeed(vitesseMoteur2[mouvement]); stepper2.setAcceleration(accelerationMoteur2[mouvement]); stepper2.moveTo(nbPasMoteur2[mouvement]*turn);

    stepper1.run(); // Qu'il tourne ou pas
    stepper2.run();
  }

Ou bien (plus facile pour éditer la chorégraphie) avec une structure:

struct Evenement
{
uint32_t temps;
float vitesseMoteur1;
float accelerationMoteur1;
uint8_t nbPasMoteur1;
float vitesseMoteur2;
float accelerationMoteur2;
uint8_t nbPasMoteur2;
};


Evenement evenements[]={
    (0,         800.0, 1500.0,  1,            0.0,      0.0,  0), // Le moteur 1 démarre seul  
    (5000,       0.0,      0.0,  0,         800.0, 1500.0,  1), on laisse le moteur 1 continuer, et on rajoute le moteur 2 après 5s
   ...};

...

for (mouvement = 0; mouvement < N; mouvement++)
{ 
  if (millis() - TempsDuDepart < evenements[mouvement].temps; // attente de l'instant de début du mouvement
  {
     if (evenements[mouvement].vitesseMoteur1 > 0) // On demande à cet instant un départ de mouvement sur le moteur 1
       stepper1.setMaxSpeed(evenements[mouvement].vitesseMoteur1); stepper1.setAcceleration(evenements[mouvement].accelerationMoteur1); stepper1.moveTo(evenements[mouvement].nbPasMoteur1*turn); 
     if (evenements[mouvement].vitesseMoteur2 > 0) // On demande à cet instant un départ de mouvement sur le moteur 2
       stepper2.setMaxSpeed(evenements[mouvement].vitesseMoteur2); stepper2.setAcceleration(evenements[mouvement].accelerationMoteur2); stepper2.moveTo(evenements[mouvement].nbPasMoteur2*turn); 

    stepper1.run(); // Qu'il tourne ou pas
    stepper2.run();
  }

Ce code n'est pas testé, il se peut qu'il y ait des erreurs.
Il est possible de rajouter avant de demander un nouveau déplacement un test pour vérifier qu'il ne reste plus de pas à faire.

On peut bien entendu remplacer les attentes de temps millis() par des boucles d'attente "fin du mouvement", mais pour décrire les mouvements cela devient plus dur car pour:

Par exemple, si chaque moteur fais 20 tours, dire au moteur 2 de démarrer quand le moteur 1 à fais 5 tours, au moteur 3 de démarrer quand le moteur 2 à fais 5 tours, au moteur 4 de démarrer quand le moteur 3 à fais 5 tours.

il faudra dire si il n'y a pas d'accélérations:
à t=0, le moteur 1 fait 5 tours
à t=5s le moteur 1 fait 5 tours et le moteur 2 fait 5 tours
à t=10s le moteur 1 fait 5 tours et le moteur 2 fait 5 tours et le moteur 3 fait 5 tours
à t=15s le moteur 1 fait 5 tours et le moteur 2 fait 5 tours et le moteur 3 fait 5 tours et le moteur 4 fait 5 tours
à t=20s le moteur 2 fait 5 tours et le moteur 3 fait 5 tours et le moteur 4 fait 5 tours
à t=25s le moteur 3 fait 5 tours et le moteur 4 fait 5 tours
à t=30s le moteur 4 fait 5 tours
Avec les accélérations on peut connaître le temps auxquels il faut démarrer les moteurs parce qu'en nombre de tours quand on va démarrer le moteur 2, quand le moteur aura fait 5 tours, le moteur 1 en aura fait un peu plus. Combien?

En passant avec le temps cela peut donner:

Evenement evenements[]={
    (0,         800.0,   1500.0,  1,            0.0,      0.0,  0,            0.0,      0.0,  0,            0.0,      0.0,  0),
    (5100,        0.0,      0.0,  0,          800.0,   1500.0,  1,            0.0,      0.0,  0,            0.0,      0.0,  0),
    (10200,       0.0,      0.0,  0,            0.0,      0.0,  0,          800.0,   1500.0,  1,            0.0,      0.0,  0),
    (15300,       0.0,      0.0,  0,            0.0,      0.0,  0,            0.0,      0.0,              800.0,   1500.0,  1)
};

si en tournant à 1tr/s, les 5 premiers tours se feraient en... disons 5,1s