Hugo3 ist die neueste Evolution meiner Rover-Serie. Es handelt sich um ein Kettenfahrzeug, das auf einem AliExpress-Chassis basiert und von einem Raspberry Pi 5 (8GB) angetrieben wird. Ein besonderes Merkmal ist die Stromversorgung: Durch die Verwendung eines Standard-Einhell-Akkus lässt sich die Energieversorgung unkompliziert handhaben.
Der Rover ist zweckmäßig ausgestattet: Ein integrierter Servo-Controller steuert die Mechanik, während zwei Kameras (vorne und hinten) für Übersicht sorgen. Beide Kameras sind auf Gimbals montiert und lassen sich nach links und rechts schwenken (Pan). Gesteuert wird das System über eine native Swift Universal App, die auf macOS, iOS und tvOS läuft.
System-Architektur
Das System ist als verteilte Architektur konzipiert. Ein zentraler MQTT-Broker fungiert als Nervensystem, über das alle Befehle und Videodaten fließen.
+---------------------------------------+
| HUGO3 ROVER (Raspberry Pi 5) |
| [Dual Cams] --> [H.264 Encoder] |
| | |
| [I2C Drivers] < [Kotlin Client] |
+----------------------^-------|--------+
| |
Control Commands| | Video & Telemetry
| |
+----------------------|-------v--------+
| INFRASTRUCTURE |
| [Mosquitto MQTT Broker] |
+----------------------^-------|--------+
| |
Control Commands| | Video & Telemetry
| |
+----------------------|-------v--------+
| CONTROLLER (Apple) |
| [Input] --> [Swift App] |
| | |
| [VideoToolbox Decoder] |
+---------------------------------------+
Das MQTT-Protokoll
Hugo3 nutzt ein striktes JSON-Protokoll für die Steuerung und Telemetrie sowie Binär-Payloads für Video. Die Kommunikation erfolgt über folgende Topics:
1. Steuerung (hugo/control)
Richtung: Controller → Rover Wird alle 80ms gesendet, um Motoren und Servos zu steuern.
{
"leftDrive": 50.0,
"rightDrive": 50.0,
"cameraFront": 10.0,
"cameraBack": -5.0,
"light": true
}
2. Heartbeat (hugo/controllerheartbeat)
Richtung: Controller → Rover Ein leeres Objekt, das jede Sekunde gesendet wird. Bleibt es für mehr als 2 Sekunden aus, stoppt der Rover sicherheitshalber alle Motoren.
{}
3. Kontroll-Status (hugo/controlstate)
Richtung: Rover → Controller Der Rover meldet den tatsächlichen Status der Aktoren zurück, sobald sich Werte ändern.
{
"leftDrive": 50.0,
"rightDrive": 50.0,
"cameraFront": 10.0,
"cameraBack": -5.0,
"light": true
}
4. Telemetrie (hugo/systemstate)
Richtung: Rover → Controller Wird alle 2 Sekunden gesendet, um die Systemgesundheit zu überwachen.
{
"linkQuality": 58,
"signalLevel": -42,
"cpuTemp": 45.5
}
5. Video-Stream (hugo/video & hugo/videoBack)
Richtung: Rover → Controller
Binäre Rohdaten (H.264 NALUs). Pakete mit SPS/PPS/IDR-Informationen werden als retained markiert.
Payload: [00 00 00 01 67 42 ...] (Binärdaten)
Video-Pipeline: NALU-over-MQTT
Um die geringstmögliche Latenz zu erreichen, umgehen wir klassische Containerformate. Der Rover liest den H.264-Stream direkt aus dem Encoder und splittet ihn an den Start-Codes (00 00 01).
- SPS/PPS Retention: Die Konfigurationspakete (SPS/PPS) werden als
retainedNachrichten am Broker gespeichert. So kann ein Client jederzeit in den Stream einsteigen und sofort mit dem Dekodieren beginnen. - AVCC Konvertierung: Da Apples VideoToolbox NALUs im AVCC-Format (Längen-Präfix statt Start-Codes) erwartet, konvertiert der Swift-Controller die Pakete on-the-fly.
[!IMPORTANT] Kühlung: Der Raspberry Pi 5 erreicht beim Encoding von zwei parallelen 1080p-Streams schnell über 80°C. Ein Active Cooler ist daher zwingend erforderlich.
Hardware & Bill of Materials (BOM)
| Komponente | Beschreibung |
|---|---|
| Recheneinheit | Raspberry Pi 5 (8GB) |
| Motor-Treiber | Waveshare uHAT (I2C Adr: 0x40) |
| Servo-Treiber | Waveshare HAT (I2C Adr: 0x41) |
| Kameras | 2x Raspberry Pi Camera Module 2 (NoIR) |
| Stromversorgung | 5A Step-Down Regler (für 2S/3S LiPo) |
Anschlussbelegung der Motoren
Steuerung
Dank der Integration des Apple GameController-Frameworks fühlt sich die Steuerung fast wie ein Videospiel an. Neben den Joysticks für Fahrt und Kamera können über die Schultertasten konstante Geschwindigkeiten für präzise Manöver festgelegt werden.
Controller-Mapping für die Swift-App
