MIRO عبارة عن منصة روبوت داخلية مفتوحة. الجزء 4 - مكون البرنامج: ARDUINO (AVR)

صورة

نواصل تفكيك مكون البرنامج من منصة MIRO. أود أن أدرس بمزيد من التفصيل بالضبط البرنامج تحت AVR. لذلك ، سوف نكرس جزأين لهذه القضية. في البداية وصفنا الهيكل العام للمكتبة ، وفي الثانية - تنفيذ بعض الأساليب الأساسية.

جدول المحتويات: الجزء 1 ، الجزء 2 ، الجزء 3 ، الجزء 4 ، الجزء 5 .

تحول البرنامج تحت ARDUINO إلى أنه أكبر البرامج المكتوبة ذاتيا. بشكل عام ، فإن كل منطق العمل المباشر مع المشغلات وأجهزة استشعار الروبوت يكمن في AVR. وعلى هذا المستوى ، يتم تنفيذ API - مكتبة برامج سريعة التطوير لـ MIRO.

يوصف هيكل API في قسم الويكي لمستودع التخزين المناظر. حتى الآن ، فقط باللغة الروسية. والآن سنقوم بتحليل الكود بمزيد من التفاصيل. لن أعطي عن قصد إعلانات كاملة عن الصف ، وأختصرها مع علامة "..." ، ولم يتبق سوى الأشياء المهمة في الوقت الحالي.

في نموذج البرنامج الخاص بنا ، يتكون كل روبوت MIRO من هيكل ومجموعة من الأجهزة المتصلة. عند التصميم ، كان من المفترض أن هيكل الروبوت - سيكون دائمًا نوعًا ما من الهيكل المعدني - يجب مراعاة الروبوتات أو الروبوتات التي تستخدم بعض مبادئ الحركة الأخرى بشكل منفصل.

class Miro : public Robot { public: Miro(byte *PWM_pins, byte *DIR_pins); #if defined(ENCODERS_ON) Miro(byte *PWM_pins, byte *DIR_pins, byte *ENCODER_pins); #endif ~Miro(); ... }; 

فئة Miro هي فئة عالية المستوى وتصف التكوين الكامل للروبوت. هذه الفئة هي سليل فئة الروبوت ، الذي يصف فقط الوظائف الأساسية للروبوت.

 class Robot { public: Robot(byte *PWM_pins, byte *DIR_pins); #if defined(ENCODERS_ON) Robot(byte *PWM_pins, byte *DIR_pins, byte *ENCODER_pins); #endif ~Robot(); Chassis chassis; void Sync(); int attachDevice(Device *dev); int dettachDevice(Device *dev); ... protected: Device* _devices[ROBOT_MAX_DEVICES]; byte _device_count; }; 

يقوم المصمم بإجراء الإعداد الأولي لدبابيس الهيكل والقيم الأولية لتكوين الروبوت.

تنفذ طريقة Sync () العمليات اللازمة للهيكل ولجميع الأجهزة المتصلة بالروبوت ، كل خطوة من دورة حلقة () حلقة رئيسية من رسم ARDUINO. تستدعي أساليب Miro Sync () لفئة Miro أساليب Sync () المقابلة للهيكل وجميع الأجهزة المتصلة بالروبوت.

تحتوي فئة Robot أيضًا على مؤشر لمجموعة من الأجهزة المتصلة بالروبوت ، وطرق العمل مع هذه المجموعة (قم بتوصيل جهاز جديد ، وقطع الاتصال ، والعثور حسب الفهرس والاسم). تحتوي فئة الروبوت أيضًا على كائن من فئة الهيكل - الهيكل.

ولكن لنبدأ بشيء أكثر بساطة - مع الأجهزة. يتم وصف كل جهاز يمكن توصيله بالروبوت ، سواء كان مؤشر LED ، أو جهاز استشعار ، أو مشغل لا يرتبط مباشرة بالهيكل (عربة) ، في فئة الخلف ، وهو أمر شائع لجميع الأجهزة في فئة الجهاز الظاهري:

