.NET LED Streifen W2812B mit dem Raspberry PI 3 oder FT232H Breakout Board

by
.NET LED Streifen W2812B mit dem Raspberry PI 3 oder FT232H Breakout Board

Einleitende Worte

In diesem Blogpost wird gezeigt, wie ein LED-Streifen (WS2812B) gesteuert werden kann, sowohl unter Windows als auch unter Linux, beispielsweise auf einem Raspberry Pi. Für die Steuerung können die GPIO Pins des Raspberry Pi Board verwendet werden oder das Breakout-Board FT232H, um den Entwicklungsrechner zu verwenden oder falls das Gerät keine GPIO Pins besitzt.

Die Kommunikation erfolgt über das Netzwerk, wobei eine .NET-Anwendung auf dem Raspberry Pi läuft, die Webanfragen entgegennimmt und sie in Steuerbefehle für den Lichtstreifen umsetzt.

Vorbereitung

Es wird Visual Studio 2022 und das dotnet 8 SDK benötigt, um das Projekt bearbeiten zu können.

Das Breakout-Board FT232H kann über USB-C direkt mit dem Entwicklungsrechner verbunden werden. Die Codebasis ist auf GitHub verfügbar. Es wird lediglich 5V, Gnd und D1 verwendet. 5V wird mit der Plus Leitung des LED Streifens verbunden, Gnd mit der Minus Leitung und D1 mit der SPI Steuerleitung.

FT232H Breakout Board direkt am Entwicklungsrechner via USB-C angeschlossen
FT232H Breakout Board direkt am Entwicklungsrechner via USB-C angeschlossen

Installation .NET Runtime auf dem Raspberry Pi

Um die Installation zu starten, führt bitte die folgenden Befehle via SSH auf dem Raspberry Pi aus:

wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh
chmod +x ./dotnet-install.sh
./dotnet-install.sh --channel 8.0

Danach fügen wir die .NET-Runtime zur PATH-Variablen hinzu, um sicherzustellen, dass der Befehl dotnet im Terminal ausgeführt werden kann.

echo 'export DOTNET_ROOT=$HOME/.dotnet' >> ~/.bashrc
echo 'export PATH=$PATH:$HOME/.dotnet' >> ~/.bashrc

Zum Abschluss könnt ihr den Befehl dotnet --version ausführen, um zu überprüfen, ob die Runtime nun in der gewünschten Version verfügbar ist.

Konfiguration Raspberry Pi

Zuerst wird eine SSH Verbindung zum Raspberry Pi benötigt.

Anschließend geben wir den Befehl sudo raspi-config ein.

Daraufhin wählen wir die Option 3 "Interface Options" aus.

Als nächstes wählen wir "I4 SPI".

Dann werden wir gefragt: "Would you like the SPI interface to be enabled?". Hier wählen wir Yes.

Anschließend erscheint die Ausgabe "The SPI Interface is enabled"

Zum Schluss muss der Raspberry Pi neu gestartet werden. Diese Einstellungen sind wichtig, da der Raspberry Pi nun SPI Verbindungen über die GPIO Pins zulässt.

Anschluss Raspberry Pi

Anschlussplan Raspberry Pi
Anschlussplan Raspberry Pi

Der LED Streifen muss nur an +5V Power (PIN 2), GND (PIN 6) und dem SPI0_MOSI (PIN 19) angeschlossen werden.

Einführung in die .NET Softwarelösung

Um das FT232H Breakout Board über HTTP-Anfragen zu steuern, ist ein Webhost erforderlich. Dies wird erreicht, indem das Projekt in der Program.cs so konfiguriert wird, dass ein Webhost eingerichtet wird. Ein Vorteil dieser Lösung ist, dass Dependency Injection zur Verfügung steht, um weitere Services zu registrieren, wie es für den LEDStripService implementiert ist. Dadurch bleibt die Program.cs übersichtlich, insbesondere wenn das Projekt an Komplexität zunimmt.

using Iot.Device.FtCommon;
using RaspberryPi.Web.LEDControl;
using RaspberryPi.Web.LEDControl.Models.Settings;
using RaspberryPi.Web.LEDControl.Services;
using System.Device.Gpio;
using System.Device.Spi;

await Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        var settingsService = new SettingsService();
        LedStripSettings ledStripSettings = settingsService.GetLedStripSettings();
        HostingSettings hostingSettings = settingsService.GetHostingSettings();

        webBuilder.UseStartup<Startup>();
        webBuilder.UseUrls(new[] { $"http://0.0.0.0:{hostingSettings.Port}" });
        webBuilder.ConfigureServices(services =>
        {
            var devices = FtCommon.GetDevices();
            var usbConverterDevice = devices.SingleOrDefault(x => x.Id == Convert.ToUInt32(ledStripSettings.UsbConverterId, 10));
            var usbConverterSpiConnectionSettings = new SpiConnectionSettings(0, 3) { ClockFrequency = 2_400_000, DataBitLength = 8, ChipSelectLineActiveState = PinValue.Low };
            var raspberryGpioSpiConnectionSettings = new SpiConnectionSettings(0, 0) { ClockFrequency = 2_400_000, DataBitLength = 8, ChipSelectLineActiveState = PinValue.Low };
            
            services.AddSingleton(x => new LedStripService(ledStripSettings.NumberOfLeds, ledStripSettings.UseUsbConverter, usbConverterDevice != null ? usbConverterSpiConnectionSettings : raspberryGpioSpiConnectionSettings, usbConverterDevice));
        });
    })
    .Build()
    .RunAsync();

Die Konfiguration der Routen erfolgt in der Datei Startup.cs. Aktuell sind fünf Routen definiert:

endpoints.MapGet("/", () => "LED Web Control is running...");
endpoints.MapPost("/ledcontrol/setlighting", async (context) => await LedControlMessageHandler.HandleLedStripMessageAsync<LedStripSetLightningMessage>(context, ledStripService, default));
endpoints.MapPost("/ledcontrol/reset", async (context) => await LedControlMessageHandler.HandleLedStripMessageAsync<LedStripResetMessage>(context, ledStripService, default));
endpoints.MapPost("/ledcontrol/action", async (context) => await LedControlMessageHandler.HandleLedStripMessageAsync<LedStripActionMessage>(context, ledStripService, default));
endpoints.MapPost("/ledcontrol/setLength", async (context) => await LedControlMessageHandler.HandleLedStripMessageAsync<SetLedStripLengthMessage>(context, ledStripService, default));

GET / gibt die Nachricht "LED Web Control is running..." aus.

POST /ledcontrol/setlighting - Dieser Befehl dient dazu, den LED-Streifen anzusteuern und Farben für Segmente festzulegen.

POST /ledcontrol/reset - Mit diesem Befehl wird der LED-Streifen zurückgesetzt und laufende Aktionen gestoppt.

POST /ledcontrol/action - Über diesen Befehl können Aktionen wie Rainbow oder Knight Rider ausgeführt werden.

POST /ledcontrol/setLength - Mit diesem Befehl wird die Länge des LED-Streifens definiert.

Eine statische Klasse namens LedControlMessageHandler übernimmt die Aufgabe, HTTP-Anfragen zu verarbeiten, den Nachrichteninhalt zu lesen und zu parsen, und dann die Methode HandleLedStripMessage des LEDStripService aufzurufen.

Der LEDStripService fungiert als Bindeglied und setzt die HTTP-Anfragen in Steuerbefehle für den LED-Streifen um, indem die Methode SetPixels aufgerufen wird. Dabei werden Farben, Startindex und Länge des LED-Streifens festgelegt, um die entsprechenden Segmente in der gewählten Farbe leuchten zu lassen.

private void SetPixels(Color color, int startLEDIndex, int length)
{
    Console.WriteLine($"SetPixels: Start LED Index: {startLEDIndex} - Length: {length} - Color: {color}");

    var bitmapImage = _ledDevice.Image;

    for (int i = startLEDIndex; i < startLEDIndex + length; i++)
    {
        bitmapImage.SetPixel(i, 0, color);
    }

    _ledDevice.Update();
}

Erster Test

Nun ist es an der Zeit, die Softwarelösung lokal auf deinem PC zu starten und eine erste HTTP-Anfrage zu senden.

Web Request Beispiel für LED Steuerung
Web Request Beispiel für LED Steuerung
Leuchtender LED Streifen
Leuchtender LED Streifen

Deployment von RaspberryPi.Web.LEDControl auf den Raspberry Pi

