Architektur: Kernel & Datenfluss

Wie ein CRSF-Datenstrom zu Flügelschlag und Leitwerk wird: Modulgrenzen, die zwei Misch-Kernel und die Zustandsmaschine, die den Pterosaurier am Leben hält, wenn der Link stirbt.

Signalpfad

PteronautOS ist ein ExpressLRS-4.x-Fork, der den „PWM-Durchreichen“-Schwanz des Empfängers durch eine eigene Flugsteuer-Schicht ersetzt hat. Der Datenweg ist bewusst kurz:

CRSF radio link
  │  2.4 GHz SX1280
  ▼
rx_main / CRSF decoder        → ChannelData[]  (raw 172…1811 µs-window values)
  ▼
Ornithopter::update()          → _readChannels() → voice* fields
  ▼  kernel select: activeProfile ≥ GEARBOX_2VTAIL_1RUD ?
_computeServoMixer()   OR   _computeGearboxMixer()
  ▼
_f[]  (indexed by ServoFunc tag, µs)
  ▼
PWM output stage               → funcMap channels → wing / rudder / motor servos

Vier strukturelle Ideen halten das Biest stabil und den Code klein:

  1. Kanäle werden früh normalisiert. Jeder Rohwert im CRSF-Fenster 172–1811 wird einmal auf −1…+1 (_crsfToNorm) oder auf einen Prozentwert abgebildet, und nur diese Einheit fließt durch die Mixer — keine wiederholten magischen Konstanten.
  2. Ausgänge werden getaggt, nicht verdrahtet. Die Mixer schreiben in _f[ServoFunc]. Welchen physischen PWM-Ausgang ein Tag treibt, entscheidet später das funcMap des Profils — siehe Mixer-Referenz .Das Neu-Verdrahten eines Modells berührt nie die Mixer-Mathematik.
  3. Der Kernel ist eine Compilezeit-Familie, eine Laufzeit-Entscheidung. Sowohl der Wellenform-Flatterer als auch der Getriebe-Controller leben im Binärbild; das aktive Profil wählt den Kernel jeden Update-Tick.
  4. Failsafe ist kein Ereignis, sondern ein Zustand. Link-Verlust, Bank-Modus und Stick-Override sind explizite Gates in update(), damit Servos nie durchgehen, solange das Radio schweigt.

Zwei Kernel: Waveform & Getriebe

Ein Kernel ist der Block, der normalisierte Kanäle in Servo-Funktions-µs verwandelt. PteronautOS hat zwei Familien, unterschieden anhand der Mixer-Profilnummer:

Familie Profile Aktoren Modell-Archetyp
Wellenform-(Servo-)Kernel 0 SERVO_2WING · 1 SERVO_2WING_1RUD · 2 SERVO_4WING Schlagflügel-Servos (2–4), Kamm-Ruder Ornithopter mit Direktantrieb-Servos — das klassische PteronautOS
Getriebe-Kernel 3 GEARBOX_2VTAIL_1RUD · 4 GEARBOX_1MOT_2VTAIL · 5 GEARBOX_1MOT_2VTAIL_1RUD · 6 GEARBOX_1ELE_1RUD · 7 GEARBOX_1MOT_1ELE_1RUD Motor-ESC, V-Leitwerk oder Höhenruder + Ruder Getriebe-/motorisierter Flatterer mit konventionellem Leitwerk

Die Auswahl geschieht in update() mit dem einzigen Test PROFILE_IS_GEARBOX (activeProfile ≥ 3). Das Profil selbst ist ein Laufzeitwert: Es startet aus dem Build-Flag MIXER_PROFILE (das alte ORNITHOPTER_GEARBOX=1 mappt weiter auf Profil 5), lässt sich aber live über die WebUI per setOrnithopterProfile() umschalten — die Firmware zielt ohne Reflash auf eine neue Zelle um. Insgesamt gibt es acht Profile; ihre exakten funcMap-Layouts stehen in der Mixer-Referenz.

Waveform-Kernel (Servo-Flatterflügel)

Das Wellenform-Kernel ist, was die meisten unter „PteronautOS“ verstehen: zwei Flügel-Servos führen eine phasenkontinuierliche Oszillation aus, deren Form jeden Zyklus gemeißelt wird. Seine Anatomie:

Getriebe-Kernel (Motor + Leitwerke)

Das Getriebe-Kernel tauscht reinen Flügelschlag gegen einen motorisierten Antrieb plus konventionelles Leitwerk. Da ein Motor kontinuierlich dreht, ist dieses Kernel pro Tick zustandslos — kein Oszillator — und stattdessen:

Ein Ornithopter-Rig kann sogar beide Persönlichkeiten tragen: Flatterstart mit dem Wellenform-Kernel, Reiseflug mit dem Getriebe — der Laufzeit-Profilwechsel ist jene eine Zeile in update().

Zustände: Link, Bench & Failsafe

update() wird mit festem ~10 ms-Takt aus der WiFi/Servo-Schleife aufgerufen und prüft vor jedem Mixer drei Flags:

Zustand Bedingung Verhalten
Normalflug linkUp + Scharf-Kanal aktiv Voller Kernel-Ausgang folgt den Sticks
Bank-/Panel-Modus benchMode (WebUI-Panel, keine RC-Verbindung) Neutrale Sticks werden eingespeist, Schub unter der Flatter-Schwelle geparkt — Gleit- und Trim-Änderungen sind live sichtbar
Stick-Override stickOverride (virtuelle Kanäle) Firmware-eingespeiste Kanalwerte ersetzen CRSF vollständig (Servo-Sweeps, Tests)
Failsafe Link verloren (onLinkDown / enterFailsafe) Alle Funktionen zentrieren auf 1500 µs, Oszillator zurückgesetzt, Motor → min; CRSF-Paketverlust zentriert auch auf RX-Ebene

Das Zentrieren-bei-Verlust-Verhalten ist absichtlich in zwei Schichten dupliziert: Der CRSF-Stack sichert die Kanaldaten ab, und die Ornithopter-Schicht sichert die Geometrie ab (inklusive Oszillationszustand). Ein totes Radio hinterlässt daher eine gleitende, steuerbare Zelle — niemals eine zappelnde.

Quellcode-Karte

Modul Pfad Zuständigkeit
Ornithopter-Schicht src/lib/Ornithopter/ Kernel-Auswahl, Mixer-Mathematik, Wellenform-Oszillator, Profile, Trim
Flugprofile & Konstanten src/lib/Ornithopter/OrnithopterConfig.h MixerProfile-Enum, ServoFunc-Tags, funcMap, alle numerischen Standards
Oszillator / Form src/lib/Ornithopter/OrnithopterWaveform.h Phasenintegration, Heftigkeits-Formung, Umkehrlogik
Zephyrus (optional) src/lib/Zephyrus/ MPU6050 + Mahony-AHRS, Dual-PID, Kamm-/Leitwerk-Korrektur
PWM-Ausgangsstufe src/lib/ServoOutput/devServoOutput.cpp Schreibt µs synchron zum CRSF-Tick
WebUI-Konfiguration src/lib/WIFI/devWIFI.cpp Laufzeit-Profil + Tuning-Persistenz (/pteronautos)

Die nächsttiefere Schicht — exakt welche Wellenform die Zahlen erzeugen und wie jedes Profil Funktionen auf PWM-Ausgänge verdrahtet — lebt in der Mixer-Referenz , und die Servo-Timing-Hülle ist im Artikel Servo-Kernel dokumentiert.