aiuto per contare gli step durante la movimentazione di uno stepper motor

Salve a tutti,
sto prendendo confidenza con la movimentazione di un motore stepper in abbinamento ad un driver tb6600 e arduino uno. Il progetto attuale prevede di muovere il motore in un verso e in un altro con l'ausilio di due pulsanti e di contare gli step in un verso e nell'altro (quindi '+numero di step' per il verso antiorario e'-numero di step' verso antiorario) assumendo come zero della movimentazione il punto in cui l'albero sta al momento dell'accensione. Il valore lo visualizo du un display 16X2 con interfaccia I2C.
Posso assicurare che i cablaggi sono giusti e che la movimentazione con i pulsanti funziona a modo. Il mio cruccio è che non trovo un modo per definire il numero degli step: ho provato a ragionare pensando a definire una variabile StepCount e a questa variabile vorrei associare ogni step che fa quando premo il pulsante ossia vorrei che a questa variabile sia associato un valore da accumulare ogni volta che succede:

digitalWrite(DIR, LOW);
digitalWrite(ENA, HIGH);
digitalWrite(PUL, HIGH);
delayMicroseconds(200);

non so bene come tradurre questo in linguaggio di programmazione e sono ovviamente aperto a qualsiasi consiglio prevedendo di cambiare logica.

Allego il codice che ho realizzato finora:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

int switchACW = 2; //define anticlockwise temporary switch
int switchCW = 3; //define clockwise temporary switch
int PUL = 7; //define Pulse pin
int DIR = 6; //define Direction pin
int ENA = 5; //define Enable Pin

int valACW = 0;
int valCW = 0;
int StepCount = 0;

void setup() {


  pinMode (switchACW, INPUT);
  pinMode (switchCW, INPUT);
  pinMode (PUL, OUTPUT);
  pinMode (DIR, OUTPUT);
  pinMode (ENA, OUTPUT);
  pinMode (PUL, OUTPUT);
  pinMode (DIR, OUTPUT);
  pinMode (ENA, OUTPUT);

  lcd.init();

  lcd.backlight();
  lcd.print("Conteggio");
  lcd.setCursor(0, 1);
  lcd.print("step");
  delay(2000);
  lcd.clear();


}

void loop() {
  valCW = digitalRead(switchCW);

  valACW = digitalRead(switchACW);

  StepCount = 
  
    if (valCW == LOW)  {        //when clockwise temporary switch is pressed
  
    digitalWrite(DIR, LOW);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, HIGH);
    delayMicroseconds(200);
  }
  else
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, LOW);
    delayMicroseconds(200);
  }
  {
    if (valACW == LOW)   {      //when anticlockwise temporary switch is pressed
  
    digitalWrite(DIR, HIGH);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, HIGH);
    delayMicroseconds(200);
  }
  else
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, LOW);
    delayMicroseconds(200);
  }
  }
}

Così

if (valCW == LOW)  {        //when clockwise temporary switch is pressed
    StepCount++;
    digitalWrite(DIR, LOW);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, HIGH);
    delayMicroseconds(200);

fabpolli:
Così

if (valCW == LOW)  {        //when clockwise temporary switch is pressed

StepCount++;
    digitalWrite(DIR, LOW);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, HIGH);
    delayMicroseconds(200);

fabpolli:
Così

if (valCW == LOW)  {        //when clockwise temporary switch is pressed

StepCount++;
    digitalWrite(DIR, LOW);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, HIGH);
    delayMicroseconds(200);

Intanto ti ringrazio moltissimo del consiglio. ho integrato facendo stampare sul display la variabile ma ho visto che sia in un senso che nell'altro li continuava a contare. Per far sì che "se premo il pulsante antiorario segni positivamente e se premo il tasto orario segni negativamente ho pensato di sdoppiare le variabili chiamandole StepCountACW per l'antiorario e StepCountCW per l'orario e di nominare una funzione valStepTOT che faccia la sottrazione tra le due come nel codice:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

int switchACW = 2; //define anticlockwise temporary switch
int switchCW = 3; //define clockwise temporary switch
int PUL = 7; //define Pulse pin
int DIR = 6; //define Direction pin
int ENA = 5; //define Enable Pin

int valACW = 0;
int valCW = 0;
int StepCountACW = 0;
int StepCountCW = 0;

void setup() {


  pinMode (switchACW, INPUT);
  pinMode (switchCW, INPUT);
  pinMode (PUL, OUTPUT);
  pinMode (DIR, OUTPUT);
  pinMode (ENA, OUTPUT);
  pinMode (PUL, OUTPUT);
  pinMode (DIR, OUTPUT);
  pinMode (ENA, OUTPUT);

  lcd.init();

  lcd.backlight();
  lcd.print("Conteggio");
  lcd.setCursor(0, 1);
  lcd.print("step");
  delay(2000);
  lcd.clear();


}

