Ciao,
vi ho lasciato alcuni giorni per sedimentare le informazioni che vi ho dato, quindi possiamo proseguire.
Lo scopo di questa mini lezione è di creare un semplice servo tester, cioè quell'oggettino che ci permette di muovere un servo (o anche pilotare l'ESC di un motore) con una semplice manopola di un potenziometro, permettendoci di mettere a punto un modello senza dover utilizzare la radio.
Come premessa spieghiamo come si comanda un servo e come funziona un potenziometro.
Un servo ha un connettore con tre fili: due sono l'alimentazione (tipicamente 5Volt), il terzo è l'ingresso PWM. Questo segnale è costituito da un impulso digitale (quindi i possibili valori sono solo 0V e +5V) , della durata variabile tra 700 e 2100 microsecondi. L'impulso viene ripetuto 50 volte al secondo, cioè ogni 20 millisecondi.
La durata effettiva dell'ìmpulso determina quale posizione deve assumere il servo: 700 microsecondi significa "tutto a destra", 2100 microsecondi significa "tutto a sinistra", o viceversa... non ricordo. Un impulso di 1500 microsecondi significa "servo al centro".
Questi valori (700, 2100, 1500) possono variare un pochino da servo a servo, quindi non sono da considerare come valori fissi ed immutabili.
Il servo riceve questo segnale e lo compara con la posizione attuale del braccetto. Se le due posizioni non corrispondono, allora aziona il motore e sposta il braccetto per portarlo alla posizione richiesta.
Un potenziometro è costituito da una striscia di materiale resistivo, cioè debolmente conduttore, su cui scorre un contatto mobile (cursore). In pratica si comporta come se fossero due resistenze in serie, la cui somma dei valori è il valore nominale del potenziometro (ad esempio 10.000 Ohm), e che costituiscono un "partitore resistivo" o "partitore di tensione" (
https://it.wikipedia.org/wiki/Partitore_di_tensione) . Il valore delle due singole resistenze dipende dalla posizione del cursore, che azioniamo attraverso la sua manopola. Immaginiamo che colleghiamo il terminale destro del potenziometro al positivo dell'alimentazione del nostro circuito (per semplicità facciamo sempre riferimento ai 5V di alimentazione del servo) e il terminale sinistro del potenziometro al negativo dell'alimentazione, avremo che il terminale centrale, che corrisponde al punto di giunzione delle due resistenze, produrrà una tensione in uscita che è una percentuale della tensione di alimentazione ed è funzione della posizione del cursore: se il cursore è tutta a destra, il centrale sarà a +5V, se tutto a sinistra avremo 0V. Una posizione intermedia produrrà una tensione intermedia tra le due. Tutto questo dipende anche dall'eventuale circuito che colleghiamo all'uscita del potenziometro, che potrebbe alterare (anche pesantemente) la regola che ho appena definito. Per evitare questo, è opportuno che il carico applicato abbia una resistenza non inferiore a quella nominale del potenziometro.
A cosa ci serve tutto questo? Vediamo come costruire il nostro servo tester.
Utilizziamo il potenziometro per produrre una tensione variabile che applicheremo al nostro arduino e lui, di conseuenza, produrrà un segnale adatto a pilotare il nostro servo. Allo scopo introdurremo alcune nuove cose: il comando in analogRead(), il concetto di libreria ed il concetto di oggetto.
Partiamo, come al solito, da uno sketch di esempio. Userò lo sketch "Knob", disponibile tra gli esempio della IDE
- Codice: Seleziona tutto
/*
Controlling a servo position using a potentiometer (variable resistor)
by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>
modified on 8 Nov 2013
by Scott Fitzgerald
http://www.arduino.cc/en/Tutorial/Knob
*/
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int potpin = 0; // analog pin used to connect the potentiometer
int val; // variable to read the value from the analog pin
void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop() {
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180)
myservo.write(val); // sets the servo position according to the scaled value
delay(15); // waits for the servo to get there
}
Analizziamo il codice.
Le prime righe ormai le riconosciamo, sono il commento racchiuso tra /* e */
Poi troviamo la riga
#include <Servo.h>Significa che il nostro sketch deve includere una libreria di comandi aggiuntivi, cioè non nativi della IDE, che si chiama Servo.h. Le librerie sono delle cose estremamente diffuse in ambito di programmazione. Contengono delle funzioni aggiuntive specifiche per un determinato lavoro. Nel nostro caso, questa libreria aggiunge i comandi necessari a comandare facilmente un servo. Vedremo il dettaglio nel momento in cui lo utilizzaremo.
La riga successiva crea l'oggetto
myservo utilizzando la tipologia
Servo. Ma cos'è un "oggetto" in programmazione? E' la rappresentazione di un oggetto (fisico o virtuale, non importa) che può avere delle proprietà ed a cui possiamo far fare delle azioni. In altri ambienti di programmazione gli oggetti sono anche capaci di generare eventi, ma non nell'IDE di Arduino.
Cos'è una proprietà di un oggetto? Facciamo un esempio semplice. Andiamo a negozio e compriamo una lampadina (in programmazione "creiamo l'oggetto"). Questa lampadina avrà delle caratteristiche (tensione, potenza, colore, forma, etc), che in programmazione chiamiamo "proprietà". Alcune proprietà sono fisse (quindi le possiamo solo leggere): una volta comprata, non possiamo cambiarne la tensione a cui funziona, ma altre possono essere variabili. Ad esempio la proprietà "accesa" di una lampadina può valere "si" o "no" in funzione del suo stato reale. Analogamente possiamo leggere la proprietà "guasta" per sapere se è sana o se è fulminata.
Ad una lampadina possiamo chiedergli di accendersi o di spegnersi; in programmazione queste azioni si chiamano azioni o, più correttamente, "metodi".
Torniamo al nostro servo.
La riga
#include <Servo.h> ci dice che abbiamo a disposizione un negozio dove comprare dei servi.
Con la riga
"Servo myservo;" compriamo il servo
myservo da quel negozio e ce lo portiamo a casa. Mi perdonino eventuali programmatori esperti che mi leggono se uso delle espressioni non proprio ortodosse, lo scopo di questi articoli è di rendere accessibile la materia a dei profani assoluti.
E' da notare che io potrei benissimo definire due o più servi, basta dargli nomi diversi e collegarli a pin diversi di Arduino.
Servo myservo1;
Servo myservo2;
Servo myservo3;Le due righe che seguono definiscono un paio di variabili che utilizzerò nel corpo dello sketch.
int potpin = 0; // analog pin used to connect the potentiometer
int val; // variable to read the value from the analog pin
Le due variabili conterranno il numero del pin a cui è collegato il potenziometro ed il valore di tensione che Arduino leggerà su quel pin.
Notate che ci sono dei commenti sulla destra, preceduti dal doppio slash //? Sono commenti su una sola riga, a differenza di quelli inclusi tra /* e */ che possono essere scritti su più righe.
Finalmente arriviamo alla setup(), che contiene solo la riga
myservo.attach(9);Questa riga istruisce il sistema per dirgli che il nostro servo sarà collegato al pin 9 di Arduino. La libreria si occuperà di configurare correttamente quel pin, esonerandoci dal doverlo fare noi.
Se avessi avuto più servi, sarebbe stato sufficiente avere più righe:
myservo1.attach(9);myservo2.attach(10);myservo3.attach(11);La loop() contiene infine il codice che viene eseguito continuamente.
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180)
myservo.write(val); // sets the servo position according to the scaled value
delay(15); // waits for the servo to get there
La prima riga legge il valore del pin del potenziometro e mette il valore letto nella variabile
val. Questo valore è un numero compreso tra 0 e 1023. Non rappresenta un valore assoluto di tensione, come sarebbe stato logico aspettarsi, in quanto la tensione di riferimento della analogRead potrebbe essere diversa dal default di 5V. Per adesso ci interessa solo sapere che 0 significa 0V, 1023 significa +5V ed ogni valore intermedio significa una tensione intermedia. Nella pratica, questo valore ci indicherà la posizione del cursore (manopola) del potenziometro. In questo momento Arduino legge la posizione del potenziometro e la userà più tardi. Se muovo il potenziometro dopo che Arduino ha fatto questa lettura, l'esito lo vedremo al prossimo ciclo.
La seconda riga converte il valore di val, che attualmente può valere da 0 a 1023, in un range compreso tra 0 e 180. Questo avviene perché l'oggetto myservo vuole essere istruito semplicemente con l'angolo (espresso in gradi) che deve assumere: 0 gradi significa tutto da una parte, 180 gradi tutto dall'altra e cosi via.
La terza riga "invoca" (altro verbo usatissimo in programmazione, sinonimo di "chiama" o "esegue") il "metodo" (cioè l'azione)
write nel nostro servo, passandogli come parametro il valore di
val. In questo momento il nostro servo si posiziona secondo la posizione del potenziometro letto due righe prima.
La quarta riga introduce semplicemente un ritardo di 15 millisecondi prima di ricominciare il ciclo, in tempo per poter generare un nuovo segnale per il nostro servo. Ricorderete che il segnale per il servo viene prodotto ogni 20 millisecondi.
Domande?
Carlo