 class Device { public: virtual void Sync(); virtual void setParam(byte pnum, byte *pvalue); virtual void getParam(byte pnum, byte *pvalue); virtual byte getPinsCount(); virtual char* getName(); virtual byte getParamCount(); protected: byte *pins[2]; }; 

ترتبط الطرق الافتراضية setParam و getParam و getParamCount بتعيين وتلقي وتحديد عدد معلمات الجهاز. يمكن أن تكون المعلمة أي خاصية: سطوع مؤشر LED ، وموضع محرك الأقراص ، وما إلى ذلك. الطبقة اللاحقة لكل جهاز تنفذ هذه الطرق بطريقتها الخاصة. الغرض من getName ، أساليب getPinsCount ، أعتقد ، واضح من الاسم. تعد طريقة Sync التي تمت مصادفتها مؤخرًا طريقة خاصة للتحكم في الجهاز بدون حظر وأتمتة بعض العمليات مع الجهاز الذي يجب إجراؤه بانتظام ، مع تكرار كل حلقة رئيسية.

دعنا الآن نلقي نظرة على تطبيق عام أكثر أو أقل للفئة المنحدرة.

 class MIROUsonic : virtual public Device { public: void Sync(); void setParam(byte bnum, byte *pvalue); void getParam(byte bnum, byte *pvalue); byte getPinsCount(); char* getName(); byte getParamCount(); void Init(byte trig_pin, byte echo_pin); void On(unsigned int max_dist); void On(); void Off(); int getDist(unsigned int max_dist); unsigned int getMesCount(); private: bool _isOn; unsigned int _mesCount; unsigned int _dist; unsigned int _max_dist; }; 

في تحديد فئة أداة تحديد المدى بالموجات فوق الصوتية (أعلاه) ، بالإضافة إلى طرق الأصل ، هناك أيضًا طرق:

  • التهيئة الأولية ؛
  • تشغيل وإيقاف - تشغيل الجهاز (يأتي إطلاق الشركة) ؛
  • getDist - إرجاع المسافة المقاسة بواسطة الباحث عن النطاق ؛
  • إرجاع getMesCount - عدد القياسات التي تم إجراؤها منذ أن تم تشغيل الجهاز.

لتخزين الحالة الداخلية للجهاز ، يتم استخدام الحقول التالية:

  • _isOn (TRUE - الجهاز قيد التشغيل ، يتم التحكم فيه بواسطة طرق التشغيل والإيقاف) ؛
  • _mesCount (يخزن عدد الأبعاد المستخدمة في أسلوب getMesCount) ؛
  • _max_dist - الحد الأقصى للمسافة المطلوبة للقياس * ؛
  • _dist هي المسافة المقاسة الفعلية.

حول أقصى مدى القياس
* من المعروف أن جهاز HC-SR04 الواسع وفقًا لجواز السفر قادر على قياس مسافات تصل إلى 4 أمتار. ومع ذلك ، تتضمن طريقة القياس نفسها انتظار عودة الإشارة فوق الصوتية ، تليها تشفير المدة في الإشارة على خط الصدى. وفي الواقع ، إذا كان المستخدم لا يحتاج بالتأكيد إلى قياس المسافات في المدى حتى 4 أمتار ، ولكن يكفي ، في حدود 1 متر ، يمكنك الانتظار حتى 4 مرات للإشارة المنعكسة. يولد جهاز قياس المدى نفسه إشارة على خط الصدى بمجرد أن يستقبله ويقوم بإجراء التعديل. أي قد لا يؤثر هذا على طول الفترة بين القياسات المجاورة ، ولكن يمكن تقليل مدة قياس واحد بهذه الطريقة.

والآن لشرح طريقة المزامنة. إذا كان للجهاز الحالة _isOn == TRUE (on) ، فسيتم تنفيذ دورة القياس نفسها في طريقة Sync ، وسيتم تسجيل نتيجة القياس في حقل _dist. في هذه الحالة ، عند استدعاء getDist ، ستُرجع الطريقة على الفور القيمة المسجلة في _dist ، ولن تكون هناك دورة قياس. إذا _isOn == FALSE (إيقاف) ، فإن دورة القياس ، على العكس من ذلك ، يتم تنفيذها فقط أثناء استدعاء getDist ، لن يتم قياس أي شيء في طريقة المزامنة. من المفترض أن يقوم المبرمج باستدعاء طريقة Sync للروبوت بأكمله ، والتي بدورها ستستدعي أساليب Sync التي تحمل الاسم نفسه لجميع الأجهزة المتصلة بالروبوت وكائن من فئة الهيكل (الهيكل).

من بين الأجهزة الموجودة في واجهة برمجة التطبيقات (API) ، فقط تلك الأشياء التي طبقتها MIRO الآن: LED ، جهاز البحث عن نطاق الموجات فوق الصوتية ، جهاز استشعار الضوء المقاوم للصور ، محرك الأقراص ، جهاز استشعار الخط.

تلمس برفق الشاسيه. هذه الفئة تنفذ "عربة مجردة" من الروبوت. يحتوي على طرق تسمح لك بالتحكم في المحرك.

