Arquitetura: kernels e fluxo de dados

Como um fluxo CRSF se torna batimento de asa e cauda: fronteiras dos módulos, os dois kernels de mistura e a máquina de estados que mantém o pterossauro vivo quando o link morre.

Fluxo de sinal

O PteronautOS é um fork do ExpressLRS 4.x que substituiu a ponta de "passagem PWM" do receptor por uma camada dedicada de controlo de voo. O caminho dos dados é deliberadamente curto:

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

Quatro ideias estruturais mantêm a besta estável e o código pequeno:

  1. Os canais são normalizados cedo. Cada valor bruto na janela CRSF 172–1811 é mapeado para −1…+1 (_crsfToNorm) ou para uma percentagem uma única vez, e só essa unidade flui pelos mixers — sem constantes mágicas repetidas.
  2. As saídas são etiquetadas, não fixadas. Os mixers escrevem em _f[ServoFunc]. Qual saída PWM física uma etiqueta comanda é decidido depois pelo funcMap do perfil — veja a Referência de Mixers .Re-fixar um modelo nunca toca na matemática do mixer.
  3. O kernel é uma família em tempo de compilação, uma escolha em tempo de execução. Tanto o batente de forma de onda como o controlador de caixa de velocidades vivem no binário; o perfil ativo escolhe o kernel a cada tick de atualização.
  4. O failsafe não é um evento, é um estado. Ligação perdida, modo de bancada e sobreposição de stick são portas explícitas em update(), para que os servos nunca fujam enquanto o rádio está em silêncio.

Dois kernels: onda e caixa de velocidades

Um kernel é o bloco que transforma canais normalizados em µs de função de servo. O PteronautOS tem duas famílias, discriminadas pelo número do perfil de mixer:

Família Perfis Atuadores Arquétipo de modelo
Kernel de forma de onda (servo) 0 SERVO_2WING · 1 SERVO_2WING_1RUD · 2 SERVO_4WING Servos de asa batente (2–4), leme de crista Ornitóptero de servo por acionamento direto — o PteronautOS clássico
Kernel de caixa de velocidades 3 GEARBOX_2VTAIL_1RUD · 4 GEARBOX_1MOT_2VTAIL · 5 GEARBOX_1MOT_2VTAIL_1RUD · 6 GEARBOX_1ELE_1RUD · 7 GEARBOX_1MOT_1ELE_1RUD Motor ESC, cauda em V ou profundor + leme Batente engrenado / motorizado com superfícies de cauda convencionais

A seleção acontece em update() com o teste único PROFILE_IS_GEARBOX (activeProfile ≥ 3). O perfil em si é um valor de execução: começa na flag de build MIXER_PROFILE (a legada ORNITHOPTER_GEARBOX=1 ainda mapeia para o perfil 5), mas pode ser trocado ao vivo pela WebUI via setOrnithopterProfile() — o firmware re-mira uma nova aeronave sem re-flash. Há oito perfis no total; os seus layouts exatos de funcMap estão tabelados na Referência de Mixers.

Kernel de onda (flapper por servos)

O kernel de forma de onda é o que a maioria entende por "PteronautOS": dois servos de asa executam uma oscilação de fase contínua cuja forma é esculpida a cada ciclo. A sua anatomia:

Kernel de caixa de velocidades (motor + caudas)

O kernel de caixa de velocidades troca o batimento puro por um trem motorizado mais superfícies de cauda convencionais. Como um motor gira continuamente, este kernel é sem estado por tick — sem oscilador — e em vez disso:

Um mesmo ornitóptero pode até carregar as duas personalidades: lançamento batente com o kernel de forma de onda, cruzeiro na caixa de velocidades — a troca de perfil em execução é aquela única linha em update().

Estados: link, bancada e failsafe

update() é chamado numa cadência fixa de ~10 ms a partir do loop WiFi/servo e passa por três flags antes de qualquer mixer executar:

Estado Condição Comportamento
Voo normal linkUp + canal armado ativo Saída completa do kernel segue os sticks
Modo bancada / painel benchMode (painel WebUI, sem ligação RC) Sticks neutros são injetados, acelerador estacionado abaixo do limiar de batimento — edições de planagem + trim são visíveis ao vivo
Sobreposição de stick stickOverride (canais virtuais) Valores de canal injetados pelo firmware substituem o CRSF por completo (varreduras de servo, testes)
Failsafe ligação perdida (onLinkDown / enterFailsafe) Todas as funções centram em 1500 µs, oscilador reiniciado, motor → mín.; a perda de pacotes CRSF também centra ao nível do RX

O comportamento de centrar na perda é duplicado em duas camadas de propósito: a pilha CRSF faz failsafe dos dados de canal, e a camada Ornithopter faz failsafe da geometria (incluindo o estado de oscilação). Um rádio morto deixa assim uma aeronave planante e controlável — nunca uma aos solavancos.

Mapa do código-fonte

Módulo Caminho Responsabilidade
Camada Ornithopter src/lib/Ornithopter/ Seleção de kernel, matemática do mixer, oscilador de forma de onda, perfis, trim
Perfis de voo e constantes src/lib/Ornithopter/OrnithopterConfig.h Enum MixerProfile, etiquetas ServoFunc, funcMap, todos os padrões numéricos
Oscilador / forma src/lib/Ornithopter/OrnithopterWaveform.h Integração de fase, moldagem de ferocidade, lógica de reversão
Zephyrus (opcional) src/lib/Zephyrus/ MPU6050 + Mahony AHRS, PID duplo, correção de crista/cauda
Estágio de saída PWM src/lib/ServoOutput/devServoOutput.cpp Escreve µs sincronizados ao tick CRSF
Configuração WebUI src/lib/WIFI/devWIFI.cpp Persistência de perfil em execução + afinação (/pteronautos)

A camada seguinte — exatamente que forma de onda os números produzem, e como cada perfil liga funções às saídas PWM — vive na Referência de Mixers , e o envelope de temporização de servo está documentado no artigo Servo Kernel artigo.