void loop() {

  valCW = digitalRead(switchCW);

  valACW = digitalRead(switchACW);

  valStepTOT = (StepCountACW - StepCountCW);

 
    if (valCW == LOW)  {        //when clockwise temporary switch is pressed
    StepCountCW++;
    digitalWrite(DIR, LOW);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, HIGH);
    delayMicroseconds(200);
  }
  else
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, LOW);
    delayMicroseconds(200);
  }
  {
    if (valACW == LOW)   {      //when anticlockwise temporary switch is pressed
    StepCountACW++;
    digitalWrite(DIR, HIGH);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, HIGH);
    delayMicroseconds(200);
  }
  else
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, LOW);
    delayMicroseconds(200);
  }
  }

  lcd.print(valStepTOT);
  lcd.setCursor(0, 1);
}

Ora siccome non sono bravo a programmare mi dà questo messaggio di errore:

 error: 'valStepTOT' was not declared in this scope

   valStepTOT = (StepCountACW - StepCountCW);

   ^

exit status 1
'valStepTOT' was not declared in this scope

Sicuramente non l'ho scritta bene..
Come posso scriverla meglio?
Può andar bene la logic che ho proposto?

La logica potrebbe andare anche bene anche se superflua la sottrazione, è che ti mancano proprio le basi della programmazione e così facendo andrai poco lontano, comunque... il messaggio che ti da è perché usi la variabile sena averla prima istanziata ovvero definita dichiarando il tipo della variabile stessa un po' come hai fatto qui:

int StepCountACW = 0;

dove dichi che vuoi utilizzare la variabile StepCountACW e che questa conterrà dei numeri interi in un certo range e il suo valore iniziale è zero.
Per la variabile valStepTOT non hai fornito la dichiarazione. Non entro nel dettaglia di variabili globali, locali ecc. perché ti creerei solo confusione.
Con l'istruzione

StepCount++;

è come scrivere

StepCount = StepCount + 1;

non ti serve un'altra variabile per i due sensi di marcia del motore per poi calcolare gli step fatti in modo da visualizzarli sul display, di basta sommare se il motore va in un senso e sotrarre se va nell'altro.
Prova a codificare quest'idea, con una sola variabile è possibile farlo, a te risucire nella cosa :wink: .

fabpolli:
La logica potrebbe andare anche bene anche se superflua la sottrazione, è che ti mancano proprio le basi della programmazione...

mi metto all'opera.. grazie mille..
è successa anche un'altra cosa.. il motore gira molto più lentamente da quando ho inserito la variabile StepCount nei cicli if..

>LaTev: ... l'ho detto mote volte ... quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce. Gli utenti da device "mobile" ringrazieranno per la cortesia :wink:

Guglielmo

P.S.: Ho "tagliato" io il tuo "quote" ...

gpb01:
>LaTev: ... l'ho detto mote volte ... quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce. Gli utenti da device "mobile" ringrazieranno per la cortesia :wink:

Guglielmo

P.S.: Ho "tagliato" io il tuo "quote" ...

ok grazie mille

Continua a rimanere un problema che non mi spiego..
inserendo la variabile StepCount++ all'interno del ciclo if il motore si è considerevolmente rallentato e lo posso vedere andare a scatti.. come maisuccede questo?

L'istruzione ci mette un po' ad essere eseguita ma mi pare strando che ti rallenti così tanto, non è che ad ogni incremento di step scrivi sull'lcd? Perché quello si che porta via tempo.
Se è così aggiorna l'lcd non ad ogni ciclo di loop ma ogni tot millisecondi e vedi come si comporta, altrimenti se NON stai scrivendo sull'lcd ad ogni ciclo di loop posta il codice che stai usando e vediamo cosa può essere

Sì in realtà gli ho imposto di scrivere ogni volta sull'lcd... gli imposto un delay..

noooo delay è mortale ti blocca tutta la procedura devi usre millis(), se non l'hai mai usato per capire le basi con cui si usa millis() consiglio prima la lettura di QUESTO post esplicativo, dopo di che lo studio di come si usa la funzione millis(), prima QUI, poi QUI e QUI e QUI e tutti gli articoli che sono in QUESTA pagina ... alla fine il tutto dovrebbe essere più chiaro :slight_smile:

Inanzi tutto grazi molte a fabpolli per il suo aiuto... faccio progressi e grazie a te ora ne so un pizzico di più di programmazione.. volevo aggiornarvi con il mio ultimo codice:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

int switchACW = 2; //define anticlockwise temporary switch
int switchCW = 3; //define clockwise temporary switch
int PUL = 7; //define Pulse pin
int DIR = 6; //define Direction pin
int ENA = 5; //define Enable Pin

