Nell’ultima lezione, abbiamo visto come controllare un LED RGB utilizzando il monitor seriale. Questa volta vedremo come controllare i servi (o servo motori) usando un potenziometro. Con questo, saremo in grado di imparare a puntare un sensore in una direzione per ottenere informazioni di un area specifica. Per fare questo, utilizzeremo alcuni nuovi concetti, misura analogica e funzioni mappa. che spiegheremo in seguito.
Lista dei materiali
- Scheda di controllo ZUM BT-328 o una Arduino compatibile
- Servo
- Potenziometro
Collegamenti elettrici
Collegare i moduli di questo progetto è molto semplice, tutto quello che dobbiamo fare è collegare il servo ai pin con uscita PWM ed il potenziometro ad un ingresso analogico. Puoi vedere i collegamenti nello schema che segue:
Il codice
Inizieremo con un esempio semplicissimo che diventerà più complesso in seguito.
Muovere il servo nella posizione indicata dal potenziometro
Per prima cosa scriviamo l’intero codice, per poi analizzarlo in dettaglio.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <servo.h> int pinPot = A1; // Il pin analogico collegato al potenziometro Servo miServo; // La variabile per controllare il servo void setup() { miServo.attach(10); } void loop() { int potRead = analogRead(pinPot); // Legge il valore del sensore analogico int servoValue = map(potRead, 0, 1023, 0, 180); // trasforma il valore da 0 a 1023 in da 0 a 180 miServo.write(servoValue); // Imposta il servo con l'angolo corrispondente delay(500); // Wait 500 ms } |
Iniziamo includendo la libreria Servo e dichiarando le variabili dei pins:
1 2 3 4 5 6 |
// Includiamo la libreria Servo #include <servo.h> // Creiamo un oggetto servo Servo miServo; int pinPot = A1; // Pin analogico connesso al potenziometro |
La libreria Servo è specifica per questo tipo di motore. La maggior parte dei servo permette movimenti compresi tra 0 e 180º. Se vuoi approfondire come funziona la libreria Servo, puoi guardare la Arduino reference page.
Funzione setup()
1 2 3 4 |
void setup() { miServo.attach(10); } |
In questa funzione dichiariamo che il servo è collegato al pin 10 digitale.
Funzione loop()
Questa è la funzione dove vengono eseguiti i compiti. Devono essere seguiti i seguenti passaggi.
- Leggiamo il valore del potenziometro. Se è un ingresso analogico, il valore sarà compreso tra 0 e 1023. Usiamo la funzione analogRead().
- Trasformiamo i valori compresi tra 0 e 1023 in valori compresi tra 0 e 180, usando la funzione map(). La funzione map converte una variabile che ha un intervallo di valori in un altro intervallo di valori, cioè una variabile nell’intervallo di valori compreso tra A e B cambia il suo intervallo di valori tra C e D, mantenendo la posizione relativa dell’intervallo di partenza in quello di arrivo. Puoi trovare altre informazioni sulla funzione map nella pagina di riferimento.
- Programmiamo il servo per spostarsi nella posizione ottenuta compresa tra 0 e 180.
- Sospendiamo l’esecuzione del programma per 500 ms. Facciamo questo per impedire al servo di cambiare continuamente posizione, ciò significa che il nostro programma sarà meno reattivo, ma più stabile.
Questo è il codice:
1 2 3 4 5 6 7 8 |
void loop() { int potRead = analogRead(pinPot); // Legge il valore del sensore analogico int servoValue = map(potRead, 0, 1023, 0, 180); // Trasforma il valore compreso tra 0 e 1023 in 0 e 180 miServo.write(servoValue); // Imposta il servo con l'angolo corrispondente delay(500); // Wait 500 ms } |
Muovere il servo nella posizione indicata dal potenziometro, senza movimenti bruschi
Nel prossimo esempio effettueremo lo stesso compito, ma obbligheremo il servo a muoversi con piccoli passi di 1 grado ogni 10 millisecondi. In questo modo evitiamo qualsiasi movimento improvviso causato da un movimento brusco del potenziometro. Dopo le dichiarazioni iniziali:
1 2 3 4 5 6 |
// Includiamo la libreria servo #include <servo.h> // Creiamo un oggetto servo Servo miServo; int pinPot = A1; // Il pin analogico è collegato al potenziometro |
Poi dichiariamo le variabili necessarie per eseguire correttamente il programma:
1 |
int aktValue, nextValue; // Variabile che memorizza i valori del potenziometro |
Ora utilizziamo la funzione setup per avviare il programma:
1 2 3 4 5 6 7 8 |
void setup() { // Avviamo la comunicazione seriale che comunica con la scheda Serial.begin(9600); pinMode(pinPot, INPUT); miServo.attach(10); //Indica a quale pin è collegato il servo Serial.println("Pronto!"); } |
Nella funzione setup avviamo la libreria seriale, indichiamo il potenziometro come un input e diciamo al programma quale pin è collegato al servo. Poi inviamo un messaggio all’utilizzatore dicendo che il programma è pronto. Qui possiamo vedere tutta la funzione loop:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
void loop() { nextValue = analogRead(pinPot); // Leggiamo il valore del potenziometro (0-1023) nextValue = map(nextValue, 0, 1023, 0, 180); // Scaliamo ad un valore accettato dal servo (0-180) // Comunichiamo la posizione attuale del servo in gradi Serial.print("Ángulo = "); Serial.print(nextValue); Serial.println("º"); /* Possiamo distinguere due casi: Nel primo caso, la posizione voluta è maggiore di quella attuale, così aumentiamo il valore Nel secondo caso, la posizione voluta è minore di quella attualeI, così diminuiamo il valore */ if (nextValue > aktValue) { for (int i = aktValue; i >= nextValue; i++) { miServo.write(i); // Usiamo la funzione per impostare il valore del servo delay(10); // e aspettiamo finchè viene eseguito. } } else if (nextValue > aktValue) { for (int i = aktValue; i >= nextValue; i--) { miServo.write(i); delay(10); } } aktValue = miServo.read(); delay(1000); } |
All’interno della funzione loop, per prima cosa acquisiamo il valore del potenziometro, poi usiamo la funzione map per “trasformare” la lettura del potenziometro in un angolo. Infine stampiamo l’informazione dell’angolo sul monitor seriale:
1 2 3 4 5 6 7 |
nextValue = analogRead(pinPot); // Leggiamo il valore del potenziometro (0-1023) nextValue = map(nextValue, 0, 1023, 0, 180); // Scaliamo ad un valore che il servo accetta (0-180) // Stampiamo il valore della posizione del servo in gradi Serial.print("Ángulo = "); Serial.print(nextValue); Serial.println("º"); |
A differenza delle letture digitali, la lettura analogica permette di distinguere valori tra 0 e 5 Volt. La scheda ZUM e Arduino sono dotate di un convertitore analogico-digitale a 10 bit, che significa che l’intervallo di valori è tra 0 e 1023. Puoi trovare ulteriori informazioni su analogRead qui. Ora procediamo nel modificare la posizione del servo, scegliendo tra due scenari:
- Il valore a cui il servo deve muoversi è più alto di quello attuale, così si deve incrementare la posizione:
1 2 3 4 5 6 |
if (nextValue > aktValue) { for (int i = aktValue; i >= nextValue; i++) { miServo.write(i); // Usiamo la funzione per impostare il valore del servo delay(10); // e aspettiamo finchè viene eseguito. } } |
- Il valore a cui il servo deve arrivare è inferiore a quello corrente, così dobbiamo decrementare la posizione:
1 2 3 4 5 6 |
else if (nextValue > aktValue) { for (int i = aktValue; i > nextValue; i--) { miServo.write(i); delay(10); } } |
Alla fine, salviamo il valore della posizione del servo e sospendiamo l’esecuzione del programma per un secondo:
1 2 |
aktValue = miServo.read(); delay(1000); |