motore dc controllo con encoder

Salve a tutti, avrei bisogno di un software per comandare il posizionamento di un motore dc motoridotto con un encoder cioè in base a come muovo l'encoder il motore si comporta di conseguenza, in rete non ho trovato nulla sui motori dc ma sono tutti stepper.
Grazie a chi mi aiuterà

>RoccoStragapede: ... mi raccomando, quando si fanno queste richieste, tenere sempre a mente il punto 16.1 del REGOLAMENTO ... ::slight_smile:

Guglielmo

Prova a studiare qua in particolare come varia la variabile "Valore: ", e qua come applicarlo a una serie di led. Poi prova a cambiare i led col motore, ricordando che le correnti in gioco sono MOLTO diverse.

Ciao,
P.

#define PWMPin 11

int IN1 = 9;
int IN2 = 10;

int encoderPin1 = 2;
int encoderPin2 = 3;
int cw = 4;
int ccw = 5;
int ledPin5 = 6;
int ledPin6 = 7;
int buttonPin3 = 8;

int ledState5 = LOW;
int ledState6 = HIGH;
int buttonState3;
int lastButtonState3 = HIGH;

long lastDebounceTime3 = 0;
long debounceDelay3 = 50;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

void setup() {

  pinMode(PWMPin, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);

  pinMode(buttonPin3, INPUT_PULLUP);
  pinMode(ledPin5, OUTPUT);
  pinMode(ledPin6, OUTPUT);

  Serial.begin (9600);

  pinMode(encoderPin1, INPUT_PULLUP);
  pinMode(encoderPin2, INPUT_PULLUP);
  pinMode (cw, OUTPUT);
  pinMode (ccw, OUTPUT);

  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);

  digitalWrite(cw, LOW);
  digitalWrite(ccw, LOW);

  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, HIGH);
}

void loop() {

  int reading3 = digitalRead(buttonPin3);
  if (reading3 != lastButtonState3) {
    lastDebounceTime3 = millis();
  }
  if ((millis() - lastDebounceTime3) > debounceDelay3) {
    if (reading3 != buttonState3) {
      buttonState3 = reading3;
      if (buttonState3 == HIGH) {
        ledState5 = !ledState5;
        ledState6 = !ledState6;
        if (ledState5 == HIGH) {
          analogWrite(PWMPin, 64);
        }
        if (ledState6 == HIGH) {
          analogWrite(PWMPin, 191);
        }
      }
    }
  }
  digitalWrite(ledPin5, ledState5);
  digitalWrite(ledPin6, ledState6);
  lastButtonState3 = reading3;

  Serial.println(encoderValue);
}

void updateEncoder() {

  int MSB = digitalRead(encoderPin1); 
  delay(100);
  int LSB = digitalRead(encoderPin2); 
  delay(100);
  int encoded = (MSB << 1) | LSB; 
  int sum  = (lastEncoded << 2) | encoded; 

  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  delay(1000);
  if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;
  delay(1000);
  if (sum == 0b0100 || sum == 0b0010) {
    digitalWrite(cw, HIGH);
    digitalWrite(IN1, HIGH);
    delay(500);
    digitalWrite(IN2, LOW);
    delay(500);
  }
  else {
    digitalWrite(cw, LOW);
    digitalWrite(IN1, HIGH);
    delay(500);
    digitalWrite(IN2, HIGH);
    delay(500);
  }

  if (sum == 0b0001 || sum == 0b1000) {
    digitalWrite(ccw, HIGH);
    digitalWrite(IN1, LOW);
    delay(500);
    digitalWrite(IN2, HIGH);
    delay(500);
  }
  else {
    digitalWrite(ccw, LOW);
    digitalWrite(IN1, HIGH);
    delay(500);
    digitalWrite(IN2, HIGH);
    delay(500);
  }

  lastEncoded = encoded; 
}

sono riuscito a buttare giu un listato però accusa qualche malfunzionamento e cioè:

