Stepper con Encoder Rotativo che non ritorna a Zero

Salve :) Se non si capisce bene dal titolo provo spiegarmi :) Ho preso come mia primissima esperienza con Arduino quei Kit che si trovano su Amazon, ed all'interno si trovava un motorino stepper già con una riduzione meccanica ed il suo driver, ed uno degli ultimi esempi era di controllare il motore grazie ad un Encoder Rotativo. Fino a qui tutto perfetto l'esempio funziona benissimo, ma per motivi pratici volevo sostituire il motorino del kit con un Name17 ed il DRV8825, due componenti che ho a casa e che ho già usato. Sono riuscito ad diciamo adattare il codice, e funziona si muove nelle due direzioni correttamente, ma al momento di schiacciare l'encoder per tornare alla posizione di partenza non fa assolutamente nulla :( Mi fate la cortesia di darmi un indizio su dove sbaglio.

Grazie Mille :)

#include "DRV8825.h"
#define MICROSTEPS 17
#define MOTOR_STEPS 200
#define STEP    6
#define DIR     5
#define MODE0  11
#define MODE1  10
#define MODE2   9
#define ENABLE 12
DRV8825 stepper(MOTOR_STEPS, DIR, STEP, ENABLE, MODE0, MODE1, MODE2);


volatile boolean TurnDetected;  // need volatile for Interrupts
volatile boolean rotationdirection;  // CW or CCW rotation

const int PinCLK = 2; // Generating interrupts using CLK signal
const int PinDT = 3;  // Reading DT signal
const int PinSW = 4;  // Reading Push Button switch

int RotaryPosition = 0;  // To store Stepper Motor Position

int PrevPosition;     // Previous Rotary position Value to check accuracy
int StepsToTake;      // How much to move Stepper


// Interrupt routine runs if CLK goes from HIGH to LOW
void isr ()  {
  delay(1);  // delay for Debouncing
  if (digitalRead(PinCLK))
    rotationdirection = digitalRead(PinDT);
  else
    rotationdirection = !digitalRead(PinDT);
  TurnDetected = true;
}


void setup() {

  pinMode( ENABLE , OUTPUT );
  pinMode( DIR    , OUTPUT );
  pinMode( STEP   , OUTPUT );
  pinMode( MODE0  , OUTPUT );
  pinMode( MODE1  , OUTPUT );
  pinMode( MODE2  , OUTPUT );
  pinMode(PinCLK, INPUT);
  pinMode(PinDT, INPUT);
  pinMode(PinSW, INPUT);
  digitalWrite(PinSW, HIGH); // Pull-Up resistor for switch
  attachInterrupt (0, isr, FALLING); // interrupt 0 always connected to pin 2 on Arduino UNO

}

