البنية: النوى وتدفق البيانات
كيف يتحول تيار 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
أربع أفكار بنيوية تُبقي الوحش مستقراً والكود صغيراً:
- تُطبَّع القنوات مبكراً. كل قيمة خام في نافذة CRSF 172–1811 تُسقَط مرة واحدة على −1…+1(
_crsfToNorm) أو على نسبة مئوية، ولا يتدفق عبر الخلّاطات إلا تلك الوحدة — بلا ثوابت سحرية متكررة. -
المخرجات موسومة لا مثبّتة. تكتب الخلّاطات في
_f[ServoFunc]. أي مخرج PWM فيزيائي يقوده الوسم يتقرر لاحقاً عبرfuncMapالخاص بالملف — انظر مرجع الخلّاطات .إعادة تثبيت نموذج لا تمسّ أبداً رياضيات الخلّاط. - النواة عائلة وقت الترجمة، واختيار وقت التشغيل. كلٌّ من الخفّاق الموجي ومتحكم علبة التروس يعيش في الملف الثنائي؛ الملف النشط يختار النواة في كل نبضة تحديث.
- الوضع الآمن ليس حدثاً بل حالة. انقطاع الوصلة ووضع المنضدة وتجاوز العصا هي بوابات صريحة في
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»: سيرفوان للجناح ينفّذان تذبذباً متصل الطور يُنحَت شكله كل دورة. تشريحها:
- بوابة رفرفة مع تخلّف. يجب أن يتجاوز الخانق عتبة الرفرفة (الخام ≈303 افتراضياً، ما يعادل ≈1.08 ms PWM) ليدخل الرفرفة؛ ولا يخرج إلا دون العتبة − 50 تخلّفاً، فلا يجعل الخانق الحديّ الأجنحة ترتجف أبداً.
- التردد. يتقدّم FlappingOscillator بالزمن المنقضي الفعلي(ساعة µs، dt محدود بـ 100 ms). يمزج هدف الإيقاع قناة CH6 لتردد الرفرفة والخانق عبر
throttleFrequencyMixالخاص بالملف، ضمن 0.5 Hz…flapBaseFreq/10. - السعة. نسبة الخانق من سقف سرعة السيرفو
ampMax = degPerSec / (2·f)(حيثdegPerSec = 60°/servoSpeed_ms)، بسقف صارم 55° قبل المضاعف. لذلك تنهار السعة طبيعياً عند التردد العالي — لا يطلب الجناح أبداً أكثر مما يستطيع السيرفو تقديمه. - الشراسة. تُشكَّل شراسة الضربة الهابطة(القدرة) والصاعدة(الاسترداد) لكل ضربة، وتُعدَّل لا تناظرياً بالرافعة(السحب يقسّي الهابطة، والدفع يقسّي الصاعدة) وباقتران الخانق، ثم تُقيَّد 0…8 قبل دالة الشكل.
- تفاضلات الانعراج. تضيف الدفة شراسة متعاكسة يمين/يسار(
rudderFerocityRange) وسعة متعاكسة يمين/يسار(rudderAmplitudeDifferential) بينما تبقى طور انعكاس الضربة مشتركاً بين الجناحين — سلطة الانعطاف تأتي من المكث غير المتناظر، لا من جناحين غير متزامنين. - الهندسة والإخراج. تُدرَّج الموجة المشكَّلة −1…+1 إلى درجات، وتُخلَط مع توجيه الجنيح/الرافعة(سلطة ±60° × مقياس)، وتُزاح بتريم مركز الانزلاق/الرفرفة، وتُقيَّد 0…180°، ثم تُحوَّل إلى µs عبر الغلاف القابل للضبط
servoMinUs…servoMaxUs(افتراضياً 988…2012) مع تريم لكل دالة. - فرع الانزلاق. دون عتبة الرفرفة يضمحل المذبذب وتحافظ الأجنحة على زاوية انزلاق ثابتة — حالة مثالية للمنضدة والإطلاق.
نواة علبة التروس (محرك + أذناب)
تستبدل نواة علبة التروس رفرفة الجناح الخالصة بمجموعة دفع بمحرك مع أسطح ذيل تقليدية. ولأن المحرك يدور باستمرار، فهذه النواة بلا حالة في كل نبضة — بلا مذبذب — وبدلاً من ذلك:
- يسقط الخانق(المسلَّح) على أمر ESC من 1000…2000 µs(
SF_MOTOR)، ويخمُد عند نزع السلاح؛ - يخلط الذيل: ملفات الذيل V تستخدم مزيج إلفون(جنيح+رافعة / جنيح−رافعة)، والملفات الكلاسيكية تستخدم سطح رافعة منفصلاً؛
- يسمح لـ Zephyrus(عند التفعيل) بحقن تصحيحات PID للفة والميلان في سيرفو الذيل، مقيَّدة بـ ±250 µs(
ZEPHYR_GEARBOX_CLAMP_US) كي لا تُعطّل ومضة مستشعر سيرفو أبداً؛ - يحافظ على نفس خلّاط الدفة وغلاف µs/تريم/تقييد الخاص بنواة الموجة.
يمكن لجهاز أورنيثوبتر واحد أن يحمل الشخصيتين معاً: إطلاق خفّاق بنواة الموجة، وإبحار بعلبة التروس — تبديل الملف وقت التشغيل هو ذلك السطر الواحد في update().
الحالات: الربط والمقعد وفشل الأمان
يُستدعى update() بإيقاع ثابت ~10 ms من حلقة WiFi/السيرفو ويبوّب على ثلاثة أعلام قبل تشغيل أي خلّاط:
| الحالة | الشرط | السلوك |
|---|---|---|
| طيران عادي | 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
|
يكتب µs متزامنة مع نبضة CRSF |
| إعداد WebUI |
src/lib/WIFI/devWIFI.cpp
|
ملف وقت التشغيل + استمرار الضبط(/pteronautos) |
الطبقة الأدنى — أي شكل موجة تنتجه الأرقام بالضبط، وكيف يوصّل كل ملف الدوال بمخارج PWM — تعيش في مرجع الخلّاطات ، ويُوثَّق غلاف توقيت السيرفو في مقال نواة السيرفو مقالاً.