Arquitectura: kernels y flujo de datos

Cómo un flujo CRSF se convierte en aleteo y cola: límites de los módulos, los dos kernels de mezcla y la máquina de estados que mantiene vivo al pterosaurio cuando el enlace muere.

Flujo de señal

PteronautOS es un fork de ExpressLRS 4.x que sustituyó la cola de «paso directo PWM» del receptor por una capa dedicada de control de vuelo. La ruta de datos es deliberadamente corta:

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

Cuatro ideas estructurales mantienen a la bestia estable y el código pequeño:

  1. Los canales se normalizan pronto. Cada valor crudo de la ventana CRSF 172–1811 se mapea una vez a −1…+1 (_crsfToNorm) o a un porcentaje, y sólo esa unidad fluye por los mezcladores — sin constantes mágicas repetidas.
  2. Las salidas se etiquetan, no se fijan. Los mezcladores escriben en _f[ServoFunc]. Qué salida PWM física comanda cada etiqueta lo decide después el funcMap del perfil — véase la Referencia de Mezcladores .Reasignar un modelo nunca toca la matemática del mezclador.
  3. El kernel es una familia en tiempo de compilación y una elección en tiempo de ejecución. Tanto el aleteo por forma de onda como el controlador de caja de engranajes viven en el binario; el perfil activo elige el kernel en cada tick.
  4. El failsafe no es un evento, es un estado. Enlace caído, modo banco y anulación de stick son puertas explícitas en update(), de modo que los servos jamás se desbocan con la radio en silencio.

Dos kernels: onda y caja reductora

Un kernel es el bloque que convierte canales normalizados en µs de función de servo. PteronautOS tiene dos familias, distinguidas por el número de perfil del mezclador:

Familia Perfiles Actuadores Arquetipo de modelo
Kernel de forma de onda (servo) 0 SERVO_2WING · 1 SERVO_2WING_1RUD · 2 SERVO_4WING Servos de ala batiente (2–4), timón de cresta Ornitóptero de servo de accionamiento directo — el PteronautOS clásico
Kernel de caja de engranajes 3 GEARBOX_2VTAIL_1RUD · 4 GEARBOX_1MOT_2VTAIL · 5 GEARBOX_1MOT_2VTAIL_1RUD · 6 GEARBOX_1ELE_1RUD · 7 GEARBOX_1MOT_1ELE_1RUD Motor ESC, cola en V o elevador + timón Aleteador engranado / motorizado con superficies de cola convencionales

La selección ocurre en update() con la única prueba PROFILE_IS_GEARBOX (activeProfile ≥ 3). El perfil en sí es un valor de ejecución: arranca de la bandera de compilación MIXER_PROFILE (el legado ORNITHOPTER_GEARBOX=1 aún mapea al perfil 5) pero puede cambiarse en vivo desde la WebUI vía setOrnithopterProfile() — el firmware reorienta una nueva aeronave sin reflash. Hay ocho perfiles en total; sus disposiciones exactas de funcMap están tabuladas en la Referencia de Mezcladores.

Kernel de onda (aleteo por servos)

El kernel de forma de onda es lo que la mayoría entiende por «PteronautOS»: dos servos de ala ejecutan una oscilación de fase continua cuya forma se esculpe cada ciclo. Su anatomía:

Kernel de caja reductora (motor + colas)

El kernel de caja de engranajes cambia el aleteo puro por un tren motorizado más superficies de cola convencionales. Como un motor gira continuamente, este kernel es sin estado por tick — sin oscilador — y en su lugar:

Un mismo ornitóptero puede incluso llevar ambas personalidades: lanzamiento aleteando con el kernel de forma de onda, crucero con la caja de engranajes — el cambio de perfil en ejecución es esa única línea en update().

Estados: enlace, banco y failsafe

update() se llama con una cadencia fija de ~10 ms desde el bucle WiFi/servo y verifica tres banderas antes de ejecutar ningún mezclador:

Estado Condición Comportamiento
Vuelo normal linkUp + canal armado activo La salida completa del kernel sigue a los sticks
Modo banco / panel benchMode (panel WebUI, sin enlace RC) Se inyectan sticks neutros, el acelerador se aparca bajo el umbral de aleteo — los ajustes de planeo + trim son visibles en vivo
Anulación de stick stickOverride (canales virtuales) Los valores de canal inyectados por el firmware sustituyen al CRSF por completo (barridos de servo, pruebas)
Failsafe enlace perdido (onLinkDown / enterFailsafe) Todas las funciones centran a 1500 µs, oscilador reiniciado, motor → mín.; la pérdida de paquetes CRSF también centra a nivel de RX

El comportamiento de centrar ante pérdida se duplica a propósito en dos capas: la pila CRSF aplica failsafe a los datos de canal, y la capa Ornithopter aplica failsafe a la geometría (incluido el estado de oscilación). Un radio muerto deja así una aeronave planeadora y controlable — nunca una aleteando a lo loco.

Mapa del código fuente

Módulo Ruta Responsabilidad
Capa Ornithopter src/lib/Ornithopter/ Selección de kernel, matemática del mezclador, oscilador de forma de onda, perfiles, trim
Perfiles de vuelo y constantes src/lib/Ornithopter/OrnithopterConfig.h Enum MixerProfile, etiquetas ServoFunc, funcMap, todos los valores numéricos por defecto
Oscilador / forma src/lib/Ornithopter/OrnithopterWaveform.h Integración de fase, modelado de ferocidad, lógica de reversión
Zephyrus (opcional) src/lib/Zephyrus/ MPU6050 + Mahony AHRS, PID dual, corrección de cresta/cola
Etapa de salida PWM src/lib/ServoOutput/devServoOutput.cpp Escribe µs sincronizados con el tick CRSF
Configuración WebUI src/lib/WIFI/devWIFI.cpp Perfil en ejecución + persistencia de ajuste (/pteronautos)

La capa inferior — exactamente qué forma de onda producen los números y cómo cada perfil conecta funciones a salidas PWM — vive en la Referencia de Mezcladores , y la envolvente de temporización del servo se documenta en el artículo Servo Kernel artículo.