Référence des mixers
Des manches et du gyroscope aux µs sur le fil : la géométrie complète de chaque mixer sélectionnable — axes d'aile, mélanges de dérive, elevons, trims et limites.
Cette page documente la couche mixeur de src/lib/Ornithopter/Ornithopter.cpp et le système de profils de OrnithopterConfig.h. Pour l'architecture environnante, commencez par l'
article Architecture
; pour la temporisation des impulsions et les plages de trim, voir l'
Noyau servo
article.
Étiquettes de fonction de servo
Chaque sortie de chaque mixeur est une valeur µs écrite dans _f[], indexée par une étiquette ServoFunc. Les étiquettes sont du transport — elles disent ce que signifie un signal, jamais où il est câblé :
| Étiquette | Nom | Signification |
|---|---|---|
0
|
SF_NONE
|
Réservé — aucune fonction (les premiers créneaux PWM restent libres pour BOOT et I2C) |
1 / 2
|
SF_LEFT_WING / SF_RIGHT_WING
|
Ailes battantes avant (noyau forme d'onde) |
3
|
SF_RUDDER
|
Gouvernail de tête/crête (forme d'onde) ou de dérive (boîte) — mélange lacet + roulis |
4
|
SF_MOTOR
|
Gaz d'ESC brushless (noyau boîte uniquement) |
5 / 6
|
SF_VTAIL_LEFT / SF_VTAIL_RIGHT
|
Empennages en V, mélange élevon (noyau boîte) |
7
|
SF_ELEVATOR
|
Profondeur séparée classique (profils boîte 6/7) |
8 / 9
|
SF_BACK_LEFT_WING / SF_BACK_RIGHT_WING
|
Paire d'ailes arrière d'une cellule 4 ailes (miroir de la paire avant, trim propre) |
Un profil d'exécution fournit la funcMap : un tableau qui mappe l'index de sortie PWM → ServoFunc. Les trois premiers créneaux (PWM 1…3) sont toujours SF_NONE — ils appartiennent à la sangle BOOT et au bus I2C — donc les vraies fonctions de servo commencent à l'index PWM 3 (le commentaire du firmware l'explicite : index 3 = CH4, 4 = CH5, 5 = CH6).
Les huit profils de mixer
Huit profils de mixeur existent. Les profils 0–2 pilotent le noyau forme d'onde (ailes battantes), les profils 3–7 le noyau boîte de vitesses (moteur + empennages) :
| # | Profil | Noyau | Servos | funcMap (PWM 3 · 4 · 5) |
|---|---|---|---|---|
0
|
SERVO_2WING
|
forme d'onde | 2 | Aile gauche · Aile droite · — |
1
|
SERVO_2WING_1RUD
|
forme d'onde | 3 | Aile gauche · Aile droite · Gouverne |
2
|
SERVO_4WING
|
forme d'onde | 4 (arrière-droite partage le miroir arrière-gauche) | Aile gauche · Aile droite · Aile arrière gauche |
3
|
GEARBOX_2VTAIL_1RUD
|
boîte | 3 | Gouverne · V-gauche · V-droite |
4
|
GEARBOX_1MOT_2VTAIL
|
boîte | 3 | Moteur · V-gauche · V-droite |
5
|
GEARBOX_1MOT_2VTAIL_1RUD
|
boîte | 4 (V-droite partage le miroir gauche) | Gouverne · Moteur · V-gauche |
6
|
GEARBOX_1ELE_1RUD
|
boîte | 2 | Gouverne · Profondeur · — |
7
|
GEARBOX_1MOT_1ELE_1RUD
|
boîte | 3 | Gouverne · Moteur · Profondeur |
Sélection : drapeau de build MIXER_PROFILE (ancien ORNITHOPTER_GEARBOX=1 → profil 5), puis remplaçable à l'exécution via la WebUI (setOrnithopterProfile). Le test de noyau est simplement activeProfile ≥ GEARBOX_2VTAIL_1RUD.
Mixage des axes d'aile (kernel onde)
Toutes les valeurs de canaux entrent normalisées dans les mixeurs : _crsfToNorm mappe linéairement la fenêtre brute 172…1811 vers −1…+1. Les commandes de pilotage sont ensuite mises à l'échelle par les curseurs d'autorité par profil (aileronScale, elevatorScale, 0–100 %) fois ±60° (ORNI_STEER_MAX_DEG).
Géométrie en miroir. Les servos d'aile sont montés en miroir, ce qui inverse le sens des termes de mode commun et différentiel. Le code traite donc l'aileron (roulis) comme commun — il s'ajoute aux deux ailes, devenant une déflexion physique différentielle — et la profondeur (tangage) comme différentielle dans le code, devenant une déflexion physique commune. Les équations d'angle, avec ORNI_NEUTRAL_ANGLE_DEG = 100° et le multiplicateur 2× appliqué seulement aux termes d'écart :
angleLeft = NEUTRAL + (aileron + elevator + flapCentre − degL) · 2
angleRight = NEUTRAL + (aileron − elevator − flapCentre + degR) · 2
flapping: degL/R = amplitudeL/R · shapedWave(rawPhase, ferocityL/R, …)
glide: degL = degR = 0 → static glide offset takes over
degL/degR sont les déflexions de course instantanées de l'aile gauche et droite, chacune le produit de sa propre amplitude et d'une onde façonnée par la férocité. Profondeur vers le haut renforce la course descendante ; vers le bas la montante (férocité asymétrique). Le lacet divise les ailes de deux façons complémentaires :
- Différentiel de férocité (
rudderFerocityRange) : la gauche reçoit+férocité, la droite−férocité— les deux ailes dwellent différemment mais gardent une phase d'inversion partagée (limiarShared), donc les virages sont un couple de roulis pur, jamais une désynchronisation. - Différentiel d'amplitude (
rudderAmplitudeDifferential) : amplitude gauche ×(1+Δ), droite ×(1−Δ) — divergence symétrique autour de la course fixée par les gaz.
Les angles sont bornés 0…180° et convertis en impulsions avec l'enveloppe configurable servoMinUs…servoMaxUs (défauts 988…2012) : µs = min + angle·(max−min)/180, plus le trim par fonction. Les décalages de centre de plané/battement (glideAngleDeg, flappingAngleDeg, ±15°) entrent comme termes statiques sur leur branche respective — les centres de plané et de battement peuvent donc être réglés indépendamment par profil de vol.
Mixage de la dérive (les deux kernels)
Le mixeur de gouverne est partagé verbatim par les deux noyaux — une équation, deux cellules :
mix = rudderNorm · rudderYawWeight + aileronNorm · rudderRollWeight
mix = clamp(mix, −1 … +1)
µs = 1500 + mix · 500 (rudder centre ± 500 µs)
+ gyroRudderCorrection (Zephyrus, when enabled)
+ servoTrimUs[SF_RUDDER]
Défauts : rudderYawWeight = 65%, rudderRollWeight = 35% (réglables à l'exécution dans la WebUI, stockés par sauvegarde). Le couplage de roulis sur la gouverne permet à un ptérosaure lourd d'aile de tenir des virages coordonnés sans acrobatie de fil de lacet ; réduisez le poids de roulis si la gouverne de tête semble trop agressive en roulis.
Mixage empennage et elevons (boîte à engrenages)
Le noyau boîte s'exécute sans état à chaque tick. Ses trois sous-mixeurs :
- Moteur —
SF_MOTOR: armé, gaz 0…1 mappe vers 1000…2000 µs ; désarmé ou liaison perdue force le minimum (moteur arrêté). - Gouverne — équation identique à la section ci-dessus.
- Empennages — deux familles. Les profils classiques (6/7) pilotent une profondeur séparée :
µs = 1500 + elevatorNorm·500 + pitchPID + trim. Les profils en V (3/4/5) mélangent en élevon les deux canaux sur les deux servos d'empennage :
VtailLeft = 1500 + (aileron + elevator)·scale + rollPID + pitchPID + trimL
VtailRight = 1500 + (aileron − elevator)·scale − rollPID + pitchPID + trimR
scale = 500 µs; both aileron/elevator sums clamped to −1…+1 first
Sur le noyau boîte, Zephyrus injecte les deux corrections PID de roulis et tangage dans les servos d'empennage (roulis en opposition de phase, tangage en mode commun), chacune bornée dur à ±250 µs (ZEPHYR_GEARBOX_CLAMP_US). Un glitch de gyro peut donc faire osciller, mais jamais caler, un servo d'empennage.
Injection Zéphyros, trims et failsafe
Trois points d'injection différents existent selon le noyau et l'axe :
| Axe | Noyau forme d'onde | Noyau boîte |
|---|---|---|
| Gouverne / lacet | gyroRudderCorrection ajouté aux µs du gouvernail de crête |
gyroRudderCorrection ajouté aux µs du gouvernail de dérive |
| Roulis (aileron) | — (les ailes à forme d'onde ne portent pas de PID de roulis) | gyroAileronCorrection, opposition de phase sur empennage V, borné ±250 µs |
| Tangage (profondeur) | — (injecté comme modulation d'onde dans la couche Zephyrus) | gyroElevatorCorrection, mode commun, borné ±250 µs |
Trims & limites. Chaque fonction a un trim signé par servo (servoTrimUs[tag], défaut 0, ±300 µs) ajouté en dernier, et chaque valeur passe _clampServo — une borne de sécurité absolue 500…2500 µs qui prime sur tout. En failsafe ou liaison perdue, toutes les fonctions reviennent à 1500 µs et un moteur de boîte au minimum, si bien que le modèle plane toujours vers le neutre.
Prêt pour la couche pratique ? Le Réglage de la forme d'onde montre comment ces nombres se ressentent aux manches, et l' Architecture montre où chaque mixeur se situe dans le pipeline.