Архитектура: ядра и потоки данных

Как поток CRSF превращается во взмах крыла и хвост: границы модулей, два ядра микшера и конечный автомат, который держит птерозавра в живых при потере связи.

Сигнальный тракт

PteronautOS — это форк ExpressLRS 4.x, заменивший «сквозную передачу PWM» в конце приёмника выделенным слоем управления полётом. Путь данных намеренно короткий:

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

Четыре структурные идеи держат машину стабильной, а код — компактным:

  1. Каналы нормализуются сразу. Каждое сырое значение в окне CRSF 172–1811 один раз отображается в −1…+1 (_crsfToNorm) или в проценты, и дальше через микшеры течёт только эта величина — никаких повторяющихся магических констант.
  2. Выходы помечаются тегами, а не привязываются. Микшеры пишут в _f[ServoFunc]. Каким физическим PWM-выходом управляет тег, решается позже через funcMap профиля — см. Справочник микшеров .Переназначение выводов модели никогда не трогает математику микшера.
  3. Ядро — это семейство на этапе компиляции и выбор в рантайме. И волновой махатель, и контроллер редуктора живут в бинарнике; активный профиль выбирает ядро на каждом тике обновления.
  4. Фейлсейф — это не событие, а состояние. Потеря связи, стендовый режим и переопределение стиков — явные шлюзы в update(), поэтому сервы никогда не «убегут», пока радио молчит.

Два ядра: волновое и редукторное

Ядро — это блок, превращающий нормализованные каналы в µs серво-функций. У PteronautOS две семьи, различаемые номером профиля микшера:

Семья Профили Приводы Архетип модели
Волновое (серво) ядро 0 SERVO_2WING · 1 SERVO_2WING_1RUD · 2 SERVO_4WING Сервы машущего крыла (2–4), гребневой руль Орнитоптер с прямым сервоприводом — классический PteronautOS
Редукторное ядро 3 GEARBOX_2VTAIL_1RUD · 4 GEARBOX_1MOT_2VTAIL · 5 GEARBOX_1MOT_2VTAIL_1RUD · 6 GEARBOX_1ELE_1RUD · 7 GEARBOX_1MOT_1ELE_1RUD Моторный ESC, V-хвост или руль высоты + руль Редукторный / моторизованный махатель с обычным хвостовым оперением

Выбор происходит в update() единственной проверкой PROFILE_IS_GEARBOX (activeProfile ≥ 3). Сам профиль — величина рантайма: он стартует из флага сборки MIXER_PROFILE (устаревший ORNITHOPTER_GEARBOX=1 всё ещё отображается на профиль 5), но может переключаться на лету из WebUI через setOrnithopterProfile() — прошивка перенацеливается на новый планер без перепрошивки. Всего восемь профилей; их точные раскладки funcMap сведены в Справочнике микшеров.

Волновое ядро (сервоприводный мах)

Волновое ядро — это то, что большинство понимает под «PteronautOS»: два крыльевых серво выполняют фазонепрерывное колебание, форма которого вытачивается каждый цикл. Его анатомия:

Редукторное ядро (мотор + хвосты)

Редукторное ядро меняет чистый взмах на моторизованный привод плюс обычное хвостовое оперение. Поскольку мотор вращается непрерывно, это ядро без состояния на каждый тик — без осциллятора — и вместо этого:

Один орнитоптер может даже нести обе личности: взлёт маханием на волновом ядре, крейсер на редукторе — переключение профиля в рантайме и есть та единственная строка в update().

Состояния: связь, стенд и failsafe

update() вызывается с фиксированным периодом ~10 мс из цикла WiFi/серво и перед запуском любого микшера проверяет три флага:

Состояние Условие Поведение
Нормальный полёт linkUp + канал вооружения активен Полный выход ядра следует за стиками
Стендовый / панельный режим benchMode (панель WebUI, без RC-связи) Вводятся нейтральные стики, газ удерживается ниже порога взмаха — правки планирования + трима видны вживую
Переопределение стиков stickOverride (виртуальные каналы) Значения каналов, вводимые прошивкой, полностью заменяют CRSF (прогоны серво, тесты)
Фейлсейф связь потеряна (onLinkDown / enterFailsafe) Все функции центрируются на 1500 мкс, осциллятор сброшен, мотор → мин.; потеря пакетов CRSF также центрирует на уровне RX

Поведение «центрирование при потере» намеренно продублировано в двух слоях: стек CRSF фейлсейфит данные каналов, а слой Ornithopter фейлсейфит геометрию (включая состояние осцилляции). Мёртвое радио поэтому оставляет планирующий, управляемый планер — никогда не бьющийся в конвульсиях.

Карта исходников

Модуль Путь Ответственность
Слой Ornithopter src/lib/Ornithopter/ Выбор ядра, математика микшера, волновой осциллятор, профили, трим
Полётные профили и константы src/lib/Ornithopter/OrnithopterConfig.h Перечисление MixerProfile, теги ServoFunc, funcMap, все числовые значения по умолчанию
Осциллятор / форма src/lib/Ornithopter/OrnithopterWaveform.h Интегрирование фазы, формирование свирепости, логика реверса
Zephyrus (опционально) src/lib/Zephyrus/ MPU6050 + Mahony AHRS, двойной ПИД, коррекция гребня/хвоста
Каскад PWM-выхода src/lib/ServoOutput/devServoOutput.cpp Записывает µs синхронно с тиком CRSF
Конфигурация WebUI src/lib/WIFI/devWIFI.cpp Профиль рантайма + сохранение настроек (/pteronautos)

Следующий слой вниз — какая именно форма волны получается из чисел и как каждый профиль подключает функции к PWM-выходам — живёт в Справочник микшеров , а конверт тайминга серво описан в статье Серво-ядро статье.