Selbstverständlich kann der LED-Streifen direkt über die GPIO-Pins des Raspberry Pi gesteuert werden. In unserem Fall sind diese jedoch bereits für die Motorsteuerung des Build HAT belegt. Daher greifen wir in diesem Szenario auf das Breakout-Board FT232H zurück.

Zur Bearbeitung des Projekts werden Visual Studio 2022 und das dotnet 8 SDK benötigt.

Um das Projekt zu kompilieren, navigiert man zum Root-Verzeichnis des Projekts und führt den Befehl dotnet build --configuration Release aus.

dotnet build --configuration Release
dotnet build --configuration Release

Anschließend findet ihr das Programm im Ordner /bin/Release/net8.0

Das Verzeichnis wird nun auf euren Raspberry Pi kopiert. Hierfür habe ich das Programm WinSCP genutzt, um eine Verbindung zum Dateisystem des Raspberry Pi herzustellen. Anschließend wird der gesamte Inhalt in einen passenden Pfad auf dem Raspberry Pi kopiert. In meinem Fall lautet dieser /home/tim/dev/ledcontrol.

Dotnet Anwendung via WinSCP auf den Raspberry Pi kopieren
Dotnet Anwendung via WinSCP auf den Raspberry Pi kopieren

Für einen ersten Test kann das Programm mit dem Befehl dotnet RaspberryPi.Web.LEDControl.dll ausgeführt werden.

Anschließend wird deutlich, dass der Webdienst auf allen Adressen des Hosts auf dem Port 7574 läuft (http://0.0.0.0:7574).

Der Zugriff auf den Webdienst erfolgt nun über die Netzwerkadresse des Raspberry Pi. In meinem Fall lautet diese 192.168.2.208.

Nun kann ein erster Test durchgeführt werden. Hierfür wird Postman verwendet, um eine HTTP-Anfrage abzusenden.

Die Anfrage wird auf den Typ POST gestellt und die folgende URL verwendet: http://192.168.2.208:7573/ledcontrol/action. Als Body wird der Typ raw gesetzt und der folgende Inhalt verwendet. Anschließend auf Send klicken. Im unteren Bereich sollte der Status 200 - Ok zurückkommen und der LED-Streifen sollte nun im Knight Rider Modus sein.

{
    "LedStripAction": 1
}
&nbsp; Web Request für Lichtsteuerung
  Web Request für Lichtsteuerung

Autostart der dotnet Anwendung auf dem Raspberry Pi

Um zu vermeiden, dass die Anwendung auf dem Raspberry Pi jedes Mal von Hand gestartet werden muss, können wir einen Autostart einrichten.

Dazu erstellen wir die Service-Datei und bearbeiten ihren Inhalt entsprechend.

sudo touch /etc/systemd/system/ledcontrol.service
sudo nano /etc/systemd/system/ledcontrol.service

Hierbei müsst ihr den Startbefehl sowie das Arbeitsverzeichnis (Working Directory) anpassen.

[Unit]
Description=Web Ledcontrol running on a Raspberry Pi

[Service]
ExecStart=/home/tim/.dotnet/dotnet RaspberryPi.Web.LEDControl.dll
WorkingDirectory=/home/tim/dev/ledcontrol/
User=tim

[Install]
WantedBy=multi-user.target

Anschließend wird der Service aktiviert und gestartet

sudo systemctl enable ledcontrol.service
sudo systemctl start ledcontrol.service

Um sicherzustellen, dass alles geklappt hat, führt ihr den Befehl sudo systemctl status ledcontrol.service aus. Das Ergebnis sollte dem vorherigen Testmodus ähneln.

Fazit

Die Steuerung eines LED-Streifens mit dem Raspberry Pi ist im Grunde genommen nicht besonders kompliziert, erfordert jedoch die Auseinandersetzung mit verschiedenen Themen, wie beispielsweise die Kommunikation mit den Geräten über SPI oder I²C.

Eine alternative Lösung bietet sich an, wenn kein Raspberry Pi verwendet wird. Hier kann ein beliebiges System mit einem USB-Anschluss zur Steuerung eingesetzt werden. Dies wird durch das Breakout-Board FT232H ermöglicht, das eine Abstraktion ermöglicht und somit Flexibilität bietet, da diese die benötigten GPIO's  des Raspberry Pi bereitstellen.

Links

Video Knight Rider Licht

Video Rainbow Licht

Posted on 12.01.2024 05:00