il cambio del duty alla pressione dello SW dell’encoder va bene ma se ruoto l’encoder, ogni tanto se giro orario mi va per un impulso in antiorario e poi si riprende, vale anche nell’altro senso

poi è giusto come sto comandando IN1 e IN2 che poi andranno a un L298N?

poi come faccio a dire che una volta che faccio andale a livello basso per esempio IN1 me lo deve mantenere basso per x secondi e anche con IN2?

poi per qualche motivo all’avvio mi si accende per una frazione di secondo ledPin6 e subito dopo si accende ledPin5 come deve essere, come mai?

poi vabbè dovro inserire due finecorsa per entrambi i sensi ma questo lo devo ancora fare

Grazie a chi mi dedicherà del tempo e le sue capacità

in base a come muovo l'encoder il motore si comporta di conseguenza

Cioé?

Nel tuo listato non c'è nessun commento. E' molto più semplice capire un listato fatto da altri se l'autore scrive dei commenti sulla funzione delle variabili e dei commenti su quello che fanno (dovrebbero fare!) i vari punti nevralgici del codice.

La sintassi raccomandata del interrupt è questa:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) (recommended)
Evita confusioni.
Quale arduino usi?

savoriano:
Cioé?

Cioè se ruoto l'encoder, esempio 10 gradi, anche il motore deve ruotare di 10 gradi, ma in sostanza a me serve un posizionamento manuale del motore con l'encoder

ora i gradi non sono necessari perchè sarò io a decidere di quanto voglio farlo ruotare agiendo sull'encoder ne tantomeno mi serve un feedback

spero di essermi spiegato

ho anche implementato una sorta di regolazione fine e grossa in base alla pressione dello SW dell'encoder variando il PWM

la mia idea è questa senza motore passo passo ma con un motore dc e al posto di più velocità averne solo due

10 gradi, anche il motore deve ruotare di 10 gradi,

Un motore dc standard non può fare questo, Se nel tuo motore c'è un solo campo magnetico il minimo spostamento che può fare è mezzo giro che in più sarà difficilmente ( per non dire impossibile) gestibile.
Se provi a girare il motore manualmente, capirai il problema.

scusa ho omesso il fatto che il motore è motoridotto quindi per fare 10 gradi magari il motore girerà 3600° cioè 10 giri

motoridotto

L’avevi scritto nel primo messaggio. :confused:
Quindi i motore deve girare per un certo tempo ad ogni scatto del encoder.
Questo vuol dire che se fai due scatti funzionerà per tempo*2 + un tempo che tiene conto del tempo dell’accelerazione - un tempo di decelerazione.
E’ cosi’?

credo di si ovviamente i tempi li devo poter regolare per adattarli alla mia esigenza, diciamo che il risultato finale deve essere come il video che ti ho lincato

i tempi li devo poter regolare per adattarli alla mia esigenza

Forse ci riuscirai ma non sarà cosi' preciso come un motore passa-passo, sopratutto se il motore deve far girare qualche cosa di non costante.

