Hai mai notato come le porte degli ascensori o dei cancelli automatici si fermano quando qualcuno si mette in mezzo? Tutto merito di sensori a infrarossi che formano delle “barriere a infrarossi“.
Ho iniziato a sperimentare con le barriere IR per un progetto per un cliente, poi realizzato con dei sensori di ultima generazione, ma sono rimasto colpito da quanto si riesca a fare anche con i sensori più comuni, presenti spesso nei kit base di Arduino.
Esistono diverse tipologie di sensori ad infrarossi, in varie forme e configurazioni: alcune barriere ad infrarossi per esempio sono vendute in coppie emettiore-ricevitore già pronte all’uso. Basta in questi casi metterle ai lati opposti di un passaggio e se qualcosa interrompe il fascio infrarosso, il ricevitore lo rileva subito e può azionare un relè di controllo.
Ma si può anche realizzarle in casa. Una barriera di questo tipo si può costruire con dei LED a infrarossi standard e un ricevitore VS1838B – componenti che si trovano facilmente in molti kit Arduino (e se non ci sono li trovi qui). Sono gli stessi led e ricevitori usati nei telecomandi della TV e nei televisori (il led trasmettitore lo puoi anche smontare da un vecchio telecomando!).
Altri sensori hanno una configurazione diversa: sono sensori combinati, con LED IR e ricevitore affiancati. In questo caso si misura la distanza da un oggetto in base al tempo che impiega la luce infrarossa a rimbalzare sull’ostacolo e tornare indietro. Se si mette un riflettore a una distanza nota, qualsiasi variazione indica che qualcosa si è frapposto.
L’opzione più evoluta di questi sensori sono i TOF (Time Of Flight), come il VL53L1X che possono arrivare a 4m di distanza. Sono piccolissimi e molto precisi, e funzionano proprio misurando il tempo impiegato dalla luce per andare e tornare.
Ecco come ho realizzato la mia barriera IR con un VS1838B e un LED a infrarossi.


Il LED IR sembra un comune LED da 5mm, ma emette luce intorno ai 940nm, invisibile all’occhio umano. Puoi comunque verificare che funzioni puntandolo con la fotocamera dello smartphone: vedrai una luce tenue di colore violetto (la vedi perché la fotocamera del telefono è anche sensibile agli infrarossi, i tuoi occhi no).
Segnali modulati PWM ~
Il VS1838B rileva solo segnali IR modulati, non luce IR continua. Cosa vuol dire?
Significa che il sensore non riceve nulla se semplicemente lo illumini con una luce infrarossa. Devi invece accendere e spegnere il segnale ad una frequenza di 38Khz. Cioè 38000 volte al secondo!
Serve quindi inviare un segnale modulato a 38KHz. Per fortuna Arduino ha dei pin marcati con il simbolo ~ (tilde) che indica che supportano questo tipo di segnali e ha un comando per generarli: tone()
. Di solito lo si usa per suonare con buzzer, ma funziona benissimo anche per i LED IR.
Ecco come ho collegato tutto usando un Arduino Nano:

- Il pin D11 pilota il LED IR attraverso una resistenza da 220 ohm (la resistenza serve ad evitare i picchi di corrente e a non bruciare il led).
- Il ricevitore VS1838B è collegato al pin D2 con un condensatore da 100uF (il condensatore serve per ridurre i disturbi).
Quando il comando tone()
è attivo, genera un’onda quadra a 38KHz, così:

Ma accendere tone non basta. Il sensore è un po’ “capriccioso”: se lasci il comando tone attivo continuamente, dopo poco il sensore smette di rilevare. Si devono inviare dei brevi burst (sequenze 0-1-0-1…) seguiti da una pausa. La lunghezza dei segnali e delle pause è indicata nel datasheet del sensore, il segnale acceso (1 o ON) deve durare 600us, mentre il segnale spento (0 o OFF) deve durare 900us.


