controllo e dimming di led colorati in base:
- all'immagine visualizzata su display
- colore fisso scelto dall'utente
- modalità rainbow
- effetti audio
- Host Questa parte gira sul computer e ha il compito principale di analizzare il contenuto multimediale (video o musica) e calcolare, per ciascun momento, quali colori dovranno essere inviati ai led. Una volta elaborati i dati, l’host li spedisce ad Arduino tramite la porta seriale, seguendo un protocollo ben definito. In questo modo, Arduino si limita a ricevere comandi già pronti, senza dover svolgere calcoli complessi.
- Arduino La parte Arduino, invece, ha il compito di ricevere i dati seriali dall’host e comandare i led. Riceve i pacchetti seriali, decodifica il protocollo, imposta i timer PWM (Pulse Width Modulation) sui pin corretti per controllare i led RGB (su Arduino è implementata anche una modalità autonoma, l’effetto Rainbow, che non richiede alcun dato dal PC)
Vengono impostati i pin come output e vengono configurati i timer in modalità PWM Scrivendo valori negli OCR si regola la luminosità
| LED | Colore | PortPin | Timer / OCR | Pin |
|---|---|---|---|---|
| LED0 | R | PL5 | OC5C | Pin 44 |
| LED0 | G | PL4 | OC5B | Pin 45 |
| LED0 | B | PL3 | OC5A | Pin 46 |
| LED1 | R | PH3 | OC4A | Pin 6 |
| LED1 | G | PH4 | OC4B | Pin 7 |
| LED1 | B | PH5 | OC4C | Pin 8 |
| LED2 | R | PE3 | OC3A | Pin 5 |
| LED2 | G | PE4 | OC3B | Pin 2 |
| LED2 | B | PE5 | OC3C | Pin 3 |
| LED3 | R | PB4 | OC2A | Pin 10 |
| LED3 | G | PH6 | OC2B | Pin 9 |
| LED3 | B | PG5 | OC0B | Pin 4 |
LED0 - metà sinistra verticale LED1 - metà sinistra alta LED2 - metà destra alta LED3 - metà destra verticale
| Byte # | Significato |
|---|---|
| 0 | Start byte 0xAA |
| 1 | Start byte 0x55 |
| 2 | Mode (1 = rainbow, 2 = colore fisso, 3 = video frame, 4 = musica) |
| 3 | N dati successivi |
| 4 … N+3 | Payload |
| N+4 | Checksum |
L'host invia i pacchetti via seriale ad Arduino e quest'ultimo riceve i dati e aggiorna di conseguenza i led
N.B. il pacchetto di fine per la seriale ha la seguente modalità 0xFF e non ha il payload, e quando Arduino lo riceve spegne tutti i led
-
Rainbow: Arduino fa ciclare i colori su tutti i led, producendo così un effetto arcobaleno (l'host invia un pacchetto con la modalità selezionata e pacchetto vuoto)
-
Colore fisso: l'utente decide quale colore mostrare sui led, impostando i valori R, G e B (l'host manda un pacchetto con la modalità selezionata e pacchetto di lunghezza tre con i valori scelti di R, G e B)
-
Frame video: l'host analizza un video frame per frame e manda ad Arduino i colori che devonono essere impostati sui led, sincronizzando le luci a ciò che avviene sullo schermo
Step 1 - Estrazione dei frame: vengono estratti i frame in formato PPM (Portable Pixmap) Il formato PPM è fatto in questo modo: P6 width height 255 [binary RGB data] -> indica tutti i pixel ognuno con 3 byte RGB
Step 2 - Analisi dei frame: ogni frame viene letto e analizzato dall’host. Per decidere che colore mandare ai led, ho implementato tre diversi algoritmi tra cui si può scegliere:
a. Media colori: ho diviso i frame in quattro sezioni (una per ogni led) e calcolo la media dei valori R, G, B per ogni regione con 4 thread in modo da calcolarli in parallelo
b. Colore predominante: simile al precedente ma invece di calcolare la media, costruisco un istogramma dei colori diviso in 16 livelli (histo[16][16][16]) e alla fine individuo il colore più popolato
c. K-means: è un algoritmo più complesso e serve per trovare i colori più significativi, anche in immagini molto complesse. Segue i seguenti passi:
START ↓ inizializza centroidi casuali ↓ ciclo iterazioni: → assegna pixel a centroidi → ricalcola centroidi ripeti ↓ per ogni centroide: → calcola dei parametri (saturazione, luminosità, differenza valori rgb) → calcola score scegli cluster col punteggio più alto ↓ ritorna colore dominante
Step 3 - Invio dei colori via seriale: l’host prepara il pacchetto con i colori dei 4 led (payload ha grandezza 12 byte). Poi spedisce il pacchetto seriale ad Arduino, sincronizzandosi con il framerate, in questo modo il cambio colore dei led è sincronizzato con il video.
Per sincronizzare video e led: -> Misuro quanto tempo impiego a elaborare il frame -> Eseguo la logica: analizzo il frame, mando i dati, avvio il video (solo durante il primo frame) -> Calcolo quanto tempo è passato -> Decido quanto aspettare in base a quanto ogni frame deve durare (1sec/FRAME_SEC) -> Faccio dormire il programma
- Musica: funziona in modo simile al video. L’host analizza un file audio in modo che i led possano pulsare seguendo la musica (più la musica è forte, più i led diventano luminosi). Anche qui l’host invia pacchetti seriali identici a quelli della modalità video.
Step 1 - Estrazione dell'audio in formato RAW: questo formato è puro audio digitale, senza intestazioni, né metadati.
Step 2 - Lettura dei campioni: l’audio viene letto in blocchi di 4410 campioni in modo tale da avere 10 campioni al secondo (44100campioni/sec / 10campioni = 4410 dimensione dei blocchi)
Step 3 - Calcolo dell'energia: per ogni blocco di audio si misura RMS (Root Mean Square), che rappresenta la potenza media o l’energia del segnale. L’RMS restituisce sempre un numero positivo compreso tra 0 e 1 che cresce quando il suono diventa più forte. Dal RMS calcoliamo la luminosità dei led moltiplicando per 255
RMS = sqrt( (1/N) * sum_{i=1}^{N} (sample_i / 32768)^2 )
Step 4 - Invio dei colori via seriale: l'host prepara il pacchetto da inviare alla seriale per i led (payload ha grandezza 3 byte). Poi spedisce il pacchetto sincronizzandosi come per la modalità video.