int valACW = 0;
int valCW = 0;
int StepCountACW = 0;
int StepCountCW = 0;

unsigned long previousMillis = 0; //will store last time LCD was updated
unsigned long interval = 50;  //interval at which to show value on LCD (milliseconds)

void setup() {


  pinMode (switchACW, INPUT);
  pinMode (switchCW, INPUT);
  pinMode (PUL, OUTPUT);
  pinMode (DIR, OUTPUT);
  pinMode (ENA, OUTPUT);
  pinMode (PUL, OUTPUT);
  pinMode (DIR, OUTPUT);
  pinMode (ENA, OUTPUT);

  lcd.init();

  lcd.backlight();
  lcd.print("Conteggio");
  lcd.setCursor(0, 1);
  lcd.print("step");
  delay(2000);
  lcd.clear();


}

void loop() {
  valCW = digitalRead(switchCW);

  valACW = digitalRead(switchACW);

  unsigned long currentMillis = millis();
 
    if (valCW == LOW)  {        //when clockwise temporary switch is pressed
 
    digitalWrite(DIR, LOW);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, HIGH);
    delayMicroseconds(200);
    StepCountCW++;
  }
  else
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, LOW);
    delayMicroseconds(200);
  }
  {
    if (valACW == LOW)   {      //when anticlockwise temporary switch is pressed
 
    digitalWrite(DIR, HIGH);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, HIGH);
    delayMicroseconds(200);
    StepCountACW++;
  }
  else
  {
    digitalWrite(DIR, HIGH);
    digitalWrite(ENA, HIGH);
    digitalWrite(PUL, LOW);
    delayMicroseconds(200);
  }
  }

 if (currentMillis - previousMillis > interval)  {
    
    previousMillis = currentMillis; //save the last time LCD was updated
    lcd.clear();
    lcd.print("Step:");
    lcd.setCursor(0, 1);
    lcd.print(StepCountACW - StepCountCW);
  }
}

Adesso il codice mi permette di sommare gli step antiorari (positivi) e orari (negativi) e di scriverlo a schermo sfruttando un lag in millisecondi.
C'è ancora un problema... continua a non essere fluido il movimento del motore (meglio di quando ho implementatoo un delay che bloccava la procedura ma non troppo diverso) e c'è ancora un po' di flickering sulla scritta del LCD. Altra cosa che mi preoccupa è che se aumentao il valore della variabile "interval" la fluidità cala proporzionalmente (un po' come se avessi fatto delay e non millis).. sicuramente ho scritto qualcosa di sbagliato..

Ho fatto un piccolo test: se aumento il valore di "interval" ad esempio a 500 millisecondi l'lcd non flickera più se non ogni mezzo secondo e il motore è fluido fino a quando non si stampa sull'LCD il valore dello step.. immagino sia ancora un problema che Arduino non riesca a gestire la movimentazione del motore e scrivere allo stesso tempo su lcd il valore nonostante il lag

Allora è normale che se aumenti l'intervallo non vedi sfarfallare l'lcd in quanto lo aggiorni meno spesso, ti posso suggerire di apportare le seguenti modifiche:
Non memorizzare il valore di millis in una variabile non ti è utile fai una cosa del tipo

