sincronizzazione motore stepper e nastro trasportatore con encoder

Salve, avrei la necessità di sincronizzare un nastro trasportatore mobile (che chiamiamo “slave”) a più nastri esistenti (non contemporaneamente) controllati ad inverter (che chiamiamo “master”) che hanno velocità variabili. Le velocità variano dallo 0 giri/min. a un max di 240 giri/min. per cui avevo pensato di usare un encoder con rotella a contatto sul nastro “master” esistente, che rileva la velocità del nastro, per sincronizzare uno stepper montato sul nastro trasportatore mobile “slave”. In teoria, ad ogni giro di encoder deve corrispondere un giro di motore, e lo deve fare sia a 10 giri/min che a 200 giri/min e seguire le eventuali variazioni di velocità in perfetto sincronismo con il nastro “master”!
La mia prima domanda: è fattibile?
Indico il materiale in mio possesso per il progetto:

Arduino Duemilanove
encoder magnetico: ris. 32 imp. per giro
Eltra EL58H512: ris.2048 (5124) imp. per giro
Eltra EL58H90Z5: ris.360 (90
4) imp. per giro
Driver: Stepperonline mod DM860Y
Motore: Stepperonline NEMA 34 - mod. 34HE45 - 6.0A - 8.2Nm - 200 passi - 4fili

Ho provato con lo sketch preso in prestito da Kabuby che posto sotto e funziona con velocità da 0 a qualche decina di giri max ed a seconda dell’encoder che monto, ovvero:

Driver settato a 800 microstep con encoder ris. 2048 imp./giro ha un movimento molto fluido ma velocità max bassissima, mentre con l’encoder magnetico con ris. 32 imp/giro il motore risulta più nervoso alle basse velocità ma ha una velocità max maggiore ma, comunque, non occorrente alle mie necessità!
La mia seconda domanda: si riesce, con qualche modifica allo sketch postato, a fare quello che vorrei?

Cordialmente,
Cappuccio Domenico

/*  Digital Pin 2 accepts external interrupts. Pin1 of a rotary encoder
    is attached to DigitalPin2. An interrupt routine will be called
    when pin1 changes state, including noise.
    This will be made more efficient with hardware debouncing.
    */
int pin1 = 2;
int pin2 = 3;
long counter;
boolean goingUp = false;
boolean goingDown = false;

//parte relativa al motore
const int Enable = 6;         // pin enable (blu)
const int Direzione = 7;      // pin direzione (verde)
const int Pulsazione = 8;     // pin pulsazione (grigio)

int sync = 20;

void setup()
{
  counter = 0;
  //Serial prints for debugging and testing
  Serial.begin(9600);

/* Setup encoder pins as inputs */
    pinMode(pin1, INPUT); // Pin 2
    pinMode(pin2, INPUT); // Pin 4

// encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, decoder, FALLING);

//parte relativa al motore
  pinMode(Enable, OUTPUT);        //pin 6
  pinMode(Direzione, OUTPUT);     //pin 7
  pinMode(Pulsazione, OUTPUT);    //pin 8

  pinMode(Enable, OUTPUT);        //pin 6
  pinMode(Direzione, OUTPUT);     //pin 7
  pinMode(Pulsazione, OUTPUT);    //pin 8


  digitalWrite(Enable, LOW);      //acceso
  
}

void loop()
{
//using while statement to stay in the loop for continuous
//interrupts
while(goingUp==1) // CW motion in the rotary encoder
{
goingUp=0; // Reset the flag
counter ++;

  for(int i=0;i<sync;i++){
  digitalWrite(Direzione, LOW);
  digitalWrite(Pulsazione, HIGH);
  digitalWrite(Pulsazione, LOW);
  delayMicroseconds(350);

  }


Serial.println(counter);


}

while(goingDown==1) // CCW motion in rotary encoder
{
goingDown=0; // clear the flag
counter --;


  for(int i=0;i<sync;i++){
  digitalWrite(Direzione, HIGH);
  digitalWrite(Pulsazione, HIGH);
  digitalWrite(Pulsazione, LOW);
  delayMicroseconds(350);

  }
Serial.println(counter);
}
}

void decoder()
//very short interrupt routine
//Remember that the routine is only called when pin1
//changes state, so it's the value of pin2 that we're
//interrested in here
{
if (digitalRead(pin1) == digitalRead(pin2))
{
goingUp = 1; //if encoder channels are the same, direction is CW
}
else
{
goingDown = 1; //if they are not the same, direction is CCW
}
}

Come da REGOLAMENTO, punto 7, il codice va racchiuso nei tag CODE e NON nei tag QUOTE ... ti prego di correggere il tuo post qui sopra. Grazie.

Guglielmo

Mi scuso, correzione effettuata, piccola distrazione!
Saluti!

Buonasera, forse è più semplice di quanto pensassi, o lo spero!
Ho provato a collegare i due canali A&B dell'encoder a due ingressi (pin 7 e 8 di Arduino) e settato due uscite ( pin 12 per DIR e 13 per CLK di arduino) collegato al driver stepper.
Il codice postato sotto e funziona!
Il problema è che avendo un motore a 200 step per avere un giro completo dovrei avere un encoder con risoluzione con multipli di 200 pul.
Infatti con un encoder da 360 pul non riesco a fare un giro completo del motore, mentre con quello da 512 pul vado oltre.
Per cui, in teoria, se collegassi un encoder a 2000 pul. avrei 5 giri di motore completi con 1 giro di encoder.
La mia domanda è:
Se io vado ad una velocità encoder di 60 giri al minuto avrei un frequenza di 2Khz!
Arduino riesce a gestire sugli ingressi ed uscite tali frequenze senza perdere passi?
Scusate la mia ignoranza in materia!
Spero in una vostra delucidazione!
Cordialmente
Cappuccio Domenico

