Allegro A4988 e Arduino (3)

luca 30/05/2013 28

In questa ultima parte del tutorial relativo al driver A4988, vedremo come realizzare un controller per regolare velocità e direzione di rotazione di un motore stepper.

Circuito

Utilizzeremo lo stesso circuito del post precedente:

  • un Arduino Uno;
  • un LCD Keypad shield;
  • un driver Pololu A4988 montato su breadboard;
  • un motore stepper NEMA17.

GUI

Il nostro controller darà la possibilità di regolare la velocità (da 0 a 70 RPM, giri/minuto) e la direzione di rotazione.

Sul display LCD verranno visualizzati velocità e direzione corrente e una progress bar:

La regolazione avviene tramite i 5 pulsanti disponibili:

  • UPDOWN regolano la velocità;
  • LEFTRIGHT regolano la direzione;
  • SELECT attiva lo stop di emergenza (velocità = 0).

Rotazione continua

Per garantire una rotazione continua, lo sketch di Arduino dovrà inviare al driver Pololu i comandi di step ad una frequenza costante.

Vediamo un esempio: per una velocità di 60RPM e con un motore da 200 passi / giro, Arduino deve inviare al driver (60*200)/60 = 200 comandi / sec ovvero un comando ogni 5ms.

Per garantire un timing così preciso, utilizzo gli interrupt generati dal Timer1 di Arduino come spiegato in questo articolo.

Su Playground esiste una comoda libreria per configurare tale Timer:

#include 
[...]
Timer1.initialize(100);
Timer1.attachInterrupt(timerIsr);

Con queste istruzioni, si configura il Timer1 per generare un interrupt ogni 100 millisecondi (0.1ms) e per chiamare, ad ogni interrupt, la funzione timerIsr().

La distanza temporale tra un comando di step e il successivo dipende dalla velocità attuale (nell’esempio sopra per 60RPM tale distanza è di 5ms). Visto che le velocità possibili sono soltanto 15 (da 0 a 70RPM con passo 5RPM), ho calcolato tale distanza (in ticks di 0.1ms) per le varie velocità e l’ho inserita in un array:

const int speed_ticks[] = {
-1, 600, 300, 200, 150, 120, 100, 86, 75, 67, 60, 55, 50, 46, 43};

All’interno della funzione timerIsr() incremento un contatore e – se ho raggiunto il numero di ticks per la velocità impostata – invio un comando di step al driver:

void timerIsr() {
 
  if(actual_speed == 0) return;
 
  tick_count++;
 
  if(tick_count == ticks) {  
 
    // make a step
    digitalWrite(PIN_STEP, HIGH);
    digitalWrite(PIN_STEP, LOW);
 
    tick_count = 0;
  }
}

Nella prossima pagina vedremo il resto dello sketch e un esempio di funzionamento…

Pagine: 1 2

