Dispense Arduino
Materiale tratto dal nostro corso di base Arduino, con esempi ed esercizi
Impulsi, LED variabili e motori
Affrontiamo adesso l'argomento della generazione di impulsi variabili con Arduino, funzione nota come PWM; è una tecnica molto utilizzata perché produce effetti equiparabili ad un output analogico: la applicheremo infatti per variare la luminosità dei led o la velocità dei motori.
Nella seconda parte della pagina accenneremo ad alcuni tipi di motori ed ai metodi per pilotarli con Arduino.
Il PWM

PWM è l'acronimo di Pulse Width Modulation, ovvero
modulazione a larghezza di impulso: questa è una funzionalità
che possiedono alcuni piedini del microcontrollore, che
consente di generare un'onda quadra a frequenza
fissata, ma con un tempo ON solitamente diverso da quello
OFF. Nell'immagine a lato, ad esempio, abbiamo un segnale
con un periodo di 2ms, e quindi con una frequenza di
500Hz ().
Il segnale è però alto solo per 1/3 del periodo, circa 0.67ms:
la percentuale di tempo in cui il segnale è ON per ogni periodo
prende il nome di duty cycle (ciclo utile), e in questo caso
è circa 33%.

Il PWM è generato in maniera asincrona rispetto al programma
caricato, ed è gestito da componenti hardware (timer) che hanno
un'uscita su soli 6 pin, contrassegnati da una tilde ~ o dalla
sigla PWM
.
Il primo esempio che vediamo riguarda il led dimming, andremo cioè a variare la luminosità di un LED alimentandolo con impulsi anziché con una tensione fissata. La minore luminosità è dovuta alla persistenza della visione dell'occhio, che non distingue il lampeggio del led, e ne percepisce una luminosità media continua.