 class Chassis { public: Chassis(byte *PWM_pins, byte *DIR_pins); #if defined(ENCODERS_ON) Chassis(byte *PWM_pins, byte *DIR_pins, byte *ENCODER_pins); #endif ~Chassis(); void Sync(); float getVoltage(); int wheelRotatePWMTime(int *speedPWM, unsigned long time); int wheelRotatePWM(int *speedPWM); bool wheelIsMoving(byte wheel) {return this->_wheel_move[wheel];} byte getWheelCount() { return WHEEL_COUNT; } #if defined(ENCODERS_ON) int wheelRotateAng(float *speed, float *ang, bool en_break); unsigned long wheelGetEncoder(byte wheel); ... #endif //ENCODERS_ON private: float _vbat; //Battery volgage bool _wheel_move[WHEEL_COUNT]; char _wheelDir[WHEEL_COUNT]; byte _wheel_PWM_pins[WHEEL_COUNT]; byte _wheel_DIR_pins[WHEEL_COUNT]; void _init(byte *PWM_pins, byte *DIR_pins); #if defined(ENCODERS_ON) byte _wheel_ENCODER_pins[WHEEL_COUNT]; bool _wheel_sync_move; float _wheelAngSpeed[WHEEL_COUNT]; float _wheelSetAng[WHEEL_COUNT]; float _wheelSetAngSpeed[WHEEL_COUNT]; ... #endif //ENCODERS_ON }; 

إذا أخذنا بعين الاعتبار عربة بدون تشفير وعمومًا دون ملاحظات ، فهناك طرق تحكم بسيطة لهذا باستخدام إشارة PWM. إذا كان هناك ترميز في العربة ، تصبح الفئة أكثر تعقيدًا. لتبسيط حياة المستخدم ، طرق مثل تظهر فيه:

  • wheelRotateAng - دوران العجلة عند زوايا دوران محددة مسبقًا مع سرعات زاوية معينة ؛
  • إرجاع wheelGetPath - طول المسار الذي اجتازته كل عجلة ؛
  • wheelGetLinSpeed ​​- إرجاع السرعة الخطية الحالية لكل عجلة ؛
  • wheelGetAngSpeed ​​- إرجاع السرعة الزاوية الحالية لكل عجلة ؛
  • إرجاع wheelGetEncoder - عدد استجابات برامج التشفير لكل عجلة.

وعدد من الأساليب المساعدة. وكذلك طريقة معايرة الدفع. ولكن بمزيد من التفصيل ، سيتم النظر في الطرق الرئيسية لفئة الهيكل في المرة القادمة.

مع التقدم قليلاً ، سيكون من المناسب في هذا المكان ملاحظة أنه يمكن تكييف مكتبة Miro بأكملها بسهولة أو تكميلها مع أي روبوت آخر باستخدام نظام حركة تفاضلية بعجلتين. وبجهد معين - وإلى تكوينات الدفع والتوجيه الأخرى. في حالة الدائرة التفاضلية ، تحتاج فقط إلى وصف ملف التكوين config.h بشكل صحيح. ودون أي RPi. على سبيل المثال ، في أقل من ساعة ، أطلقنا كل شيء على مثل هذه الأشياء الصغيرة لدورة الأمن السيبراني الإقليمية BlackMirrorCTF-2019 في جامعتنا ( الرابط ).

صورة

كان لدى الروبوتات واجهة للوصول عبر TELNET ونظام قيادة للتحكم عن بعد. كانت الوثيقة مع نظام القيادة مخفية أو مشفرة في مكان ما. قام المشاركون بمسح عناوين IP وفتح المنافذ على الروبوتات نفسها. مع اتصال ناجح ، أصدرت الروبوتات دعوة ، وفهم المشاركون أنهم "دخلوا". حسنًا ، بعد ذلك أحضرت الفرق الروبوتات على طول الطريق السريع إلى خط النهاية. في البداية ، أرادوا جعل المسار بأكمله مع الروبوتات في مكان ما في غرفة معزولة مع تثبيت كاميرا IP ، ولكن واجه المنظمون بعض المشاكل مع كاميرا IP وفقدوا بعض السحر.


هذا كل شيء الآن. من المحتمل أنه أثناء التطوير ، سيخضع نموذج البرنامج للتغييرات. بالمناسبة ، تم تعديله مؤخرًا بشكل طفيف ، بعد أن بدا الرمز أكثر خبرة OOP-shchik.

قبل الجزء الخامس - دعنا نتحدث عن الترميز والزوايا والمعايرة.

Source: https://habr.com/ru/post/ar475512/


All Articles