Realizziamo una piccola GUI in Java per gestire Led RGB con Arduino

In questo articolo vedremo come realizzare un’interfaccia grafica in Java che ci permetta di comunicare con Arduino per gestire il colore dei led RGB collegati.
Per realizzare questo progetto ci occorre:

Per quanto riguarda le strip led, visto che esistono un grande varietà di modelli, vediamo nel dettaglio quelli più comuni e cerchiamo di capire le differenze e come funzionano.

Differenza tra WS2801, WS2811 e WS2812

Nel web si trovano principalmente questi tre modelli:

1. WS2801
2. WS2811/WS2812
3. WS2812B

Le sigle sopra citate si riferiscono a circuiti integrati usati per pilotare i LED, ma comunemente usate per identificare le strip led.
Questi  IC possono controllare fino a 3 led, e nel caso delle strip RGB permettono di gestire i led rossi,verdi e blu.
La strip WS2801 (Fig.1) è quella più conosciuta presenta l‘IC esternamente ai led e a differenza degli altri modelli utilizza 4 fili VCC,GND,DATA,CLK presentando la linea di clock separata.

Strip LED WS2801
Fig.1 – Strip LED WS2801

La WS2812 è una strip che contiene all’interno del led 5050 il chip WS2811 ed è pilotabile con solo 3 fili VCC,GND e DATA.
Come visibile in Fig.2 un led 5050 è package di 5mmx5mm con 3 led all’interno (rosso,verde e blu), inoltre si può notare che, nella strip WS2812, all’interno del led si vede il chip WS2811 assente invece nel classico led 5050.

Strip LED WS2812 (a sinistra) e LED 5050 (a destra)
Fig.2 – Strip LED WS2812 (a sinistra) e LED 5050 (a destra)

Giusto per confondere ulteriormente le idee 🙂 sul web potete trovare anche il modello WS2812B ma non preoccupatevi questo modello è molto simile a quello della versione precedente WS2812, infatti avremo sempre i 3 contatti per pilotare la strip, le differenze principali riguardano la struttura interna del led e come si vede in Fig.3 la presenza di soli 4 pin e non più 6.
Se volete approfondire la differenza tra questi due ultimi modelli vi rimando a questo sito http://rgb-123.com/ws2812b-vs-ws2811/.

WS2812B (in alto a sinistra), WS2812 (in basso a destra) e WS2812B (a destra)
Fig.3 – WS2812B (in alto a sinistra), WS2812 (in basso a destra) e WS2812B (a destra)

Collegare Arduino alla strip WS2812

Ora che abbiamo capito le differenze tra tutti questi modelli dobbiamo capire come farli funzionare o meglio come collegarli ad Arduino.
Come si vede in Fig.2 e Fig.3 sulla strip sono presenti delle frecce, queste indicano la direzione dei dati lungo la strip quindi per farla funzionare correttamente bisogna saldare i 3 file come indicato in Fig.4. L’alimentazione è di 5 V e il pin dei dati può essere collegato ad un qualsiasi pin digitale di Arduino, l’utilizzo della resistenza da 470 ohm è facoltativa.

Arduino e WS2812
Fig.4 – Arduino e WS2812

 Sketch Arduino

Prima di passare al codice java vediamo il codice da caricare sulla nostra scheda Arduino e cerchiamo di capire come funziona.

Nelle prime due righe vengono importate le due librerie necessarie per il corretto funzionamento del codice, in particolare la prima Adafruit_NeoPixel.h è utilizzata per pilotare i led mentre la seconda MoodLight.h per realizzare l’effetto arcobaleno.

Dalla riga 4 alla 10 sono state definite le variabili usate nel codice, in particolare:

  • #define PIXEL_PIN 10: Indica il pin della scheda Arduino collegato alla linea dati della strip led.
  • #define PIXEL_COUNT 20: Indica il numero totale di led presenti sulla strip, necessario per creare successivamente l’oggetto Adafruit_NeoPixel.
  • int valueRead: Una variabile di tipo intero usato per leggere i dati dalla seriale.
  • byte data_in[4]: Un array di tipo byte dove salvare i quattro byte inviati dall’applicazione java.
  • int saturation: Una variabile di tipo intero usata per definire il valore di saturazione dei led, necessaria per creare l’oggetto Moodlight. Il valore varia tra 0 e 255.
  • int brightness: Una variabile di tipo intero usata per definire il valore di luminosità dei led, necessaria per creare l’oggetto Moodlight. Il valore varia tra 0 e 255.
  • int hue: Una variabile di tipo intero usata per definire il valore del colore dei led, necessaria per creare l’oggetto Moodlight. Il valore varia tra 0 e 359.

Nelle righe 12 e 13 vengono creati due oggetti: Adafruit_NeoPixel e MoodLight.

Il primo campo del costruttore Adafruit_NeoPixel rappresenta il numero di pixel presenti sulla strip, il secondo il pin digitale di Arduino usato, mentre l’ultimo parametro indica il tipo di strip Neopixel usata. Per maggiori informazioni https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library.

NOTA: Neopixel è la marca della strip led WS2812 realizzata da Adafruit.
L’oggetto MoodLight invece non ha parametri ed è usato per creare l’effetto arcobaleno.

Nel setup() la prima riga apre la porta seriale e setta il data rate a 9600 bps, mentre le righe successive inizializzano tutti i pixel allo stato off.

All’interno del loop() possiamo distinguere due blocchi il primo serve per leggere i dati da seriale, nel nostro caso ogni volta che sono disponibile più di 3 byte questi vengono letti e con un ciclo for salvati nell’array data_in.

Il secondo blocco è usato invece per la scelta dell’animazione dei led, nello specifico si è scelto di pilotare i led singolarmente se il primo byte salvato nell’array data_in è uguale al carattere ‘A’ mentre con l’effetto arcobaleno in caso sia uguale a ‘B’.

Da notare che nel caso dell’effetto arcobaleno il dato inviato dall’applicazione java è un numero compreso tra 0 e 359 per questo sono usati 2 byte, e quindi per ricostruire il dato e salvarlo nella variabile intera hue si usa la seguente riga di codice data_in[2]*256+data_in[1], quando vedremo il codice java sarà tutto più chiaro.

Ora vediamo nel dettaglio come sono realizzate le due funzione richiamate nel loop().
La prima single_color() setta attraverso la for tutti i led della strip utilizzando il metodo setPixelColor() che riceve in ingresso 4 parametri, il primo indica il numero del pixel da accendere e come per gli array l’indice parte da 0 per cui in una strip da 20 led il primo led sarà lo 0 mentre l’ultimo il 19, i restanti 3 parametri indicano la luminosità dei colori rispettivamente rosso, verde e blu.
Con strip.show() si rendono effettivi i settaggi dei colori verso la strip led.

La seconda funzione rainbow_light(int hue) è utilizzata per creare l’effetto arcobaleno, questo grazie ad un parametro in ingresso che identifica il colore.

ml.setHSB(hue, saturation , brightness) permette di settare gli attributi colore, saturazione e luminosità dell’oggetto ml.
Anche in questo caso il for è utilizzato per settare il colore definito dalla variabile hue su tutti i led della strip.
Per ottenere i colori dall’oggetto ml si invocano i metodi getRed(), getGreen() e getBlue().

GUI Java

Siamo quasi alla fine, ora ci manca solamente di realizzare l’interfaccia grafica in java che ci permetta di modificare il colore dei led collegati ad Arduino.
Come prima cosa apriamo Eclipse e dopo aver creato un nuovo progetto Java “ArduinoRGB” inseriamo un file .java scegliendolo attraverso il wizard: WindowBuilder->Swing Designer->Application Window e definiamo la classe ArduinoRGB.
Ora abbiamo la struttura iniziale della finestra e la possibilità di modificare il codice attraverso l’interfaccia grafica offerta da questo plug-in spostandoci nella scheda Design.
In Fig.5 possiamo vedere quello che andremo a realizzare, quindi iniziamo!

GUI Java
Fig.5 – GUI Java

Come prima cosa iniziamo ad inserire tutti gli elementi che ci occorrono all’interno della finestra e posizioniamoli come in Fig.5, oppure date spazio alla vostra fantasia e definite la vostra GUI.
Come per una ricetta quello che ci serve sono:

  • 4x JSlider
  • 6x JLabel
  • 1x JCheckBox
  • 2x JButton
  • 1x Choice

Prima di passare al codice facciamoci aiutare da questo plug-in per definire alcune impostazioni iniziali di questi elementi.
Iniziamo con le Label una volta selezionate nella finestra Properties andiamo a cambiare il campo text con il nome che vedete in Fig.5, scegliamo il colore in foreground, il font e per ultimo nella casella Variable diamo un nome significativo alle varie Label per esempio per la scritta “RED” mettiamo lblRed, questo vale per tutti gli elementi che inseriamo in quanto quando si passa al codice è più semplice riconoscerli.
Dopo aver finito con le Label passiamo agli Slider e sempre nella finestra Properties nel campo maximum scriviamo 255 per gli slider Red, Green e Blu mentre 359 per lo slider Rainbow. Come valore iniziale value mettiamo 0.
Per i Button le impostazioni da modificare sono solamente il campo text, per il Checkbox il campo label mentre il Choice è già pronto così.
Dimenticavo per i seguenti elementi: Button “Reset LED”, i 4 Slider e il Checkbox “Rainbow” bisogna deselezionare il campo enable (false) in quanto ad avvio applicazione non devono essere abilitati fintanto che  non si stabilisce una connessione.

Focus codice Java

Ora che abbiamo definito la nostra GUI possiamo passare al codice vero e proprio, visto che però è molto lungo mi soffermerò principalmente nei punti inseriti da me e non sul codice auto-generato dal plug-in WindowBuilder.

La prima cosa che dobbiamo fare è inserire la libreria jSCC, utilizzata per la comunicazione seriale, per fare questo dobbiamo fare click con il tasto destro sul progetto “ArduinoRGB” selezionare Properties->Java Build Path->Libraries->Add JARs e caricare il file .jar contenente la libreria scaricata in precedenza. Per poter usare questa libreria dobbiamo importarla nel file .java con la seguente riga di codice.

Inseriamo nella classe ArduinoRGB i seguenti attributi in modo tale da essere visibili in tutti i suoi metodi.

  • SerialPort serialPort: Un oggetto SerialPort descrive l’interfaccia di basso livello di una porta seriale definendo le funzionalità minime richieste.
  • String[] listPort: Un array di stringhe contenente i nomi delle porte seriali disponibili.
  • boolean init: Un boolean, inizializzato a false, usato per capire quando si è instaurata la connessione.

Iniziamo a vedere alcuni metodi della classe ArduinoRGB, il primo è serialInitialize() questo metodo permette di aprire la porta seriale, precedentemente scelta, e di settare i seguenti parametri della porta: baud, n° bit di dati, n° bit di stop e la parità della porta il tutto all’interno di un blocco try-catch per gestire eventuali eccezioni.

Il metodo serialWrite(int[] rgbValue) permette di inviare sulla seriale 4 byte, secondo una determinata struttura, utilizzati da Arduino per accendere il colore del led scelto dalla GUI.
Il primo byte data[0] contiene il carattere ‘A’ indica l’animazione singleLed() presente nel codice Arduino, i restanti 3 byte prendono i valori (0-255) passati in ingresso dall’array rgbValue che definisce rispettivamente i colori rosso, verde e blu.
Una volta salvato i valori nell’array data questi vengono inviati con la seguente riga di codice serialPort.writeBytes(data).

Di seguito possiamo vedere l’overloading del metodo serialWrite che questa volta accetta un intero rainbowValue il cui valore si riferisce al colore dell’arcobaleno da dare in ingresso alla funzione rainbow_light(hue) presente nel codice Arduino.
Da notare che data[0] questa volta è uguale ‘B’ per avvisare Arduino di usare l’effetto arcobaleno, inoltre  per inviare rainbowValue valore che varia tra 0 a 359 un solo byte non basta per cui se ne usano 2 e sul secondo si prende il valore di ingresso shiftato a destra di 8 bit, data[3] invece non è usata quindi è impostata 0.

L’ultimo metodo che andiamo a vedere è initialize() usato per inizializzare il contenuto della finestra, ossia tutti gli elementi che abbiamo definito all’inizio nell’area Design.
Prima di tutto creiamo un array che conterrà la tripletta di valore per il led rosso, verde e blu da inviare per seriale.

Ora inseriamo i vari eventi per gestire gli slider rosso, verde, blu e rainbow. Come si vede nel codice qui sotto, scegliendo dalla sezione Design, cliccando sull’evento change dell’elemento slider viene creato il metodo   stateChanged(ChangeEvent e) all’interno del quale si può inserire cosa vogliamo accada al verificarsi del movimento dello slider.

Nel nostro caso quando si verifica un cambiamento del valore dello slider si controlla prima se la connessione con la porta seriale è attiva (init == true) e in caso positivo si salva nell’array rgb[2] il valore dello slider e lo si invia tramite serialWrite(rgb). Un codice simile è usato per gestire lo stesso evento per gli altri slider.

Il metodo itemStateChanged(ItemEvent e) è utilizzato per gestire l’evento riguardante il cambiamento di stato del CheckBox “Rainbow“, quando si verifica tale evento si controlla lo stato del checkbox se è selezionato si attiva lo slider rainbow, si disattivano gli altri 3 (rosso, verde e blu) settando i loro valori a 0 ed infine si invia il valore del colore sulla seriale con serialWrite(sliderRainbow.getValue()).
In caso sia deselezionato si disattiva lo slider rainbow e si attivano gli altri inviando la tripletta dei colori rgb sulla seriale.

Più avanti nel codice troviamo l’evento per il button “Reset LED“, se premuto reimposta i valori degli slider a 0 in base allo stato del checkBox “Rainbow“.

L’ultimo tasto della nostra GUI rimane il button “Update” che ci permette di aggiornare la lista delle porte seriali disponibili all’interno dello Choice.

Ogni volta che si preme viene aggiornato l’array listPort attraverso SerialPortList.getPortNames(), quindi si rimuovono tutti i vecchi elementi all’interno dello choice e con una for si aggiornano quelli nuovi.

Infine la parte forse più importante e quella che viene eseguita per prima 🙂 è la seguente, ossia l’inizializzazione della porta e l’abilitazione degli slider (rosso, verde e blu).

Infatti quando si sceglie una porta dalla lista viene aperta la porta e settati i parametri (serialInitialize()) e abilitati i vari slider, checkbox e il button ResetLed.

Siamo arrivati alla fine di questo lungo articolo spero che sia stato tutto chiaro, in caso di problemi o dubbi potete lasciare un commento.
Il codice del progetto lo potete scaricare cliccando sull’icona qui sotto.

Download
Download