.NET Motorsteuerung mit dem Raspberry PI 3 und Build HAT

by
.NET Motorsteuerung mit dem Raspberry PI 3 und Build HAT

Einleitende Worte

In diesem Blogpost wird gezeigt, wie man mithilfe eines Raspberry Pi in Verbindung mit dem Erweiterungsmodul Build HAT einen Lego-Motor steuern kann. Der Build HAT ist ein Add-on-Board für den Raspberry Pi, das den 40-Pin-GPIO-Header verwendet und es ermöglicht, dort angeschlossene Motoren zu steuern. Die Steuerung erfolgt über das Netzwerk, wobei eine .NET-Anwendung auf dem Raspberry Pi ausgeführt wird, die Webanfragen entgegennimmt und sie in Steuerbefehle umsetzt.

Vorbereitung

Zuerst wird der Raspberry Pi vorbereitet. In diesem Beispiel wird ein Raspberry Pi Modell 3 B verwendet. Zur Installation des Betriebssystems wird der Raspberry Pi Imager genutzt, und das Raspberry Pi OS ausgewählt.

Tipp: Nutzt den Konfigurator, um direkt den SSH-Dienst zu aktivieren und euer WLAN zu konfigurieren. Dadurch kann der Raspberry Pi ohne zusätzlichen Konfigurationsaufwand direkt headless starten.

Anschließend wird der Build HAT montiert. Zunächst werden die mitgelieferten Abstandshalter am Raspberry Pi angebracht, und dann wird der Build HAT aufgesteckt. Dieser wird anschließend mit Schrauben fixiert. Danach wird das Board an die externe Spannungsversorgung angeschlossen. Diese versorgt auch den Raspberry Pi mit Strom, sofern ein geeignetes Netzteil verwendet wird. Ich habe das empfohlene Netzteil gleich mitbestellt. Es liefert eine Ausgangsleistung von 8.0V Gleichstrom, 6.0 A und 48.0 Watt.

Nun kann der Motor angeschlossen werden. Dafür kann einfach ein freier Port des Build HAT verwendet werden. In meinem Beispiel habe ich den Port A genutzt.

Bildstrecke:

Raspberry Pi 3, Build HAT inklusive Befestigungsmaterial
Raspberry Pi 3, Build HAT inklusive Befestigungsmaterial
Montierter Build HAT mit angeschlossener Stromversorgung
Montierter Build HAT mit angeschlossener Stromversorgung
Motor an Build HAT Port A angeschlossen
Motor an Build HAT Port A angeschlossen

Konfiguration Raspberry Pi

Um die Verbindung herzustellen, öffnen wir zunächst eine SSH-Verbindung zum Raspberry Pi.

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 "I6 Serial Port".

Dann werden wir gefragt: "Would you like a login shell to be accessible over serial?". Hier wählen wir No.

Anschließend folgt die Frage: "Would you like the serial port hardware to be enabled?". Dort wählen wir Yes.

Zum Schluss werden die Einstellungen noch einmal angezeigt und wir müssen den Raspberry Pi neu starten. Diese Einstellungen sind wichtig, da der Raspberry Pi über den seriellen Port auf den Build HAT zugreift und mit diesem kommuniziert.

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
.NET Runtime auf Raspberry Pi installieren
.NET Runtime auf Raspberry Pi installieren

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.

Einführung in die .NET Softwarelösung

Um den Build HAT über HTTP-Anfragen steuern zu können, ist ein Webhost erforderlich. Dies wird erreicht, indem das Projekt in der Program.cs einen solchen Webhost konfiguriert. Ein weiterer Vorteil dieser Lösung ist die Verwendung von Dependency Injection, um weitere Services zu registrieren, wie dies hier für den MotorControlService umgesetzt ist. Dadurch bleibt die Program.cs übersichtlich, insbesondere wenn das Projekt an Komplexität zunimmt.

using RaspberryPi.BuildHat.Web.MotorControl;
using RaspberryPi.BuildHat.Web.MotorControl.Models.Settings;
using RaspberryPi.BuildHat.Web.MotorControl.Services;

await Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
        var settingsService = new SettingsService();
        MotorControlSettings motorControlSettings = settingsService.GetMotorControlSettings();
        HostingSettings hostingSettings = settingsService.GetHostingSettings();

        webBuilder.UseStartup<Startup>();
        webBuilder.UseUrls([$"http://0.0.0.0:{hostingSettings.Port}"]);
        webBuilder.ConfigureServices(services =>
        {
            services.AddSingleton(x => new MotorControlService(motorControlSettings.BuildHatPort, motorControlSettings.MotorPort));
        });
    })
    .Build()
    .RunAsync();

Die Routen können in der Datei Startup.cs konfiguriert werden, aktuell sind drei Routen definiert:

endpoints.MapGet("/", () => "MotorControl is running...");
endpoints.MapPost("/motorcontrol/speed", (context) => MotorControlMessageHandler.HandleMotorControlMessage<SetMotorSpeedControlMessage>(context, motorControlService));
endpoints.MapPost("/motorcontrol/runseconds", (context) => MotorControlMessageHandler.HandleMotorControlMessage<SetMotorSpeedForSecondsControlMessage>(context, motorControlService));

GET / gibt die Nachricht "MotorControl is running..." aus.

