Tinkercad controlla un motore con encoder è dedicato all’uso di un motore dc con encoder.
alcuni giorni fa ho trovato nella libraria dei componenti messi a disposizione da tinkercad un motore dotato di encoder:
e controllandolo con il classico L293D :
presente anch’esso tra i componenti presenti in thinkercad, puoi realizzare un progetto di controllo del motore.
Puoi trovare il progetto condiviso qui.
Il video Tinkercad controlla un motore con encoder
Come in ogni tutorial della serie dedicata a tinkercad ho realizzato un video in cui puoi vedere:
sia come costruire il circuito in modo semplice sia la realizzazione del codice di controllo che trovi nei paragrafi successivi.
Il circuito
Per realizzare il circuito con cui tinkercad controlla un motore con encoder puoi seguire lo schema visibile nel video e che ti riporto come immagine:
in questo esempio usi solo uno dei due canali del driver L293D in quanto è solo uno il motore da controllare.
I pin arduino coinvolti nel controllo del motore sono 5 e 6, entrambi PWM.
L’encoder dovrà essere connesso ai pin 2 e 3, che di default per Arduino Uno sono di tipo interrupts, ossia possono assolvere alla lettura dei segnali provenienti da un encoder, o altro segnale digitale, in modo sel tutto indipendente dal loop().
Puoi approfondire gli interrupt in questo articolo: Rotary Encoder: come utilizzare un encoder con Arduino.
Il primo sketch di controllo del motore
il primo sketch del tinkercad controlla un motore con encoder si occupa del solo controllo del motore:
#define motorA 5 #define motorB 6 void setup() { Serial.begin (9600); pinMode(motorA,OUTPUT); pinMode(motorB,OUTPUT); } void loop() { analogWrite(motorA,127); digitalWrite(motorB,LOW); delay(100); }
le prime due linee definiscono i pin con cui potrai controllare la rotazione del motore dc mediante L293D;
la linea 05: imposta la comunicazione seriale;
le linee 06-07: imposta come OUTPUT i pin 5 e 6;
linea 11: imposta a 127 l’output sul pin 5 in modo che la velocità di rotazione sia il 50% della velocità massima del motore. Tale velocità, nella simulazione, corrisponderà a 3rpm;
linea 12: imposta a 0 ( LOW ) il valore di output sul pin 6 per impostare la rotazione in senso orario.
Dopo aver verificato che il motore gira in modo regolare con queste impostazioni passa alla lettura dell’encoder.
Il secondo sketch: lettura dell’encoder
La lettura dell’encoder in questo esercizio è la parte più complessa, ti consigli o di leggere il mio precedente articolo dedicato all’encoder rotativo prima di procedere oltre.
Ora che sai come funziona un encoder puoi passare al codice:
#define motorA 5 #define motorB 6 int encoderPin1 = 2; int encoderPin2 = 3; volatile int lastEncoded = 0; volatile long encoderValue = 0; volatile long correctEncoderValue =0; long lastencoderValue = 0; int lastMSB = 0; int lastLSB = 0; void setup() { Serial.begin (9600); pinMode(encoderPin1, INPUT); pinMode(encoderPin2, INPUT); digitalWrite(encoderPin1, HIGH); //turn pullup resistor on digitalWrite(encoderPin2, HIGH); //turn pullup resistor on attachInterrupt(0, updateEncoder, CHANGE); attachInterrupt(1, updateEncoder, CHANGE); pinMode(motorA,OUTPUT); pinMode(motorB,OUTPUT); } void loop() { correctEncoderValue = encoderValue/4; Serial.println(correctEncoderValue); analogWrite(motorA,127); digitalWrite(motorB,LOW); delay(100); } void updateEncoder(){ int MSB = digitalRead(encoderPin1); //MSB = most significant bit int LSB = digitalRead(encoderPin2); //LSB = least significant bit int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++; if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --; lastEncoded = encoded; //store this value for next time }
in cui le linee 03 e 04 servono a definire i due pina a cui è connesso l’encoder;
linee 05-12: sono le variabili che ti serviranno per la lettura dell’encoder come spiegato nell’articolo che hai letto;
le linee 16-21: servono a impostare la modalità dei pin relativi all’encoder a INPUT, a impostarli a 1 ( HIGH ) attivando al contempo la resistenza interna di pullup corrispondente ai pin 2 e 3 ed, infine, a definire quale funzione richiamare ad ogni CHANGE del valore rilevato su uno di quei pin.
Nella funzione loop le modifiche saranno poche:
linea 28: ricalcola il valore di currentEncoderValue come il valore rilevato sull’encoder diviso 4, in quanto, come hai già letto, la lettura dell’encoder con il codice suggerito nella funzione updateEncoder() incrementa il valore reale di 4 volte;
linea 30: scrivi sul monitor seriale il valore corrente dell’encoder;
In ultimo ho copiato ed incollato la funzione updateEncoder() dal primo articolo che ho scritto sull’encoder, servirà per calcolare il valore rilevato dalla rotazione.
Sketch finale: controlla il motore con l’encoder
Lo sketch finale del tinkercad controlla un motore con encoder riguarda la possibilità di bloccare la rotazione del motore al momento in cui l’encoder rileva un valore impostato.
In questo esempio ho usato un valore arbitrale di 3000 impulsi.
Lo sketch resta invariato nella maggior parte delle linee a parte la funzione loop che riceve una piccola modifica:
#define motorA 5 #define motorB 6 int encoderPin1 = 2; int encoderPin2 = 3; volatile int lastEncoded = 0; volatile long encoderValue = 0; volatile long correctEncoderValue =0; long lastencoderValue = 0; int lastMSB = 0; int lastLSB = 0; void setup() { Serial.begin (9600); pinMode(encoderPin1, INPUT); pinMode(encoderPin2, INPUT); digitalWrite(encoderPin1, HIGH); //turn pullup resistor on digitalWrite(encoderPin2, HIGH); //turn pullup resistor on attachInterrupt(0, updateEncoder, CHANGE); attachInterrupt(1, updateEncoder, CHANGE); pinMode(motorA,OUTPUT); pinMode(motorB,OUTPUT); } void loop() { correctEncoderValue = encoderValue/4; Serial.println(correctEncoderValue); if ( 0<=correctEncoderValue && correctEncoderValue < 3000) { analogWrite(motorA,127); digitalWrite(motorB,LOW); } else { analogWrite(motorA,0); digitalWrite(motorB,LOW); } delay(100); } void updateEncoder(){ int MSB = digitalRead(encoderPin1); //MSB = most significant bit int LSB = digitalRead(encoderPin2); //LSB = least significant bit int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++; if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --; lastEncoded = encoded; //store this value for next time }
in modo particolare dovrai aggiungere la condizione di if riportata alla linea 33: in cui valuterai se il numero di impulsi è compreso tra 0 e 3000, valore di soglia definito.
Quando il valore letto sull’encoder resta all’interno di questo range farai girare il motore come in precedenza.
Al superamento del valore 3000 entrerai nella condizione di else che provvederà a fermare il motore portando a 0 il valore sul pin 5;
Noterai nel video che il valore letto è 3018 prima che si fermi il motore e ti lascio sperimentare con il simulatore per comprendere cosa causi questo valore di lettura superiore e come correggerlo nel tuo personale progetto: tinkercad controlla un motore con encoder.