void loop() {

  digitalWrite( STEP  , LOW  );
  digitalWrite( MODE0 , HIGH );
  digitalWrite( MODE1 , HIGH );
  digitalWrite( MODE2 , LOW  );

  if (!(digitalRead(PinSW))) {   // check if button is pressed
    if (RotaryPosition == 0) {  // check if button was already pressed
    } else {
      digitalWrite( STEP, HIGH );
      delay( 1);
      digitalWrite( STEP, LOW  );
      delay( 0);
      RotaryPosition = 0; // Reset position to ZERO
    }
  }

  // Runs if rotation was detected
  if (TurnDetected)  {
    PrevPosition = RotaryPosition; // Save previous position in variable
    if (rotationdirection) {
      RotaryPosition = RotaryPosition - 1;
    } // decrase Position by 1
    else {
      RotaryPosition = RotaryPosition + 1;
    } // increase Position by 1

    TurnDetected = false;  // do NOT repeat IF loop until new rotation detected

    // Which direction to move Stepper motor
    if ((PrevPosition + 1) == RotaryPosition) { // Move motor CW
      digitalWrite( DIR , HIGH );
      digitalWrite( STEP, HIGH );
      delay( 1);
      digitalWrite( STEP, LOW  );
      delay( 0);
    }

    if ((RotaryPosition + 1) == PrevPosition) { // Move motor CCW
      digitalWrite( DIR , LOW );
      digitalWrite( STEP, HIGH );
      delay( 1);
      digitalWrite( STEP, LOW  );
      delay( 0);
    }

    digitalWrite(12, LOW);
    digitalWrite(6, LOW);
    digitalWrite(5, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
  }

}

ciao...nel tuo sketch quando premi il pulsante di reset PinSW azzeri solo la variabile RotaryPosition...e basta...non gli chiedi di tornare a "casa". gli unici momenti in cui fai muovere il motore è quando RotaryPosition è maggiore o minore di una unità rispetto alla variabile PrevPosition.

quindi nella if() dove resetti la variabile dovresti dirgli di tornare alla posizione 0...come non lo so...non conosco la libreria, forse sbaglio, ma non mi sembra tu la stia utilizzando al meglio...cosa serve creare ed inizializzare l'oggetto stepper se dopo attivi e disattivi "a mano" i vari PIN!?...ripeto non conosco la libreria ma così sicuramente non si riesce a tenere conteggio delle attivazioni...almenochè, dato che ogni attivazione dura 1 ms, prima di resettare la variabile RotaryPosition, usi il suo valore (ABS) come delay() andando CW o CCW a seconda se positivo o negativo...che comunque resta un posizionamento non preciso.

Grazie :) Anche se ho capito pochissimo hehehe ma la verità e che non conosco assolutamente i comandi completi della libreria DRV8825 e non riesco nemmeno a trovarli :(

Un indizio su cosa scrivere su Google, per trovare i comandi di una libreria sarebbe oro colato :)

ciao...sicuramente questa libreria l'hai salvata nella cartella libraries; se non presente un "manuale" della libreria, per conoscere le "parole chiave" che ti mette a disposizione, devi guardarti il file KEYWORDS...e dopo cercare le stesse nel file .cpp dove di solito un po' di spiegazione viene data. diversamente devi guardarti gli esempi che la libreria stessa mette a disposizione.

Grazie Mille dopo ci provo ;)