int MOTOA = 12;                 // Dir motore pin digitale 12  
int MOTOB = 13;                 // Pul motore pin digitale 13  
int ENCODERA = 7;               // pin di input canale A encoder
int ENCODERB = 8;               // pin di input canale B encoder
int val = 0;                  // si userà val per conservare lo stato del pin di input  
  
void setup() {  
  pinMode(MOTOA, OUTPUT);       // imposta il pin digitale come output
  pinMode(MOTOB, OUTPUT);       // imposta il pin digitale come output  
  pinMode(ENCODERA, INPUT);     // imposta il pin digitale come input 
  pinMode(ENCODERB, INPUT);     // imposta il pin digitale come input 
}  
  
void loop() {  
  val = digitalRead(ENCODERA);  // legge il valore dell'input e lo conserva  
  
    
  if (val == HIGH) {          // controlla che l'input sia HIGH
    digitalWrite(MOTOA, HIGH);  // ecc.+  MOTORE A  
  }  
  else {  
    digitalWrite(MOTOA, LOW);   // ecc.-  MOTORE A 
  }  
    val = digitalRead(ENCODERB);  // legge il valore dell'input e lo conserva  
  
    
  if (val == HIGH) {          // controlla che l'input sia HIGH
    digitalWrite(MOTOB, HIGH);  // ecc.+  MOTORE B  
  }  
  else {  
    digitalWrite(MOTOB, LOW);   // ecc.-  MOTORE B
  } 
}
int MOTOA = 12;                 // Dir motore pin digitale 12  
int MOTOB = 13;                 // Pul motore pin digitale 13  
int ENCODERA = 7;               // pin di input canale A encoder
int ENCODERB = 8;               // pin di input canale B encoder
int val = 0;                  // si userà val per conservare lo stato del pin di input  
  
void setup() {  
  pinMode(MOTOA, OUTPUT);       // imposta il pin digitale come output
  pinMode(MOTOB, OUTPUT);       // imposta il pin digitale come output  
  pinMode(ENCODERA, INPUT);     // imposta il pin digitale come input
  pinMode(ENCODERB, INPUT);     // imposta il pin digitale come input
}  
  
void loop() {  
    val = digitalRead(ENCODERA);  // legge il valore dell'input e lo conserva  
  
    digitalWrite(MOTOA, val);  // ecc.+  MOTORE A  
 
    val = digitalRead(ENCODERB);  // legge il valore dell'input e lo conserva  
  
    digitalWrite(MOTOB, val);  // ecc.+  MOTORE B  

  }
}

Credo il codice sopra funzioni come il tuo ma senza le if

Tieni conto che i motori passa passo possono essere spinti oltre il limite della frequenza e poltre questa non perdono passo ma assumono un comportamento oscillatiorio.

In questo modo sembra che siano gli encoder che fanno eseguire i passi al motore.

Io penso che motore permettendo si riesce a superare i 2kHz. Ma poi c'è da vedere se arduino deve essere impegnato ad eseguire altro codice che se corposo ritarderà il loop e magari il primo encoder ha già compiuto la transizione ma la mcu ci arriva troppo tardi e quindi è come se ti fossi perso un passo.

Ciao.

Ti ringrazio per la risposta, in effetti il codice da te postato funziona (anche se c'era una parentesi graffa in più)
In pratica Arduino non deve fare altro quando l'encoder è in funzione, per cui dovrebbe andare tutto liscio.
Pensi che sia in grado di lavorare 24 ore al giorno?
Per quanto riguarda il discorso encoder, non ne ho trovati con risoluzioni da 1600 pul/giro (se non su richiesta e costerebbero una vagonata di euro) per cui userò quello in mio possesso che è di 2048 pul/giro accoppiando il motore con pulegge da 25 e 32 denti in modo tale da ristabilire il rapporto! (2048/1600 rapp. 1.28 - 32/25 rapp. 1.28)

Ciao.

Pensi che sia in grado di lavorare 24 ore al giorno?

mmmh...no questa certezza la devi creare testando il tutto, poi io mi chiederei cosa accade se si guasta qualcosa? cade l'aereo? Perdo 13 trilioni di euro?

Se le conseguenze di un guasto sono non accettabili si deve trovare una soluzione che limiti i danni.

Ricorda che il passo passo ha coppia ridotta ad alti reggimi. Il periodo di tempo (T) in secondi per una frequenza F vale T = 1/F. La frequenza F = 1/T.

2kHz sono 2000Hz 1/2000 = 0,0005 secondi ( 500us ). Il clock di arduino lavora a 16MHz ed inoltre quel codice si può ottimizzare (o addirittura eliminare arduino del tutto impiegando le logiche TTL).

Mentre i limiti di velocità/coppia motore non sono modificabili.

Ciao.

Buonasera, anche io penso che Arduino sia sprecato per questa applicazione! In effetti, credo, che non debba fare altro che amplificare il segnale di uscita dell'encoder per pilotare il driver stepper. Il problema è che non ho conoscenze tali da consentirmi di fare ciò, per cui se hai uno schemino o un link dove andare a prendere esempi te ne sarei grato!
P.S. se il tutto non funzionasse bene come vorrei, non ci saranno catastrofismi, ne prenderò atto e me ne farò una ragione! :wink:
Ti ringrazio per la risposta e le dritte e ti saluto cordialmente!