POST /motorcontrol/speed - Befehl, um den Motor mit einer bestimmten Drehzahl laufen zu lassen.

POST /motorcontrol/runseconds - Befehl, um den Motor mit einer bestimmten Drehzahl für X Sekunden laufen zu lassen.

Es gibt eine statische Klasse namens MotorControlMessageHandler. Ihre Aufgabe besteht darin, HTTP-Anfragen entgegenzunehmen, den Nachrichteninhalt auszulesen und zu parsen, und anschließend einen Aufruf an den MotorControlService zu starten, indem die Methode HandleMotorControlMessage aufgerufen wird.

Der MotorControlService ist das Bindeglied, das die HTTP-Nachrichten in Bewegung umsetzt, indem die Methoden SetMotorSpeed oder RunMotorForSeconds, je nach Nachrichtentyp, aufgerufen werden.

Diese Methoden setzen dann die entsprechenden Steuerbefehle an den Build HAT ab, und der Motor dreht sich entsprechend der eingestellten Geschwindigkeit.

_buildHat.SendRawCommand($"port {(byte)_motorPort} ; plimit 1\r");
_buildHat.SendRawCommand($"port {(byte)_motorPort} ; bias 0.1\r");
_buildHat.SendRawCommand($"port {(byte)_motorPort} ; pwm ; set {(speed / 100.0).ToString(CultureInfo.InvariantCulture)}\r");

Das vollständige Codebeispiel findet ihr auf GitHub

Deployment von RaspberryPi.BuildHat.Web.MotorControl

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.

Kopiert nun dieses Verzeichnis auf euren Raspberry Pi. Dazu könnt ihr ein Programm wie WinSCP verwenden, um eine Verbindung mit dem Dateisystem des Raspberry Pi herzustellen. Anschließend kopiert ihr den gesamten Inhalt in einen geeigneten Pfad auf dem Raspberry Pi. In meinem Fall ist das /home/tim/dev/motorcontrol.

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

Für einen ersten Test könnt ihr das Programm mit dem Befehl dotnet RaspberryPi.BuildHat.Web.MotorControl.dll ausführen:

Erster Test auf dem Raspberry Pi mit dotnet run
Erster Test auf dem Raspberry Pi mit dotnet run

Nachdem der Build HAT mit der Nachricht "Signature received" geantwortet hat, sollte die Status-LED auf Grün springen. Anschließend könnt ihr feststellen, dass der Webdienst auf allen Adressen des Hosts auf dem Port 7573 läuft (http://0.0.0.0:7573).

Um auf den Webdienst zuzugreifen, verwendet ihr die Netzwerkadresse des Raspberry Pi. In meinem Fall ist das 192.168.2.208.

Nun könnt ihr einen ersten Test durchführen. Verwendet dazu Postman, um eine HTTP-Anfrage abzuschicken.

Stellt die Anfrage auf den Typ POST und verwendet die folgende URL: http://192.168.2.208:7573/motorcontrol/speed. Als Body setzt den Typ auf raw und verwendet folgenden Inhalt. Klickt anschließend auf Send. Im unteren Bereich sollte der Status 200 - Ok zurückkommen, und der Motor sollte sich zu drehen beginnen.

{
    "MotorSpeed": 50
}
Web Request für Motorsteuerung
Web Request für Motorsteuerung

Um den Motor zu stoppen, sendet ihr einfach erneut den gleichen Befehl und setzt MotorSpeed auf 0.

Für die zweite Funktion verwendet ihr eine POST-Anfrage an die URL http://192.168.2.208:7573/motorcontrol/runseconds mit folgendem Body:

{
    "MotorSpeed": 50,
    "Seconds": 15
}

Der Motor dreht dann mit der Geschwindigkeit von 50 % für 15 Sekunden und stoppt danach.

Autostart der dotnet Anwendung auf dem Raspberry Pi

Um die Anwendung auf dem Raspberry Pi nicht jedes Mal manuell starten zu müssen, können wir einen Autostart einrichten.

Dazu erstellen wir eine Service-Datei und bearbeiten deren Inhalt entsprechend.

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

Hier müssen der Startbefehl und das Arbeitsverzeichnis (Working Directory) angepasst werden.

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

[Service]
ExecStart=/home/tim/.dotnet/dotnet RaspberryPi.BuildHat.Web.MotorControl.dll
WorkingDirectory=/home/tim/dev/motorcontrol/
User=tim

[Install]
WantedBy=multi-user.target

Anschließend wird der Service aktiviert und gestartet

sudo systemctl enable motorcontrol.service
sudo systemctl start motorcontrol.service

Um sicherzugehen, dass alles geklappt hat, könnt ihr den Befehl sudo systemctl status motorcontrol.service ausführen. Das Ergebnis sollte dem im Testmodus ähneln.

Status motorcontrol.service
Status motorcontrol.service

Fazit

Das Steuern eines Motors mit dem Raspberry Pi ist grundsätzlich nicht schwer, erfordert jedoch Kenntnisse in verschiedenen Bereichen wie Hardware, Software, Serial Port und Linux. Dieser Blogpost bietet einen hervorragenden Einstiegspunkt, um eigene Projekte voranzutreiben und sich mit diesen Themen vertraut zu machen.

Links

Posted on 22.12.2023 05:00