Go Down

Topic: [Moteurs PAP] un code qui marche? (Read 9997 times) previous topic - next topic

Super_Cinci

Salut la communauté!

Alors j'ai fait une petit électronique simple, on rentre avec deux fils et on sort sur les 4 bobines du moteur pas à pas. en fait, j'ai fait un simple démultiplexeur 2 => 4.

Mais voilà, histoire de, j'ai mi ce code là :

Code: [Select]

void loop(){
  PORTD += 0x04; // interface connectée sur D3 et D4, on fait tourner la séquence { 00, 01, 10, 11}
  delay(analogRead(A0);    // potar sur A0 pour la vitesse
}


ça marche, mais pas moyen d'aller vite, le moteur déraille tout de suite!

Alors j'ai regardé avec mon oscillo, ben franchement, le signal gigote dans tous les sens (entre le delay et l'analogRead...), donc normal que le moteur ne suive pas.

j'ai ressorti un vieux montage à base de CMOS, un oscillateur, compteur, démultiplexeur, et là, le moteur répond impec (tant qu'on lui laisse le temps d'accélérer bien sur!)

Quelqu'un a un bout de code à base de vraies interruptions qui marche bien pour faire aller le moteur super vite? Sinon, je le ferai, mais bon, autant travailler ensemble ;)

j'ai ouvert la lib stepper, bouh que c'est laid! que des int 16 bits, des digitalWrite()... Bref, tout ce qu'il faut pour faire une catastrophe!

3Sigma

J'ai ça (voir code dans fichier attaché) qui fonctionne nickel avec ce moteur (http://www.pololu.com/catalog/product/1200) et ce driver (http://www.pololu.com/catalog/product/2128).

Je ne suis pas sûr que ça corresponde vraiment à ce que tu veux mais si ça peut te donner des idées, ça sera déjà pas mal.

Super_Cinci

Salut et merci,

Il y aurait de l'idée, mais l'utilisation de la fonction tone() ne me convient pas trop. D'accord, ça permet certainement de générer une belle horloge pour le driver, mais avec ça, tu ne contrôles pas du tout le nombre de pas. Mon idée est de pouvoir "dire" faire x pas en avant ou en arrière, et que tout ça passe bien sûr par une phase d'accélération et décélération, avec toutes les contraintes de fonctionnement (vitesse max, conditions de charge...).

J'ai commencé à plancher sur l'utilisation d'un timer qui génère une horloge de fonctionnement, et quelques contrôles autour, mais j'imagine que quelqu'un a déjà planché sur le truc, je ne voudrais pas réinventer l'eau chaude, simplement adapter sa température...

fdufnews

Faudrait regarder dans les codes des CNC ou des imprimantes 3D.
Il y en a plusieurs qui utilisent des cartes arduino

Super_Cinci

De tous les projets de CNC que j'ai pu voir, les déplacements sont extrêmement lents, et je ne pense pas que ce soit dû aux "vitesses de coupe", mais plutôt de la difficulté de faire tourner deux moteurs PAP en même temps, et surtout synchros dans le cas de diagonales.

Je n'en ai encore vu aucun proposant des déplacements "rapides", les vitesses des moteurs semblent fixes. Le plus dur étant la gestion de l'accélération (surtout de plusieurs moteurs qui ne tournent pas à la même vitesse mais doivent être synchros) qui permettrait de gagner énormément. Je pense que tout est faisable avec un petit AVR, mais va falloir lui rentrer profondément dedans pour arriver à ce que j'en attends.

Je vais quand même retourner faire un tour sur gogol...

fdufnews

Google et le forum sont tes amis:
2 ème résultat en faisant une recherche sous google avec les mots clés "arduino stepper motor library"
Peut être intéressant http://forum.arduino.cc/index.php/topic,22400.0.html

B@tto

Bah GRBL niveau optimisation y'a pas mieux ... mais je comprend pas vraiment ton problème de vitesse : un moteur pas à pas, d'une manière générale il est difficile de dépasser 10 000 pas/s, et encore tu n'as plus qu'1/4 du couple ... et 10khz c'est tenable, même avec des digitalWrite()
Blog électronique : battomicro.wordpress.com
Photographie : www.interactive-celebration.fr
Fablab de Montpellier : www.labsud.org

Super_Cinci

et 10khz c'est tenable, même avec des digitalWrite()
pas tant que ça... car un digitalWrite() avec du delay(), ça sort tout sauf une fréquence assez stable pour un PAP. arrivé à une certaine vitesse, un petit écart de tempo dans un cycle représente une accélération qui souvent peut être fatale (perte de pas, voire décrochage complet du moteur).

J'ai regardé GRBL, en effet, il semblerait que ça soit pas mal, à regarder de près. (mais c'est lourd!)

Sinon, pour la lib de mikem, il faut lancer le plus souvent possible stepper.run(), sinon, le moteur ne tourne pas. Et de cette manière, on a toutes les chances de taper à côté et encore une fois, perdre toute la stabilité. C'est surtout ça que je recherche : la stabilité. GRBL se base sur une interruption timer, donc devrait être stable.

