Was fertig ist
Der komplette Quellcode liegt auf GitHub: github.com/ichrocke/arduino-mariokart (Firmware, Mac-Programm, Notizen, diese Seite). Hier die Übersicht, damit klar ist, was einen erwartet. Man braucht: einen ESP32 mit Bluetooth Classic (WROVER oder WROOM, ein paar Euro), ein USB-Kabel, einen Mac oder PC mit Python, eine Switch mit Mario Kart 8 Deluxe und für die KI-Teile eine HDMI-Capture-Karte (UVC-Stick mit MS2109-Chip, etwa 15 Euro; sie sitzt zwischen Dock und Fernseher) sowie ein Gamepad am Rechner für die Trainingsfahrten.
Das GitHub-Repository ist im Moment noch privat. Ich räume Code und Notizen noch auf, bevor ich es freigebe; das dauert noch etwas. Die Links auf dieser Seite führen bis dahin ins Leere. Sobald es offen ist, steht es hier.
Firmware für den ESP32
Basiert auf JereDev-Source/esp32-switch-controller (GPL-3.0). Eigene Ergänzungen: Auto-Reconnect zur gespeicherten Konsole, Befehle reconnect und unpair, kompakte Antworten mit Latenzwert, schnellere Abfrage der seriellen Schnittstelle. Gebaut wird mit PlatformIO und ESP-IDF 5.5.
platformio.ini– Board, Umgebungwrover, 16 MB Flashsdkconfig.wrover– Bluetooth-Konfiguration: nur Controller, kein Bluedroidbtstack_hid.c/btstack_hid.h– Bluetooth-Teil: Pro-Controller-Profil, Reconnect, Report-Taktswitch_proto.c– das Frage-Antwort-Spiel mit der Switch (Subcommands)pc_control.c– JSON-Protokoll zum Mac, Watchdogmain.c,CMakeLists.txt– Einstieg und Build- BTstack als Komponente (mitgeliefert, inklusive micro-ecc)
pio run -e wrover -t upload
Steuerzentrale am Mac (Python)
gui.py– die GUI mit drei Tabs: Controller, Capture (Vorschau, Latenz, Aufnahme) und KI (fahren lassen, Shadow-Modus)action.py– das Aktionsformat (siehe unten), gemeinsam für Tastatur, Gamepad und KIlink_json.py– Adapter zum JSON-Protokoll der Firmware, 50 Zustände pro Sekunde, Latenzstatistiklink.py,protocol.py– Port-Suche, Reset, altes Binärprotokolllatency_test.py– Messung Mac → ESP32 → Funkpaketdevice.py,latency.py,recorder.py– Capture-Karte, Ende-zu-Ende-Latenz, Aufnahme (JPEG 160×90 mit Aktionen, 30 Hz)dataset.py,model.py,train.py– Trainingsdaten zuschneiden und stapeln, das Netz (KartNet), das Trainingpolicy.py– der Echtzeit-Fahrer: Bild rein, Aktion raus, 15-mal pro Sekundeenv.py– die Schnittstelle, hinter der die KI Bild und Eingabe siehtrequirements.txt– pyserial, pygame-ce, opencv-python, numpy, torchController starten.command– Doppelklick-Starter für macOS
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python gui.py
Erstes Koppeln
- ESP32 per USB an den Mac, GUI starten, warten bis der Chip „Seriell“ grün ist.
- Switch 2: Home → Controller → Griff/Reihenfolge ändern.
- Nach wenigen Sekunden erscheint „Pro Controller“. Fenster anklicken, Leertaste ist A.
- Ab jetzt verbindet sich die Firmware nach jedem Neustart von selbst wieder.
Die KI fahren lassen
- Capture-Karte zwischen Dock und Fernseher, Webcam abziehen. Im Capture-Tab „Geräte suchen“, dann „Capture“ (F4).
- Zeitfahren starten, Aufnahme an (F6) und selbst fahren. 20 Minuten reichen für ein erstes Modell.
- Training starten:
python -m train.train --shift 2 --val none, etwa vier Minuten auf einem Apple-Silicon-Mac. - Im KI-Tab „Modell laden“, Rennen starten, F7. Die KI lenkt und driftet, A hält sie selbst. Greift man am Gamepad ein, fährt man sofort selbst; loslassen, und sie übernimmt wieder.
- Läuft dabei die Aufnahme, zählen nur die eigenen Eingriffe als Lernziel. Nachtrainieren, Modell laden, wiederholen.
Das Protokoll zwischen Mac und ESP32
JSON-Zeilen über die serielle Schnittstelle mit 115 200 Baud. Der Mac schickt den vollständigen Zustand, die Firmware antwortet kurz:
Mac → ESP32: {"id":412,"cmd":"state","r":8,"s":0,"l":0,"lx":2048,"ly":2048,"rx":2048,"ry":2048}
ESP32 → Mac: @PC {"id":412,"ok":true,"connected":true,"lag":11}
r, s und l sind die drei Tastenbytes wie im echten Controller-Report (hier: A gedrückt). Sticks haben 12 Bit, 2048 ist die Mitte. Kommt 500 ms kein Zustand, lässt die Firmware alle Tasten los.
Aktionsformat
@dataclass
class Action:
steer: float # -1.0 links … +1.0 rechts (linker Stick X)
ly: float # linker Stick Y
rx: float # rechter Stick X
ry: float # rechter Stick Y
accel: bool # A
brake: bool # B
drift: bool # R
item: bool # L
buttons: Button # weitere Tasten als Bitmaske
hat: Hat # Steuerkreuz
Dieses Format ist die Schnittstelle zwischen allem, was fährt (Tastatur, Gamepad, KI) und allem, was sendet (Firmware). Die KI muss später nur eine Action pro Bild liefern.
Die Firmware steht unter GPL-3.0 (Urheber JereDev-Source, Anpassungen aus diesem Projekt), der Python-Teil wird mit dem ZIP ebenfalls quelloffen. Nintendo, Switch, Mario Kart und Pro Controller sind Marken von Nintendo. Dieses Projekt ist ein privates Hobby ohne Verbindung zu Nintendo.