아키텍처: 커널과 데이터 흐름

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. 채널은 일찍 정규화됩니다. 172–1811 CRSF 창의 모든 원시 값은 −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()로 실시간 전환할 수 있습니다 — 재플래시 없이 새 기체로 다시 조준합니다. 총 8개 프로파일이 있으며, 정확한 funcMap 배치는 믹서 레퍼런스에 표로 정리돼 있습니다.

파형 커널 (서보 날갯짓)

파형 커널은 대부분이 "PteronautOS"라고 부르는 것입니다: 두 날개 서보가 매 사이클 형태를 조각하는 위상 연속 진동을 수행합니다. 그 구조:

기어박스 커널 (모터+꼬리)

기어박스 커널은 순수 날갯짓을 모터 구동계 + 일반 꼬리면과 맞바꿉니다. 모터는 연속 회전하므로 이 커널은 틱마다 무상태이며 — 오실레이터 없음 — 대신:

하나의 오르니톱터 장비가 두 성격을 모두 지닐 수도 있습니다: 파형 커널로 플래핑 발진, 기어박스로 순항 — 런타임 프로파일 전환은 update()의 그 한 줄입니다.

상태: 링크·벤치·페일세이프

update()는 WiFi/서보 루프에서 고정 ~10 ms 케이던스로 호출되며, 믹서 실행 전 세 플래그를 검사합니다:

상태 조건 동작
정상 비행 linkUp + 아밍 채널 활성 전체 커널 출력이 스틱을 따릅니다
벤치/패널 모드 benchMode(WebUI 패널, RC 링크 없음) 중립 스틱이 주입되고, 스로틀은 플랩 임계값 아래에 정차 — 글라이드 + 트림 편집이 실시간으로 보입니다
스틱 오버라이드 stickOverride(가상 채널) 펌웨어 주입 채널 값이 CRSF를 완전히 대체합니다(서보 스윕, 테스트)
페일세이프 링크 손실(onLinkDown / enterFailsafe) 모든 함수가 1500 µs로 중앙화되고, 오실레이터 리셋, 모터 → 최소; 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, 듀얼 PID, 크레스트/테일 보정
PWM 출력 스테이지 src/lib/ServoOutput/devServoOutput.cpp CRSF 틱에 동기화된 µs를 기록합니다
WebUI 설정 src/lib/WIFI/devWIFI.cpp 런타임 프로파일 + 튜닝 영속성(/pteronautos)

바로 아래 계층 — 숫자가 정확히 어떤 파형을 만들고, 각 프로파일이 함수를 PWM 출력에 어떻게 배선하는지 — 는 믹서 레퍼런스 에 있고, 서보 타이밍 엔벨로프는 서보 커널 문서에 있습니다.