Sono riuscito a trovare solo pochi comandi e non sembra essercene di specifici per la posizione. :( Probabilmente questo driver non lo permette :(

StepperDriver KEYWORD1

BasicStepperDriver KEYWORD1
DRV8880 KEYWORD1
DRV8834 KEYWORD1
DRV8824 KEYWORD1
DRV8825 KEYWORD1
A4988 KEYWORD1
MultiDriver KEYWORD1
SyncDriver KEYWORD1

setMicrostep KEYWORD2
setSpeedProfile KEYWORD2
move KEYWORD2
rotate KEYWORD2
setRPM KEYWORD2
getRPM KEYWORD2
setCurrent KEYWORD2
enable KEYWORD2
disable KEYWORD2
startMove KEYWORD2
startRotate KEYWORD2
nextAction KEYWORD2
stop KEYWORD2
startBrake KEYWORD2

CONSTANT_SPEED LITERAL1
LINEAR_SPEED LITERAL1

ciao...mi sa che non ri riesce a ricavare quanto ha girato il motore per tornare al punti di partenza...come detto o valuti se RotaryPosition è positiva o negativa, per determinare la direzione da impostare, e il suo valore lo usi come delay() ...e poi la azzeri...oppure installi un encoder al motore/camera per verificare la sua rotazione...e allora conti impulsi...oppure metti un sensore di riferimento per lo "0" ed azioni il motore fino ad arrivare a tale punto.

Grazie di nuovo per il tuo tempo :wink:
Si ho capito il sistema ed dovrei accoppiare un secondo encoder al motore :wink:
Ma mi sembra assurdo che riesca a farlo con il Kit ed il motore da €1,20 e non con il DVR8825 :frowning:
Con questo motorino il suo driver e questo codice funziona tutto alla perfezione senza altri componenti, cosa mi dimentico ?

#include "Stepper.h"
#define STEPS  32   // Number of steps for one revolution of Internal shaft
                    // 2048 steps for one revolution of External shaft

volatile boolean TurnDetected;  // need volatile for Interrupts
volatile boolean rotationdirection;  // CW or CCW rotation

const int PinCLK=2;   // Generating interrupts using CLK signal
const int PinDT=3;    // Reading DT signal
const int PinSW=4;    // Reading Push Button switch

int RotaryPosition=0;    // To store Stepper Motor Position

int PrevPosition;     // Previous Rotary position Value to check accuracy
int StepsToTake;      // How much to move Stepper

// Setup of proper sequencing for Motor Driver Pins
// In1, In2, In3, In4 in the sequence 1-3-2-4
Stepper small_stepper(STEPS, 8, 10, 9, 11);

// Interrupt routine runs if CLK goes from HIGH to LOW
void isr ()  {
  delay(4);  // delay for Debouncing
  if (digitalRead(PinCLK))
    rotationdirection= digitalRead(PinDT);
  else
    rotationdirection= !digitalRead(PinDT);
  TurnDetected = true;
}

void setup ()  {
  
pinMode(PinCLK,INPUT);
pinMode(PinDT,INPUT);  
pinMode(PinSW,INPUT);
digitalWrite(PinSW, HIGH); // Pull-Up resistor for switch
attachInterrupt (0,isr,FALLING); // interrupt 0 always connected to pin 2 on Arduino UNO
}

void loop ()  {
  small_stepper.setSpeed(700); //Max seems to be 700
  if (!(digitalRead(PinSW))) {   // check if button is pressed
    if (RotaryPosition == 0) {  // check if button was already pressed
    } else {
        small_stepper.step(-(RotaryPosition*50));
        RotaryPosition=0; // Reset position to ZERO
      }
    }

  // Runs if rotation was detected
  if (TurnDetected)  {
    PrevPosition = RotaryPosition; // Save previous position in variable
    if (rotationdirection) {
      RotaryPosition=RotaryPosition-1;} // decrase Position by 1
    else {
      RotaryPosition=RotaryPosition+1;} // increase Position by 1

    TurnDetected = false;  // do NOT repeat IF loop until new rotation detected

    // Which direction to move Stepper motor
    if ((PrevPosition + 1) == RotaryPosition) { // Move motor CW
      StepsToTake=50; 
      small_stepper.step(StepsToTake);
    }

    if ((RotaryPosition + 1) == PrevPosition) { // Move motor CCW
      StepsToTake=-50;
      small_stepper.step(StepsToTake);
    }
  }
     digitalWrite(8, LOW);
     digitalWrite(9, LOW);
     digitalWrite(10, LOW);
     digitalWrite(11, LOW);     
}

ciao...bhe i due codici sono molto differenti tra loro...nel senso che il codice dell'esempio usa la libreria il tuo, come detto, no. tra le altre cose c'è questo che diverge dal tuo codice:

  if (!(digitalRead(PinSW))) {   // check if button is pressed
    if (RotaryPosition == 0) {  // check if button was already pressed
    } else {
        small_stepper.step(-(RotaryPosition*50));
        RotaryPosition=0; // Reset position to ZERO
      }
    }

attenzione però che loro hanno anche impostato il loro oggetto Stepper:

Stepper small_stepper(STEPS, 8, 10, 9, 11);

poi lo hanno impostato come:

small_stepper.setSpeed(700); //Max seems to be 700

ed utilizzano il metodo specifico per muovere il motore:

small_stepper.step(-(RotaryPosition * 50));

e questo fa quello che ti suggerivo io...però attenzione che loro usano un modo diverso per muoversi "normalmente"...e cioè:

    // Which direction to move Stepper motor
    if ((PrevPosition + 1) == RotaryPosition) { // Move motor CW
      StepsToTake = 50;
      small_stepper.step(StepsToTake);
    }

    if ((RotaryPosition + 1) == PrevPosition) { // Move motor CCW
      StepsToTake = -50;
      small_stepper.step(StepsToTake);
    }

domanda...se stai utilizzando gli stessi componenti...perchè non usi tale e quale anche lo sketch?

Grazie ;-)

Ho capito già parecchio, ma il problema deriva proprio perché non volevo utilizzare una libreria generica "[u]penso[/u]" non adatta mentre di usare quella del driver in mio possesso il DRV8825 tutto li :) se vedi nel mio primo post #include "DRV8825.h" sarebbe la libreria del driver :(