Super_Cinci

#8
Oct 24, 2013, 11:53 am Last Edit: Oct 24, 2013, 11:56 am by Super_Cinci Reason: 1
Bon... par rapport à ce que j'essaie de faire, GRBL va être trop long à nettoyer...

j'ai donc fait quelques calculs savants, en fonction des différents moteurs que j'ai sous la main et de leurs réducteurs associés...

comme ils viennent tous d'imprimantes et scanners, ils offrent des déplacements de courroie équivalents à des résolutions de 600 ou 1200DPI. J'ai regardé ce qu'un timer 8bits pouvait m'offrir en terme de vitesse de la courroie / fréquence de pas.

ma formule donne V(mm/s) = F(Hz) x 25,4 / R. (R = résolution en DPI ou en pas par pouce).

Je vous cache pas que derrière, il y a peut-être une éventuelle idée de CNC... j'ai déjà réussi à adapter l'algorithme de Bresenham pour faire un déplacement en ligne droite en 3D (du point (X1, Y1, Z1) au point (X2, Y2, Z2) ) avec accélération et décélération, à partir d'une interruption timer. Sur papier, car je n'ai rien monté en mécanique pour l'instant...

Mais voilà, je bute (plus pour très longtemps) sur l'accélération, car je voudrais dans un premier temps qu'elle soit constante et c'est pas évident, car la config du timer se fait en secondes² alors que l'accélération est en 1/s². je peux passer par tableau, mais il va me falloir plusieurs tableaux... ou utiliser un timer dédié qui génère l'accélération, mais là encore, ça me fera deux timers par moteur, on va vite être limité.

Bref, pour rester à 1 timer par moteur (pour gérer au besoin des déplacements indépendants), avec une accélération moyenne de 10mm.s-2 et rester dans des calculs 8 bits, j'obtiens de vitesse comprise entre 3 et 41mm.s-1 (donc normalement, j'atteins la vitesse max en 3 secondes)... Mais il y a un mais, car les changements de vitesses se font par paliers, et pas sûr que la moteur accepte le dernier palier (de 919Hz à 976Hz d'un coup, comme ça!) va falloir tester! Et bien sûr, en charge, car l'inertie d'une charge joue beaucoup sur la capacité à accélérer!

je vous tiens au courant...

vince3838

Salut,

J'ai bidouillé un code pour gérer 3 moteurs pour un robot "delta" avec une rampe linéaire pour éviter de sauter des pas au démarrage en charge, ça marche très bien chez moi, j'ai utilisé  l'algorithme de Bresenham.

voila un bout de code:

Code: [Select]

  if(val[0]-prev[0]>0){digitalWrite(3,HIGH);}else{digitalWrite(3,LOW);} //determination du sens
     if(val[1]-prev[1]>0){digitalWrite(6,HIGH);}else{digitalWrite(6,LOW);}
     if(val[2]-prev[2]>0){digitalWrite(9,HIGH);}else{digitalWrite(9,LOW);}

     for(int i=0;i<3;i++){d[i] = val[i] - prev[i];}  //calcul de la course a parcourir   

     long m= max(max(abs(d[0]),abs(d[1])),abs(d[2])); // identifier distance maxi pour denominateur:

     for(int i=0;i<3;i++){r[i]=(float)abs(d[i]) / (float) m;a[i]=0;} // debut de calcul des ratios, le plus grand sera égal à 1
     
      float v=m*1/Rampe;     // defini la plage d'acceleration et de deceleration (10% de la course en acceleration et 10% en deceleration, 80% en vitesse max);
      float w=m-v;
     
     
     for(float n=0;n<m;n++){ //debut boucle de mouvement
       float CoefSpeed=1.00; // par defaut coef de vitesse au max(ni acceleration ni deceleration)
         if (n<v){CoefSpeed=map(CoefSpeed,n,v,1.70,1.00);}
         if (n>w){CoefSpeed=map(CoefSpeed,n,w,1.00,1.70);}

     
        for(int i=0;i<3;i++){a[i]=a[i]+r[i];} // on incrémente:
   
    //si erreur >=1 on fait une step, puis on decremente l'erreur
    //les stepX... juste pour info du nombre réel de steps effectué
    if(a[0]>=1.00){a[0]--;reel[0]++;digitalWrite(2, HIGH);delayMicroseconds(delayUs);digitalWrite(2, LOW);}
    if(a[1]>=1.00){a[1]--;reel[1]++;digitalWrite(5, HIGH);delayMicroseconds(delayUs);digitalWrite(5, LOW);}
    if(a[2]>=1.00){a[2]--;reel[2]++;digitalWrite(8, HIGH);delayMicroseconds(delayUs);digitalWrite(8, LOW);}   
    delayMicroseconds(Speed*CoefSpeed);

} //vitesse globale des moteurs à définir suivant installation
 
  while(1){
   
    boolean rattrapageOK = true;
  if(reel[0] < abs(d[0])){reel[0]++;digitalWrite(2, HIGH);delayMicroseconds(delayUs);digitalWrite(2, LOW);rattrapageOK = false;}
  if(reel[1] < abs(d[1])){reel[1]++;digitalWrite(5, HIGH);delayMicroseconds(delayUs);digitalWrite(5, LOW);rattrapageOK = false;}
  if(reel[2] < abs(d[2])){reel[2]++;digitalWrite(8, HIGH);delayMicroseconds(delayUs);digitalWrite(8, LOW);rattrapageOK = false;}
  delayMicroseconds(Speed);
  if(rattrapageOK = true){break;}
  }
 
    // RAZ DELTA CAR MOUVEMENT EFFECTUE
    for(int i=0;i<3;i++){prev[i] = val[i];prevt[i] = t[i];reel[i]=0;}
} // if error ==0
  return(error);