if (millis()- previousMillis > interval)  {
  previousMillis = millis(); //save the last time LCD was updated

tanto anche se ti dovessi salvare un valore differente di un millisecondo non ti cambia nulla.
La modifica proposta non è che migliora chissaché ma intanto è un ottimizzazione dell'uso della memoria, quello che potrebbe fare la differenza (visiva sopratutto) è quella di evitare di cancellare tutto lo schermo e riscrivere sempre tutto io proverei a eliminare la la clear dell'lcd e sposterei

lcd.print("Step:");

nel setup subito dopo l'ultima clear che fai nel setup.
Lasciando quindi nell'if gestito con millis() solo la setCursor e la print del valore.
Questa soluzione ha un problema, ovvero quando passi da un valore a due cifre ad un valore ad una sola cifra (Es. 10 -> 9) vedresti stampato 90, ma anche a questo vi è rimedio, più d'uno in realtà in base a come ti piace implementarlo. Nel frattempo prova ad apportare le modifiche suggerite e vedi se (come penso) sfarfallamento e reattività migliorano, se poi sei soddisfatto del risultato prova a trovare una strada per evitare il problema che ti ho esposto in precedenza.
Altra cosa che può migliorare la reattività (forse) e avere un codice più ottimizzato (sicuro) è eliminare i delayMicroseconds nelle parti che gestiscono l'arresto del motore quando rilasci i pulsanti, non ti servono a nulla, nella parte dei pulsanti premuti i delaymicroseconds li hai messi per un motivo specifico oppure perché hai usato un codice trovato in rete?

Ah altra cosa hai una graffa aperta ed una chiusa di troppo nel tuo codice, eliminale sono superflue :wink:

certo quando ho letto le modifiche ho pensato "ci potevo arrivare prima...:(" ma del resto sto imparando.. allora ho apportato le modifiche ma il risultato non è migliorato moltissimo.. Mi hai aiutato a risolvere il problema del flickering ma lo stepper continua ancora ad impuntarsi e non ne vuole sapere di comportarsi in maniera fluida anche se ho giocato con i delayMicroseconds e i microstep sul driver, il risultato è sempre una brutta vibrazione dovuta ad uo "start and stop" balordo..
Il codice lo avevo visto inizialmente sul sito della dfrobots ma era solo per la movimentazione, diciamo un test per vedere se lo stepper funzionava e vederlo girare.. il resto l'ho tìscritto io buttando un occhio su altri sketch soprattutto per le ultime modifiche..
Forse si può ottenere qualche altro risultato usando una libreria per lo stepper?

Sugli stepper non ho esperienza, diciamo che presi una breakout board e ne feci girare uno preso da una stampante per prova anni fa e poi basta quindi non saprei consigliarti o dire se con una libreria risolveresti.
La domanda che mi sorge spontanea è: Visto che tu dici che senza aggiornare l'lcd il motore gira fluido, ti andrebbe bene aggiornare l'lcd solo in due momenti?
Mi spiego meglio premi il pulsante e aggiorni l'LCD non mettendo gli step eseguiti ma indicando "il motore gira" (una sola volta pre pressione molto importante questo dettaglio!) e poi non lo aggiorni più finché non hai mollato il pulsante, allora, e solo allora, dopo aver fermato il motore aggiorni l'lcd riportando il numero di passi effettuati. Può essere una valida alternativa?

magari questa:

fabpolli:
Sugli stepper non ho esperienza, diciamo che presi una breakout board e ne feci girare uno preso da una stampante per prova anni fa e poi basta quindi non saprei consigliarti o dire se con una libreria risolveresti.
La domanda che mi sorge spontanea è: Visto che tu dici che senza aggiornare l'lcd il motore gira fluido, ti andrebbe bene aggiornare l'lcd solo in due momenti?
Mi spiego meglio premi il pulsante e aggiorni l'LCD non mettendo gli step eseguiti ma indicando "il motore gira" (una sola volta pre pressione molto importante questo dettaglio!) e poi non lo aggiorni più finché non hai mollato il pulsante, allora, e solo allora, dopo aver fermato il motore aggiorni l'lcd riportando il numero di passi effettuati. Può essere una valida alternativa?

Così per imparare senz'altro ma avevo un'idea in mente dopo aver preso confidenza ossia di leggere a schermo gli step fatti (o in alternativa i gradi) e quindi di potersi fermare una volta letto un certo valore a schermo.. se stampassi il numero solo una volta lasciato il pulsante allora non potrei più sapere quando mi voglio fermare (l'idea è sulla falsa riga di un controllo manuale per la movimentazione).. quindi vorrei insistere su questa linea..
Quello che mi lascia perplesso è che il flickering è sparito (segno che adesso grazie a te il codice è più efficiente) ma qualsiasi cosa faccia per dare respiro ad arduino sembra lasciare il problema inalterato, ossia se aumento il delay per ridurre la velocità oppure diminuisca i microstep comunque ha questo andamento non molto consono.. Per capire se era un problema di hardware ho messo nel setup una piccola routine con un ciclo while che termina una volta premuto il pulsante per il verso antiorario e lo stepper si comporta egregiamente...

Ok, lo supponevo. Considera che una MCU della classe Arduino non è multi-task quindi per forza di cose mentre invia i caratteri al display non può fare altro e questo ti porta ad aver necessità di pensare in modo differente a quanto non ci fa ad esempio su un PC. Comunque ti butto li un'altra idea, magari anche questa non è adeguata all'obiettivo che ti prefiggi ma non si sa mai.
Se i pulsanti "comandassero" il display e poi il programma facesse girare i motore?
piegazione:
All'avvio il programma mostra sul display Step: 0
Premi il pulsante per girare a destra e il contatore sul display viene incrementato ogni N unità di tempo (con un delay o meglio ancora con uso di millis() che non si sa mai in futuro se il delay può darti fastidio se ti cambia la logica del programma), quando il display ti mostra gli step desiderati rilasci il pulsante, a questo punto il programma fa girare il motore degli N step necessari senza la necessità di aggiornare il display di continuo a vantaggio della fluidità del moto del motore.
Se ti piace come idea ti suggerisco di iniziare ad implementarla come descritto, poi si può migliorare il tutto gestendo la pressione del pulsante con il motore in movimento. Se non va bene come logica prova la libreria ma non so se otterrai vantaggi significativi o meno, tentar non nuoce