qui mi sorge il dilemma se devo cambiare il DRV8825 per poter usare la libreria standard #include "Stepper.h" :confused:

Grazie Mille :)

ciao...non so che libreria usi ma facendo una ricerca ho trovato QUESTA che se guardi negli esempi se devi anche includere la DRV8825.h ti "spiega" come...e quindi sarebbe perfetta.

Grazie Mille ;-) Già spulciata per bene ma anche qui l'esempio non mi permette di stabilire un punto di partenza. Da quello che ho capito per utilizzare il sistema come da esempio del Kit dovrei utilizzare la libreria STEPPER.H ma sembra funzionare con quattro connessioni :( ed il DRV8825 ne prevede solo due il STEP e il DIR, o sono io che non lo capisco... Proverò ancora prima di cambiare driver ;-)

ciao...non l'ho spulciata del tutto...ma se dai un occhio a DRV8825.h e .cpp trovi che i possibili costruttori sono:

    DRV8825(short steps, short dir_pin, short step_pin);
    DRV8825(short steps, short dir_pin, short step_pin, short enable_pin);
    DRV8825(short steps, short dir_pin, short step_pin, short mode0_pin, short mode1_pin, short mode2_pin);
DRV8825(short steps, short dir_pin, short step_pin, short enable_pin, short mode0_pin, short mode1_pin, short mode2_pin);

quindi...sembra che il minimo indispensabile necessiti di 3 parametri. il restante dei pin sono utilizzati per decidere la "velocità" ...e/o altro. forse se dai un occhio QUA capisci meglio.

Cespe: ehm ... credo che partiate da una premessa errata ... ;)

Un'encoder calettato ad un motore, a meno che non sia a tre canali di cui il terzo e' il segnale "home", oppure sia di tipo "assoluto" e non "incrementale", NON consente di stabilire in che punto il motore si trova, ne di settare un punto "di partenza", non senza un finecorsa esterno ...

Non mi sembra che tu indichi quale motore e quale encoder stai usando, ma suppongo che sia un incrementale standard a due canali, dato che gli altri due tipi non sono molto diffusi ... quindi se hai la necessita' di avere un punto di partenza certo e sempre uguale, dovrai per forza aggiungere un finecorsa al tutto, in modo da poter "azzerare" la posizione allo start, e sapere poi da dove parti ... dopo, contando gli impulsi che dai al terminale STEP, potrai calcolarti in che punto deve arrivare, ma solo dopo ... ;)

ed uno degli ultimi esempi era di controllare il motore grazie ad un Encoder Rotativo.

A me sembra di capire che l' encoder é inteso quello da interfaccia utente e non quello che legge i giri/posizione del motore. Ciao Uwe

infatti Cespe aveva allegato una foto del sistema cablato e si vede che l’encoder è usato per comandare a mo di potenziometro il motore…infatti lo sketch di prova conta gli impulsi ricevuti dall’encoder, positivi e negativi, per far ruotare il motore in CW o CCW.
come detto da Etemenanki, ma anche da me nei primi post :smiley: , ci sono due possibili vie…o si installa un sensore di “home” oppure si utilizza la variabile RotaryPosition che contiene il conteggio dell’encoder manuale per ritornare, più o meno, all’inizio.

Si scusate… se posso aver fatto confusione, ma l’esempio del Kit che funziona “diciamo senza molte pretese di precisione” e un encoder rotativo tipo potenziometro a venti passi, come quello che rimetto nella foto qui.
E da quello che ho capito fino adesso :slight_smile: e che non posso usare la libreria STEPPER.h con il mio DRV8825 che ha una libreria tutta sua, dove il RotaryPosition non è contemplata :frowning:
Pensare che il mio progetto voleva tenere conto di più posizioni per poi richiamare con un pulsante :frowning: