ReSpeaker 4 LEDs mit Pi4J steuern
Motivation
Für ReSpeaker im allgemeinen gibt es bereits zahlreiche Bibliotheken, auch einige die LEDs über die GPIO Pins ansteuern. Leider sind diese in Python geschrieben und somit wenig hilfreich für Java Projekte.Da die LEDs an verschiedenste Ereignisse gebunden werden sollen, habe ich mich zunächst auf die Suche gemacht, um eine geeignete Bibliothek für den ReSpeaker 4 zu finden.Für den Respeaker 2 wurde ich tatsächlich fündig, allerdings funktioniert dieser Code nicht mit dem ReSpeaker 4.So entstand diese Bibliothek, welche nachfolgend hier erläutert wird.
Technische Nebensachen – Pins usw.
Der ReSpeaker 4 wird bekanntlich über die GPIO Pins des Raspberry PIs verbunden, ob direkt oder über ein Flachbandkabel beeinflusst die Ansteuerung nicht.Standardmäßig werden dabei nachfolgende Pins verwendet:Data Pin – 12Clock Pin – 14Power Pin – 21Jetzt unterscheided die PI4J Bibliothek zwei unterschiedliche Setzstrukturen der Pins, nämlich Default aka wPi und Broadcom.Der nachfolgende Code geht vom Default aus. Um zu sehen, welcher Pin dem Broadcom- Muster gegenüber steht kann der Befehlgpio readall
verwendet werden.
Benötigte Komponenten
- PI4J
- ReSpeaker 4
- Raspberry Pi (gestet ab 3 b+, sollte aber auch mit Zero gehen)
Pi4J einbinden
Wie gewohnt, lässt sich die benötigte Bibliothek einfach über Maven einbinden.
<dependencies>
<dependency>
<groupId>com.pi4j</groupId>
<artifactId>pi4j-core</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
Allgemeiner Programmablauf
Zuerst benötigt der Speaker Power. Dafür muss der Power Pin (hier Pin 21) auf High gesetzt werden. Im Anschluss daran erfolgt die Festlegung des Datenpins und des Tacktpins (Pin 12 und 14) .
Die Farben der LEDs sind bytecodiert und müssen im entsprechenden Byte Muster übertragen werden.
Insgesammt besteht der übertragene Wert aus 32- Bits. Die ersten 8 Bits stehen für die Helligkeit, gefolgt von 8 Bits Rot-Anteil, 8 Bits Grün-Anteil und abschließend 8 Bits Blaue-Anteil. Im Code wird dies mit dem Shift-Operator umgesetzt:
data = ( brightness << 24 ) | ( redRatio << 16 ) | ( greenRatio << 8 ) | blueRatio
Finally Getting Started
Zunächst erfolgt eine Initiallisiering der PI4J Bibliothek. Dafür wird die zugehörige Factory-Methode verwendet. Wie bereits oben erwähnt, erfolgt alles mit der standard Default Pinbelegung. Ansonsten könnte in der Zeile 2 bei setDefaultProvider auch die Broadcom Belegung gewählt werden.
public void init(Pin data_pin, Pin clock_pin) {
GpioFactory.setDefaultProvider(new RaspiGpioProvider());
GpioController gpioController = GpioFactory.getInstance();
setPowerToHigh(gpioController);
dataPin = gpioController.provisionDigitalOutputPin(data_pin);
clockPin = gpioController.provisionDigitalOutputPin(clock_pin);
data = new int[numberOfLights];
resetAllLights();
}
Nach dem holen der Instanz erfolgt das Aktivieren des Power Pins, das setzten des Daten- und Taktpins und das vorbereiten des Datenarrays. Abschließend werden alle LEDs auf den Auszustand gesetzt.
private void setPowerToHigh(GpioController gpioController) {
gpioController.provisionDigitalOutputPin(RaspiPin.GPIO_21).high();
}
public void resetAllLights() {
for (int i = 0; i < numberOfLights; ++ i) {
data[i] = 0;
}
show();
}
Setzen der LED-Farben
Die übertragung der Farben erfolgt in drei Schritten über die Methode show():
- Preamble setzen
- Bits übertragen
- Abschluss setzen
public final void show() {
sendPreamble();
sendData();
sendLatch();
}
private void sendPreamble() {
for (int i = 0; i < numberOfLights; ++ i)
writeByte(( byte ) 0);
}
private void sendData() {
for (int i = 0; i < numberOfLights; ++ i)
writeLedData(data[i]);
}
private void sendLatch() {
dataPin.setState(false);
for (int i = 0; i < 36; ++ i) {
clockPin.setState(true);
clockPin.setState(false);
}
}
private void writeByte(byte out) {
for (int i = 7; i >= 0; -- i) {
dataPin.setState( ( out & ( 1 << i ) ) != 0);
clockPin.setState(true);
clockPin.setState(false);
}
}
private void writeLedData(int data) {
writeByte(( byte ) ( 0xe0 | ( ( data >> 24 ) & 0x1f ) ));
writeByte(( byte ) ( data ));
writeByte(( byte ) ( data >> 8 ));
writeByte(( byte ) ( data >> 16 ));
}
In diesen Methoden erfolgt neben dem Übertragen der Lichtbits, auch das setzten des Clock Pins auf die notwendigen Zustände.
Während die writeByte() Methode die entsprechenden Bits an die GPIO-Schnittstelle überträgt, beendet die sendLatch() Methode die Übertragung. In dieser Methode werden 36 Nullen gesendet, um das Ende zu signalisieren.
Verwendung
Nach dem Instanziieren der Class muss zuerst der Data und Clock Pin gesetzt werden, anschließend lässt sich über die setLight() Methode jede der verfügbaren LEDs auf die gewünschte Farbe setzen. Während die erste Variable für den LED Index steht, folgen danach die RGB Werte. Zuletzt steht der Helligkeitsfaktor mit einem Maximalwert von 31.
Über die Show() Methode erfolgt dann die letztendliche Übertragung an den ReSpeaker.
GPIOLEDController t = new GPIOLEDController(12);
t.init(RaspiPin.GPIO_12, RaspiPin.GPIO_14);
//Setzt die erste LED auf rot
t.setLight(0, 255, 0, 0, 31);
t.show();
Fazit
Der ReSpeaker ist ein sehr schöner Baustein um Zustände zu visualisieren. Neben der offensichtlichen Funktion als 4-fach Lautsprecher, eignet er sich mit seinen 12 LEDs auch perfekt um die gängigen Sprachassistenten nachzuempfinden und deren Muster nachzubauen.
Für Java bestehen nach meinem Kenntnisstand noch nicht viele Anwendungen, da die Mehrheit doch Python verwendet. Für Python stellt der Hersteller bereits Bibliotheken auf seinem Github zur Verfügung.
Ich hoffe mit dieser Bibliothek auch die Java Entwicklung zu ermutigen und gleichzeitig zu unterstützen.
Die ganze Java Bibliothek befindet sich auf meinem Github.