Ora mi spieghi cosa sono le variabili IN1 IN2 cw cww cosa vuol dire quando ledPin5 e ledPin6 si accendono et PWMPin (quando usi #define è norma scrivere tutto in maiuscolo)?

allora le variabili IN1 e IN2 sono gli input del L298N, driver motor, cw e ccw non le considerare servono a me in questa fase per vedere il verso dell'encoder
ledPin5 e ledPin6 sono due led che mi segnalano se il pwm è a 20% del duty oppure al 70%
PWMPin è dove preleverò il segnale pwm al pin 11 per l'ENABLE del L298N
per il #define scriverò tutto minuscolo

Penso che il tu problema venga dalla funzione "UpdateEncore"
Mettiamo il caso che giri l'encoder senso orario

if (sum == 0b0100 || sum == 0b0010) {//Condizione vera
    digitalWrite(cw, HIGH); //Entra in questo if
    digitalWrite(IN1, HIGH);
    delay(500);
    digitalWrite(IN2, LOW); //Fa girare il motore
    delay(500);
  }
  else {// questa parte ovviamente non vine eseguita
    digitalWrite(cw, LOW);
    digitalWrite(IN1, HIGH);
    delay(500);
    digitalWrite(IN2, HIGH);
    delay(500);
  }

  if (sum == 0b0001 || sum == 0b1000) {//Anche questa non viene eseguita
    digitalWrite(ccw, HIGH);      //Perché la condizione è falsa
    digitalWrite(IN1, LOW);
    delay(500);
    digitalWrite(IN2, HIGH);
    delay(500);
  }
  else {  // questa invece si perché è un else
    digitalWrite(ccw, LOW);
    digitalWrite(IN1, HIGH);
    delay(500);
    digitalWrite(IN2, HIGH);// quindi Arresta il motore
    delay(500);
  }

Se giri in senso antiorario il motore si arresta per poi ripartire.
Ci vogliono tutti questi delay?

no gli ho messi perchè notavo malfunzionamenti, infatti hai ragione non servono tantè che non ho notato evidenti miglioramenti

Hai letto tutti gli otto commenti?
Sai come rimediare tenendo la tua logica?
Ce n'è una semplicissima.

per il #define scriverò tutto minuscolo

MAIUSCOLO

ho letto i commemti però non riesco a capire perchè questa non la esegue

if (sum == 0b0001 || sum == 0b1000) {//Anche questa non viene eseguita
    digitalWrite(ccw, HIGH);      //Perché la condizione è falsa
    digitalWrite(IN1, LOW);
    delay(500);
    digitalWrite(IN2, HIGH);
    delay(500);
  }

qua io volevo che invertisse il senso di marcia e sinceramente non so come rimediare anche usando return

Cancella quello che ho detto! Ho dei dubbi :confused:
Sto imparando con te l’uso del encoder perché non l’ho mai usato!!
(dopo un’ora circa…)
Me lo sono studiato e facendo delle prove su un foglio ho un risultato che non combacia con quello che hai scritto sul tuo codice.

int encoded = (MSB << 1) | LSB;
  int sum  = (lastEncoded << 2) | encoded;

  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  delay(1000);
  if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

Con i miei calcoli non trovo 0b1110 ma 0b1010!

Facciamo un passo alla volta cosi’ capisci la logica di quello che sto facendo
Prova questo e mi dirai se dal seriale encoder lavora bene.

void updateEncoder() {

  int MSB = digitalRead(encoderPin1);
  //delay(100);
  int LSB = digitalRead(encoderPin2);
  //delay(100);
  int encoded = (MSB << 1) | LSB;
  int sum  = (lastEncoded << 2) | encoded;
  Serial.print("Sum: ");
  Serial.println(sum);
  if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
  {
    encoderValue ++;
  }
  //delay(1000);
  if (sum == 0b1010 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
  {
    encoderValue --;
  }
}

è solamente la funzione UpdateEncoder il resto non l’ho cambiato.
Questo per vedere se i vari sum sono giusti.

Grazie del tempo che mi stai dedicando!!!

Ho inserito il codice e praticamente funziona uguale, spiego in dettaglio come:

all'accensione di arduino in qualsiasi senso io giro l'encoder prendiamo per esempio orario, dal seriale la partenza è 0 come inizio a ruotare va subito -1 e poi va a 2 fermandosi, poi va bene sempre in crescendo stessa cosa nel vero anti orario 0 va 1 e poi -2

sempre ruotando in senso orario se ruoto con una frequenza bassa da 2 passa a 3 poi a 5 poi a 8 poi a 9 non è regolare ma il senso lo mantiene, stessa cosa nel verso opposto ma se incalzo con le rotazioni incomincia ad impazzire, cioè alza e abbassa di continuo, solo se riduco la frequenza delle rotazione si riprende

Da come descrivi il problema puo essere i sum errati.
Ho modificato il codice del post #17 mettendo 2 serial.print per vedere i sum.
Prova e mi dirai.

Peccato che non ho un encoder perché avrei provato anch'io dato che questa cosa mi interessa molto.