La pausa tra una sequenza di ON-OFF e l’altra è un elemento cruciale. Se continui a fare ON-OFF senza fare pause, allora dopo poco il sensore non rileverà più nulla. Nel mio progetto ho scoperto che una pausa di almeno 20ms rende il sistema stabile (anche se il datasheet dice che bastano 5ms).
Sul lato del ricevitore, quindi, possiamo contare quanti impulsi arrivano e capire se la barriera è libera o occupata.


Il codice per emettere impulsi e rilevare i dati con VS1838B utilizzando i timer
Ho provato due metodi diversi per fare il conteggio: con i timer e con gli interrupt.
Con i timer, accendo e spengo il LED IR alternandolo, e conto quante volte il ricevitore rileva un fronte di discesa. I timer non bloccano l’esecuzione e si basano sul conteggio del tempo rispetto a millis
(per i millisecondi) o micros
(per i microsecondi):
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | // // read barrier, infrared with timers and tone // int IR_LED_PIN = 11 ; int IR_RECEIVER_PIN = 2 ; void setup () { pinMode (IR_LED_PIN, OUTPUT ); pinMode (IR_RECEIVER_PIN, INPUT ); Serial.begin ( 115200 ); } int readBarrier( unsigned int len) { int s1_0 = 0 ; int count = 0 ; unsigned long m1 = micros () + len * ( 600 + 900 ); unsigned long m2 = 0 ; // timer switch ON/OFF ir led int k = 0 ; // every m1 timer we turn on/off the signal Len times and check the receiver while ( micros () < m1) { // IR transmitter if ( micros () > m2) { m2 = micros () + (k % 2 = = 0 ? 600 : 900 ); // 600us for 1 and 900us for 0 if (k % 2 = = 0 ) { tone (IR_LED_PIN, 38000 ); } else { noTone(IR_LED_PIN); } // Check received bit and count it while ( micros ()<m2) { int s1 = digitalRead (IR_RECEIVER_PIN); if (s1 = = 0 & & s1_0 = = 1 ) { // falling count + + ; } s1_0 = s1; } k + + ; } } delay ( 20 ); return count; } void loop () { Serial.println ( readBarrier( 10 ) ); } |
Programma Arduino per barriera infrarossi con interrupt
Con gli interrupt, lascio che sia Arduino a contare ogni volta che il segnale del ricevitore scende da ALTO a BASSO. È un metodo più efficiente e preciso perché gli interrupt permettono di definire che funzione eseguire quando succede un cambiamento su un pin. In pratica Arduino si accorge del cambiamento e chiama la funzione che incrementa il contatore:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | // // read barrier, infrared with interrupt and tone // // originally here: https://forum.arduino.cc/t/solved-problem-with-ir-receiver-vs1838b/628739 #define IR_LED_PIN 11 #define IR_RECEIVER_PIN 2 volatile int count; void setup () { pinMode (IR_LED_PIN, OUTPUT ); pinMode (IR_RECEIVER_PIN, INPUT ); attachInterrupt(digitalPinToInterrupt(IR_RECEIVER_PIN), falling, FALLING ); Serial.begin ( 115200 ); count = 0 ; } // this function is called when the sensor output a falling signal void falling() { count + + ; // count it! } int readBarrier( unsigned int len) { for ( int i = 0 ; i < len; i + + ) { tone (IR_LED_PIN, 38000 ); delayMicroseconds ( 600 ); noTone(IR_LED_PIN); delayMicroseconds ( 900 ); } int count2 = count; count = 0 ; // reset counter delay ( 20 ); // minimum pause return count2; } void loop () { Serial.println ( readBarrier( 10 ) ); } |
Entrambi i metodi hanno funzionato bene. Sono riuscito perfino a rilevare ostacoli a oltre 3 metri di distanza e sicuramente si può andare oltre!
Se hai un Arduino e qualche componente IR a disposizione, provalo!
Comments on “Costruire una barriera ad infrarossi con Arduino e sensori VS1838B”