Super_Cinci

Je vois, mais tu utilises des digitalWrite() et delay(), et ces fonctions ne sont pas assez temporellement stables pour envoyer du boudin dans un PAP. En plus, les calculs sur float ne prennent jamais deux fois le même temps d'exécution. Je cherche à pondre des fréquences de ouf (quelques KHz). mais si à un moment, sur un régime établi, un pas décide de mettre du temps à venir, alors ça équivaudrait à ralentir le moteur. On s'en fout un peu, car on les compte, les pas, donc on sait où on est. sauf que si le moteur n'arrive pas à ralentir assez, ça peut suffire à ce qu'il soit quand même trop loin du pas suivant, et donc il déraille.

L'exemple d'un défilé militaire : tant que tout le monde marche au pas, ok, ça pète! Mais si un fantassin met le pied à côté, c'est tous les autres derrière qui vont le suivre, et là, un 14 juillet sur les champs, ça va pas être dans le goût du chef, blâme général.

Ou encore le coup de l'escalier, si tu rates une marche, tu as toutes les chances de rater toutes les autres et ça fait mal. (amuse-toi à changer la hauteur d'une seule marche de 2cm, plus personne n'arrivera à monter ou descendre l'escalier sans se casser lag.).

sur des fréquences jusqu'à 100Hz, bah... ça le fait, les temps sont assez long pour que le courant dans les bobines prenne le dessus. mais si on va vite, le courant reste faible, donc il n'y a plus cet effet bourrin qui force le pas...

il faut que je teste mon code pour voir jusqu'où peut aller un PAP. je prends pour exemple une bécane que j'ai chez moi (une découpeuse de vinyl de 2m de long, une CNC de rêve), sa résolution est de 1016 DPI (400 ppcm), et quand tu vois le cutter parcourir les 2m (80000pas) en 4 secondes (20KHz?), on se dit que les PAP, bien réglés, ça fait des malheurs (vu le prix de la machine, elle ne rate jamais un pas)! d'ailleurs, les CNC homemade, ça tourne pas bien vite, et j'imagine que justement, c'est une question de stabilité des pas qui fait qu'on ne peut pas aller plus vite...

B@tto

delay() est basé sur un timer, donc parfaitement temporellement stable. Si tu passes par des manipulations de port directe alors il n'y a aucune raison que ta fréquence fasse du boudin
Blog électronique : battomicro.wordpress.com
Photographie : www.interactive-celebration.fr
Fablab de Montpellier : www.labsud.org

Super_Cinci

Code: [Select]

unsigned long micros() {
unsigned long m;
uint8_t oldSREG = SREG, t;

cli();
m = timer0_overflow_count;
t = TCNT0;
if ((TIFR0 & _BV(TOV0)) && (t < 255)) m++;
SREG = oldSREG;

return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

void delay(unsigned long ms)
{
uint16_t start = (uint16_t)micros();

  while (ms > 0) {
if (((uint16_t)micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
On est quand même dans l'approximatif, là, non? Quand je parle de stabilité, c'est que sur plusieurs appels, la fonction produit exactement le même temps. là, c'est loin d'être le cas.

B@tto

Je vois pas l'approximation :o

micros() est incrémenté par l'overflow du timer, je vois pas ce qu'il y a de hasardeux !

Et puis il faut avoir le sens des réalités : à 10 khz ça fait des périodes de 100 µs, même à 5% d'erreur c'est pas ça qui fera décroché ton PAP ... digitalWrite(), lui, est hasardeux (je suis tombé sur un topic d'un mec qui avait testé, en moyenne c'est 5-7µs, mais des fois ça tape sans raison à 17-18).

Après en gestion multi moteurs ça devient particulièrement pertinent d'utiliser les timers car en delay() c'est ingérable

Blog électronique : battomicro.wordpress.com
Photographie : www.interactive-celebration.fr
Fablab de Montpellier : www.labsud.org


Go Up