28 Comments »

  1. Nikolai 20/08/2013 at 07:42 - Reply

    Hi Luca!
    Thank you very much. But there is one big prolema, I have it hangs does not work, the engine is spinning and the buttons are not controlled.
    Do “reset” button is working again controlled, then again hanging is not controlled by buttons.
    Using the Arduino Uno, tried Arduino Mega 2560 also does not work.
    Please help solve the problem

  2. Nikolai 26/08/2013 at 05:15 - Reply

    37 int previous_time;

    change to
    37 unsigned long previous_time;

  3. berlon 17/11/2013 at 09:33 - Reply

    Hi !
    Can i use your scheme with EasyDriver 4.4 ?
    Example here http://bildr.org/2011/06/easydriver/

    I think that 3 inputs from arduino is the same ..?!

    • luca 17/11/2013 at 10:38 - Reply

      Hi, it should work because the EasyDriver has the same STEP/DIR interface as the controller I used.
      Let me know!

  4. Paolo 15/12/2013 at 15:24 - Reply

    Caro Luca,
    Vorrei usare il tuo programma per collegare i seguenti componenti

    un Arduino Uno;
    un LCD Keypad shield;
    un driver Pololu DRV8825 montato su breadboard;
    un motore stepper NEMA 23

    Potresti darmi qualche suggerimento per i collegamenti?
    Grazie
    Paolo

    • luca 16/12/2013 at 14:14 - Reply

      Ciao Paolo,

      sostanzialmente i collegamenti sono gli stessi del mio esempio perché il driver DRV8825 è pin compatibile con quello usato da me (chip A4988).

  5. Antonio 09/01/2014 at 19:14 - Reply

    Salve Luca, in anzi tutto complimenti per i tutorial sono veramente interessanti e molto chiari.
    vorrei usare il tuo programma facendogli qualche modifica ma non ci riesco, potresti darmi una mano?
    Le modifiche sono le seguenti:
    1 dovrei pilotare in microsecondi anzi che in milisecondi
    2 sul display lcd anzi che visualizzare la velocità in RPM dovrei visualizzare il ritardo tra un passo e l’altro
    Spero che tu possa darmi una mano perché non ci riesco proprio.
    Grazie.

    • luca 14/01/2014 at 18:51 - Reply

      Ciao Antonio

      partiamo dalla prima richiesta perché mi “preoccupa”… difficilmente riuscirai ad avere passi della durata di microsecondi a causa dell’inerzia e della corrente; volevi ottenere una elevata velocità?

  6. Antonio 15/01/2014 at 09:24 - Reply

    Ciao Luca Grazie per avermi risposto, no non è per aumentare la velocità
    Ma per avere più scelta.
    Mi spiego meglio
    Sto usando
    Nema17 a 12v 1,2A 200 passi
    Arduino 2009
    Display lcd con tasti
    DRV8825
    Il tutto assemblato su una montatura equatoriale di un telescopico.
    Il motore deve far si che il telescopio compia un giro completo di 360 gradi in 24 ore sul asse AR, secondo la demoltiplica che ho usato per aumentare i giri e diminuire lo sforzo, il motore deve compiere un giro i circa 65 secondi e fin che vado a passi interi o a mezzi passi tutto ok ma se piloto a micropassi diciamo a 1/16 o 1/32 di passo con i millisecondi non riesco ad ottenere la rotazione nel tempo giusto.
    Praticamente dovrei impostare diverse velocità di rotazione aumentando di un secondo per ogni velocità e con i microsecondi dovrei riuscirci.
    Spero di essermi spiegato bene e grazie per la pazienza.
    Ciao

    • luca 27/01/2014 at 22:05 - Reply

      Ciao Antonio

      un giro in 65 secondi vuol dire che devi fare 200 passi in 65 secondi. Se anche vai a 32 microsteps, si parla sempre di 6400 “impulsi” ogni 65 secondi quindi circa 100 impulsi al secondo = 10ms a impulso… come mai ti serve invece lavorare con interrupt più frequenti?

  7. Marco 03/03/2014 at 20:04 - Reply

    Ciao Luca,
    Per prima cosa vorrei farTi i complimenti per questo progetto che formidabile!
    Forse ho sbagliato qualche cosa perchè ho comprato tutti i componenti hardware da Te usati, ma il programma non mi funziona bene.
    Infatti all’inizio il motorino va che è una meraviglia, ma se dopo un pó che , per esempio va a 45 rpm , decido di cambiare la velocità o invertire il senso in cui il motorino gira , accade che la tastiera della LCD keypad shield si blocca ed il motore non si puó più controllare.
    Potresti dirmi cosa sbaglio?
    Grazie in anticipo
    Marco

  8. IainA 25/04/2014 at 17:16 - Reply

    This code… is beautiful! You have no idea how useful this was (as I have many steppers and A4988’s lying around from various Repraps!)

    Thank you very much for posting a very concise and understandable set of tutorials!

    :D

  9. luca 10/07/2014 at 08:41 - Reply

    Buongiorno Luca

    Ho provato il tuo tutorial, ma il motore invece che girare effettua un passo avanti e uno indietro rimanendo sempre nella stessa posizione. Vorrei capire se e’ il motore che e’ rotto o la pcb della Pololu.

    grazie mille

    saluti

    • luca 14/07/2014 at 15:24 - Reply

      ciao Luca

      è possibile che sia collegato sbagliato al driver? uno step avanti e uno indietro sembra indicare che gli avvolgimenti del motore non sono collegati bene…

  10. alex 21/01/2015 at 13:13 - Reply

    Hi Luca!
    Greetings from Berlin :-)

    I was very glad to have seen your project, very great! I use it for my automatic Camera Slider
    I have downloaded and install the sketsch, it works but only in one direction. What’s wrong with it?

    photolink:
    https://www.dropbox.com/s/l1ygmvdgum1ui5n/Foto%2021.01.15%2013%2009%2059.jpg?dl=0

    lg. Alex

    • luca 21/01/2015 at 20:03 - Reply

      Hi Alex,

      the “arrow” on the LCD changes its direction? Check the connection between PIN3 of Arduino and the DIR pin of the stepper driver…

  11. antony 22/01/2015 at 00:30 - Reply

    ciao luca!
    volevo chiederti riusciresti a fare una variante del firmware dove e possibile usare un lcd 16×2 con convertitore ic2 ? ho chiedo troppo saluti antony attendo risposta !

  12. alex 24/01/2015 at 15:54 - Reply

    wow :-)

    you are right, the pin has bad contact
    now it moves in all directions

    video:
    https://www.dropbox.com/s/o38oc5defv8g4vj/Video%2023.01.15%2023%2018%2004.mov?dl=0

    one question…
    at 70 RPM is the motor rotation to slow for my slider, how can i more speedup the turns of the motor?

    i have already experiment..
    at higher speed i can´t change the direction the motor stops and hums

    • luca 31/01/2015 at 10:11 - Reply

      Hi Alex! what did you change in the sketch to add higher speeds?

  13. alex 03/02/2015 at 12:10 - Reply

    i have change folowing lines:

    // debounce time (milliseconds)
    #define DEBOUNCE_TIME 70

    // lookup table speed – ticks (interrupts)
    const int speed_ticks[] = {-1, 4000, 300, 200, 100, 80, 70, 60, 65, 60, 50, 48, 35, 25, 20};
    (4000 is for the timelapse operation)

    int unsigned long previous_time;

    // init the timer1, interrupt every 0.1ms
    Timer1.initialize(23);
    Timer1.attachInterrupt(timerIsr);

    when i change the timer1 value to higher the motor freaks out at higher speeds/turns.. can it be, that the motordriver is not fast enough?

    • luca 04/02/2015 at 21:53 - Reply

      Hi Alex: ticks is the number of “interrupts” between one step and the next one, so try reducing the last value and at the same time reduce also the Timer1.initialize() value

  14. Ruslan 21/02/2015 at 18:13 - Reply

    Hi, Luka!
    Thank you very much for your project, everything works fine. I have only one question, how to make the rotation of the stepper motor (FL57STH76-1006 1.8*) faster and reduce vibration?
    I changed the code and it helped a little:
    // init the timer1, interrupt every 0.05 ms
    Timer1.initialize(18);
    Timer1.attachInterrupt(timerIsr);

    Thanks in advance for your reply!

    • luca 24/02/2015 at 21:06 - Reply

      Hi Ruslan,

      you can also decrease the values in the speed_ticks[] vector… for example if you configure Timer1 to trigger every 0.02ms (Timer1.initialize(20)) a speed_ticks[] value of 100 makes the motor rotate 1 step / 2ms that is (for a 200 steps/rev motor) a revolution every 0.4 seconds = 150RPM

  15. Ruslan 26/02/2015 at 19:33 - Reply

    Luca, many thanks!!!
    I played around with “values in the speed_ticks[] vector” and reached the speed limit for my motor. Now I am happy :)
    Originally, my project was based on this: http://www.minie.airiclenz.com/hardware-2/hardware/ . Now I have 2 codes for timelapse and for video footage.

  16. Paolo 13/04/2015 at 21:28 - Reply

    Ciao come posso adattare il tuo fantastico progetto alla mia motor shield r3 e keypad lcd? ho reso tutto impilabile e perfettamente compatibile facendo tagliando A0 etc etc.

    Grazie del futuro supporto.

    • luca 13/04/2015 at 21:35 - Reply

      Ciao Paolo, purtroppo la r3 non consente un controllo “facile” dei motori stepper rispetto al driver che ho usato io quindi penso (non ho la shield) che richieda diverse modifiche perché funzioni.

  17. Paolo 13/04/2015 at 22:02 - Reply

    Ok, ti ringrazio davvero molto per la tempestiva risposta! incredibile!

    Grazie Molte.

Leave A Response »