const byte PWMpin = 11; void setup() { pinMode(PWMpin, OUTPUT); } void loop() { // Accensione for (byte dim = 0; dim < 255; dim++) { analogWrite(PWMpin, dim); delay(10); } // Spegnimento for (byte dim = 255; dim > 0; dim--) { analogWrite(PWMpin, dim); delay(10); } }
Vediamo che il circuito non è variato molto dal più semplice esempio del led lampeggiante, tranne per il pin a cui è collegato, che adesso deve necessariamente essere abilitato all'output PWM.
Nel programma andiamo invece ad impostare il pin in output, per poi
entrare nel loop
. Qui incontriamo la funzione
analogWrite(pin, duty)
, che si occupa della generazione
del segnale PWM: il primo parametro pin
è il pin su cui
si va a fare l'output, 11 nel nostro caso; duty
va
invece ad impostare il duty cycle, la larghezza dell'impulso.
Siccome i timer di Arduino sono ad 8-bit, dovrà essere un valore
compreso fra 0 e 255.
È presente un ciclo for
con cui si incrementa
la variabile dim
, ottenendo ad ogni giro un duty cycle
maggiore. Siccome la variazione è pressoché istantanea (il clock
di Arduino è a 16MHz, ogni operazione è eseguita in circa 70
nanosecondi) è inserita una pausa di 10 millisecondi nel ciclo,
in questo modo il led si accenderà gradualmente in circa 2.5 secondi.
Con il secondo for
si esegue l'operazione simmetrica
di spegnimento graduale.
Esercizi
- Crepuscolare proporzionale: riprendi l'esercizio del crepuscolare della lezione precedente, e accendi il led con una luminosità inversamente proporzionale alla luce letta;
- Arcobaleno: realizza un programma che replichi i colori della scala cromatica con un LED RGB, in modo continuo;
- Lampada colorata regolabile: crea una piccola lampada, usando un led RGB, un pulsante e un potenziometro. Con il pulsante selezioni uno dei colori fondamentali (rosso, verde o blu), mentre con il potenziometro regoli l'intensità di quello selezionato;
Motori DC
Per uso hobbystico, a basse tensioni e correnti, si trovano sul mercato principalmente tre tipi di motori:
- in corrente continua, anche detti motori DC (Direct Current), molto semplici da pilotare poiché è sufficiente sottoporli ad una tensione fissata per metterli in rotazione. Hanno solitamente due morsetti;
- stepper o passo-passo, più complessi nel funzionamento poiché composti da gruppi di bobine che devono essere alimentate in un determinato ordine, e per questo non trattati in questa dispensa. Hanno dai 4 ai 6 fili;
- servo, che sono in realtà motori DC provvisti di meccanica e circuiteria già pronti, per questo più semplici da gestire. Hanno 3 fili;
Per quanto riguarda la descrizione teorica dei motori DC rimando alla relativa pagina del sito, dove sono descritti in maniera più approfondita. L'unica discrepanza che si incontra riguarda l'esempio di collegamento con Arduino, dove si fa uso di un particolare tipo di transistor adatto a correnti più elevate. Vediamo qui un esempio con un generico BC546 al suo posto (transistor BJT NPN).


const byte POTENZ = A0; // potenziometro const byte MOTORE = 9; // motore void setup() { // inizializza il motore come output pinMode(MOTORE, OUTPUT); } void loop(){ byte valore = map(analogRead(POTENZ),0,1023,0,255); // il motore gira con velocità proporzionale alla // rotazione del potenziometro analogWrite(MOTORE,valore); delay(10); }
La circuiteria è totalmente equivalente a quella descritta nella
pagina dedicata, mentre il codice
sorgente differisce in parte: abbiamo un potenziometro da cui leggiamo
un valore, che viene però riproporzionato, utilizzando la funzione
map
, per essere ristretto in un intervallo 0~255
anziché 0~1023.
Così come per i LED, anche il motore può essere alimentato con
un segnale PWM: anch'esso ha una determinata inerzia, e con un segnale
impulsivo variabile possiamo variarne la velocità, senza perdere
eccessivamente in coppia motrice: difatti per rallentarlo si potrebbe
anche ridurne la tensione ai capi, ma ciò indebolisce i campi
magnetici interni, e quindi la forza motrice.
Esercizi
- Ventilatore: Realizza una piccola elica in cartoncino da apporre sul motorino, e accendilo con una velocità proporzionale alla misurazone dal sensore di temperatura;
- Trappola rumorosa: fai vibrare il motorino se rilevi un'ombra sulla fotoresistenza;
Servomotori
Quando un progetto richiede una buona precisione nei movimenti
si può ricorrere a svariate soluzioni: motori passo passo,
uso di encoder su motori DC per poter conoscerne la
posizione esatta, ma senza dubbio la soluzione più economica
per piccole applicazioni è il motore servo.
In un parallelepipedo di plastica è integrato un motore DC
provvisto di ingranaggi di riduzione, per aumentarne la coppia,
un potenziometro che rileva la posizione dell'asse, ed una scheda
elettronica che consente di pilotarlo con un singolo filo.
Il range di movimenti è, solitamente, da 0 a 180°, anche se si
possono trovare anche modelli che possono compiere un giro completo.
Il funzionamento interno, in linea di massima, non è molto complesso: il servo è pilotato con segnale PWM, che viene convertito in un segnale analogico con appositi filtri. Un comparatore interno confronta il segnale inviato con la lettura sul potenziometro interno, muovendo il motore se questi sono diversi. L'equilibrio si raggiunge quando l'asse raggiunge la posizione desiderata (un meccanismo elettronico di questo tipo è detto feedback negativo)
In realtà a noi non interessa molto il funzionamento interno, poiché Arduino integra una libreria che provvede automaticamente a generare un segnale PWM corrispondente ad un angolo specificato.

#include <Servo.h> Servo myservo; void setup() { myservo.attach(9); } // Libreria per i servo // crea un oggetto Servo (myservo) // setta il pin 9 al servo void loop() { for (byte posizione = 0; posizione < 180; posizione++) { myservo.write(posizione); // Muove il servo a zero delay(10); } delay(1000); // Pausa for (byte posizione = 178; posizione > 0; posizione--) { myservo.write(posizione); // Muove il servo a zero delay(10); } delay(1000); // Pausa }
L'obiettivo dell'esempio è di far ruotare il motore dalla posizione
0° fino a 180°, per poi farlo tornare indietro dopo una pausa di un
secondo.
Le connessioni elettroniche di un servo non richiedono l'uso di
una breadboard, essendo molto semplici: è necessario solamente
alimentarlo e collegare il morsetto di controllo ad Arduino, in
questo caso il pin 9.
La prima riga del codice specifica che sarà necessario aggiungere
alla compilazione anche la libreria Servo.h
. Con
questa è possibile creare un oggetto Servo
:
si tratta di una struttura dati tipica del C++ che agglomera
un insieme di variabili e funzioni, nel nostro caso
chiamata myservo
. All'interno dell'oggetto sono
nascoste, in questo caso, le istruzioni per il funzionamento
del motore servo. Noi possiamo controllarlo senza dover
mettere mano ai meccanismi precedemente descritti, semplicemente
chiamando specifiche funzioni: vediamo nel setup attach(9)
,
con cui si imposta il pin di Arduino destinato all'output verso
il motore.
Nel loop invece si richiama write(passi)
, settando con
un valore compreso fra 0 e 179 la posizione del servo. Sarà
la funzione poi a convertirlo nell'adeguato valore di PWM da
generare sul pin di output.
La variazione di posizione del motore non è istantanea, pertanto
è necessario inserire una piccola pausa fra un movimento e l'altro.
Riducendone il tempo, la funzione write(passi)
viene
chiamata con frequenza maggiore, pertanto il motore si muoverà
più rapidamente.
Esercizi
- Servo comando: muovi il servo nella posizione letta da un potenziometro, stabilizzando le letture per evitare oscillazioni;
- Termometro a lancetta: utilizza il servomotore e un termistore per simulare un vecchio termometro a lancetta. Puoi usare del cartoncino per realizzare una freccia ed una scala graduata;
