ستخبر هذه المقالة عن تجربة استخدام نهج الممثل في مشروع واحد مثير للاهتمام لنظام التحكم الآلي للمسرح. هذا هو بالضبط الانطباع الاستخدام ، لا أكثر.
لقد تمكنت مؤخرًا من المشاركة في مهمة واحدة مهمة للغاية - التحديث ، ولكن في الواقع - تطوير نظام تحكم آلي جديد لرفع الرفوف إلى أحد المسارح.
المسرح الحديث (إذا كان كبيرًا) يعد تنظيمًا معقدًا إلى حد ما. ويشارك فيه الكثير من الأشخاص والمعدات والأنظمة المختلفة. أحد هذه الأنظمة هو نظام التحكم "لرفع وخفض" المشهد على المسرح. أصبحت العروض الحديثة والمزيد من الأوبرا والباليه مشبعة أكثر فأكثر بالوسائل التقنية كل عام. ويستخدم الكثير من المناظر الطبيعية المعقدة وحركتها أثناء العمل. يتم استخدام المشهد بفعالية في الخطط الإرشادية ، مما يوسع معنى ما يحدث وحتى "يلعب دورك الداعم"). بشكل عام ، كان من الممتع للغاية التعرف على الحياة الخلفية للمسرح ومعرفة ما يحدث هناك خلال العروض. بعد كل شيء ، يرى المشاهدون العاديون فقط ما يحدث على المسرح.
لكن هذه المقالة ما زالت تقنية وأردت أن أشاركها في تجربة استخدام نهج الفاعل لتنفيذ الإدارة. وشارك أيضًا تجربة استخدام أحد أطر عمل C ++ القليلة - sobjectizer .
لماذا بالضبط له؟ لقد كنا نتطلع إليه لفترة طويلة. هناك مقالات عن habr ، لديها وثائق مفصلة ممتازة مع أمثلة. المشروع ناضج جدا. وأظهرت نظرة سريعة على الأمثلة أن المطورين يعملون بمفاهيم "مألوفة" (الحالات ، أجهزة ضبط الوقت ، الأحداث) ، أي لم يكن من المتوقع حدوث مشاكل كبيرة في الفهم والبراعة ، لاستخدامها في مشروعنا. ونعم ، الأهم من ذلك ، أن المطورين مناسبون وودودون ومستعدون للمساعدة في تقديم المشورة (باللغة الروسية) . لذلك قررنا أن نحاول ...
ماذا نفعل؟
لذلك ، ما هو "كائن التحكم" لدينا مثل؟ نظام المصاعد shtanketovy - هذا هو 62 ساق (الأنابيب المعدنية) على كامل عرض المرحلة معلقة فوق هذا المشهد بالذات ، كل 30-40 سم تقريبا من حافة المرحلة في العمق. يتم تعليق السيقان نفسها على الحبال ويمكن أن ترتفع أو تنخفض إلى المرحلة (الحركة الرأسية). في كل أداء (أو الأوبرا أو الباليه) ، يتم استخدام جزء من الدعامات للزينة. يتم تعليق المشهد عليها ونقله (إذا تطلب البرنامج النصي) أثناء العمل. يتم تنفيذ الحركة نفسها تحت قيادة المشغلين (لديهم لوحات تحكم خاصة) باستخدام نظام "المحرك - الكابل - الثقل الموازن" (تقريبًا مثل المصاعد في المنازل). توجد المحركات عند أطراف المرحلة (على عدة مستويات) ، بحيث تكون غير مرئية للمشاهد. تنقسم جميع المحركات إلى 8 مجموعات ولكل مجموعة ثلاثة محولات تردد (IF). في كل مجموعة ، يمكن تنشيط ثلاثة محركات في وقت واحد ، كل منها متصل بعاكسه الخاص. في المجموع ، لدينا نظام من 62 محركا و 24 العاكس ، والتي يجب علينا السيطرة عليها.
كانت مهمتنا تطوير واجهة مشغل لإدارة هذا الاقتصاد ، وكذلك تنفيذ خوارزميات الإدارة. يتضمن النظام ثلاث وظائف مراقبة. يوجد مركزان للتحكم أعلى المرحلة مباشرةً ويقع موقع واحد في غرفة المحرك (حيث توجد خزانات التحكم) ومصمم لمراقبة العمل لفني كهربائي أثناء الخدمة. في خزانات التحكم ، توجد وحدات تحكم تقوم بتنفيذ الأوامر ، والتحكم في PWM ، وتوفير الطاقة للمحركات ، وتتبع موضع السيقان. في الجزء العلوي الأول من أجهزة التحكم عن بعد هي الشاشات ، وحدة النظام حيث يتم التحكم في خوارزميات التحكم وكرة التتبع كـ "فأر". يتم استخدام شبكة Ethernet بين لوحات التحكم. كل خزانة التحكم لديها قناة RS485 (أي 8 قنوات) من كل من لوحات التحكم اثنين. يمكن تنفيذ الإدارة في وقت واحد من كل من أجهزة التحكم عن بعد (التي تكون أعلى من المستوى) ، ولكن في الوقت نفسه يتم تبادل واحد فقط من أجهزة التحكم عن بعد (المعينة من قبل المشغل كمشغل رئيسي) مع الخزانات ، وتعتبر وحدة التحكم الثانية في هذه اللحظة نسخة احتياطية ويتم تعطيل التبادل عليها.
وهنا الجهات الفاعلة
من وجهة نظر الخوارزميات ، تم بناء النظام بأكمله على الأحداث. إما أن تكون هذه هي بعض التغييرات في أجهزة الاستشعار ، أو إجراءات المشغل ، أو بداية بعض الوقت (أجهزة ضبط الوقت). ويتم وضع مثل هذه الخوارزميات بشكل جيد للغاية بواسطة نظام الجهات الفاعلة التي تعالج الأحداث القادمة ، وتشكل نوعًا من الاستجابة ، وكل هذا يتوقف على حالتها. في sobjectizer ، كل هذه الآليات تخرج من الصندوق. يمكن أن تعزى المبادئ الرئيسية التي يقوم عليها هذا النظام: يحدث التفاعل بين الجهات الفاعلة من خلال الرسائل ، ويمكن أن يكون للجهات الفاعلة حالات وتتنقل بينها ، في كل ولاية يعالج الفاعل فقط تلك الرسائل التي تهمه في الوقت الحالي. ومن المثير للاهتمام ، أن العمل مع الممثلين في صانع ربح منفصل بشكل مفاهيمي عن العمل مع سير العمل. أي يمكنك وصف العناصر الفاعلة التي تحتاج إليها ، وتحقيق منطقهم ، وتحقيق تفاعلهم من خلال الرسائل. ولكن بعد ذلك حل بشكل منفصل مسألة تخصيص المواضيع (الموارد) لعملهم. يتم ضمان ذلك من خلال ما يسمى "المرسلون" المسؤولين عن سياسة معينة للتعامل مع الخيوط. على سبيل المثال ، هناك مرسل يقوم بتخصيص مؤشر ترابط منفصل لكل ممثل للعمل معه ، وهناك مرسل يوفر مجموعة من مؤشرات الترابط (على سبيل المثال ، يمكن أن يكون هناك ممثلون أكثر من مؤشرات الترابط) مع القدرة على تعيين الحد الأقصى لعدد مؤشرات الترابط ، وهناك مرسل يخصص مؤشر ترابط واحد للجميع. يوفر وجود المرسلين آلية مرنة للغاية لإعداد نظام ممثل لتناسب احتياجاتك. يمكنك الجمع بين مجموعات من الجهات الفاعلة للعمل مع أحد المرسلين ، مع تغيير نوع من المرسل إلى آخر ، هذا يغير سطر واحد من التعليمات البرمجية بشكل أساسي. وفقًا لمؤلفي الإطار ، فإن كتابة المرسل الفريد الخاص بك ليست صعبة أيضًا. لم يكن هذا ضروريًا في مشروعنا ، لأن كل ما نحتاجه كان موجودًا بالفعل في sobjectizer.
ميزة أخرى مثيرة للاهتمام هي وجود مفهوم "تعاون" الجهات الفاعلة. التعاون عبارة عن مجموعة من الجهات الفاعلة التي يمكن أن تكون موجودة أو أن يتم تدميرها جميعًا (أو لا يتم إطلاقها) إذا كان هناك ممثل واحد على الأقل في التعاون لم يتمكن من بدء العمل أو إكماله. أنا لا أخاف من إعطاء مثل هذا التشبيه ( على الرغم من أنها من "أوبرا" أخرى ) أن مفهوم "التعاون" يشبه مفهوم "الموقد" في Kubernetes العصرية الآن ، يبدو فقط في sobjectizer ، نشأ في وقت سابق ...
في وقت الإنشاء ، يتم تضمين كل ممثل في التعاون (قد يتكون التعاون من ممثل واحد) ، ويصبح مرتبطًا بواحد أو أكثر من المرسل ويبدأ العمل. في الوقت نفسه ، يمكن (بسهولة) إنشاء الجهات الفاعلة (والتعاون) ديناميكيًا بأعداد كبيرة ، وكما يعد المطورون ، فهي ليست باهظة الثمن. تتبادل جميع الجهات الفاعلة فيما بينها من خلال " صناديق البريد " (mbox). هذا هو أيضا مفهوم مثير للاهتمام وقوي جدا في sobjectizer. يوفر آلية مرنة للغاية لمعالجة الرسائل الواردة. أولاً ، قد يكون هناك أكثر من مستلم واحد يختبئ خلف صندوق. انها حقا مريحة للغاية. على سبيل المثال ، يتم إنشاء مربع يتم فيه استلام الأحداث من المستشعرات الخارجية ويشترك كل ممثل في الأحداث التي تهمه. وهذا يوفر أسلوب "نشر / اشتراك" للعمل. ثانياً ، أتاح للمطورين الفرصة لإنشاء تطبيقهم الخاص لصناديق البريد بسهولة نسبية والذي يمكنه معالجة الرسائل الواردة مسبقًا (على سبيل المثال ، فلترةها بطريقة أو أخرى أو توزيعها بطريقة خاصة بين المستهلكين). بالإضافة إلى ذلك ، لدى كل ممثل صندوق بريد خاص به ويمكنه حتى إرسال "رابط" إليه في رسائل إلى جهات فاعلة أخرى ، على سبيل المثال ، حتى يتمكنوا من إرسال نوع من الإخطار كرد فعل إرجاع.
في مشروعنا ، من أجل ضمان استقلالية مجموعات المحركات فيما بينها ، وكذلك لضمان التشغيل "غير المتزامن" للمحركات داخل المجموعة ، تم تقسيم جميع عناصر التحكم إلى 8 مجموعات (وفقًا لعدد خزائن التحكم) ، كان لكل منها ثلاثة عمال التدفق (حيث لا يمكن لأكثر من ثلاثة محركات تعمل في مجموعة في وقت واحد).
يجب أن يقال أيضًا أن sobjectizer (في الإصدار الحالي 5.5) لا يحتوي على آليات interprocess وتفاعل الشبكة ويترك هذا الجزء للمطورين. قام المؤلفون بذلك عمداً ، بحيث يكون الإطار "أكثر سهولة". علاوة على ذلك ، كانت آليات تفاعل الشبكة "مرة واحدة" موجودة في الإصدارات السابقة ، لكن تم استبعادها. ومع ذلك ، فإن هذا لا يسبب أي إزعاج ، لأنه في الواقع يعتمد تفاعل الشبكة إلى حد كبير على المهام التي يتم حلها ، وبروتوكولات التبادل المستخدمة ، إلخ. هنا ، لا يمكن أن يكون التنفيذ الشامل هو الأمثل لجميع الحالات.
في حالتنا ، للاتصال بالشبكات والتعامل البيني ، استخدمنا أحد التطورات الطويلة الأمد - مكتبة libuniset2 . نتيجةً لذلك ، فإن بنية نظامنا تبدو كالتالي:
- توفر libuniset اتصالاً بالشبكة و interprocess (استنادًا إلى المستشعرات)
- يوفر sobjectizer إنشاء نظام من الجهات الفاعلة التي تتفاعل مع بعضها البعض (في نفس مساحة العنوان) لتنفيذ خوارزميات التحكم.
لذا ، دعني أذكرك ، لدينا 62 محركًا. يمكن توصيل كل محرك بالعاكس ، ويمكن إعطاء الحامل المقابل الإحداثيات التي يجب أن تصل إليها والسرعة التي يجب أن تتحرك بها. بالإضافة إلى ذلك ، لدى المحرك الشروط التالية:
- على استعداد للذهاب
- متصلا
- الجري (الغزل)
- حادث
- اتصال (حالة عابرة)
- الاغلاق (حالة عابرة)
ونتيجة لذلك ، يتم تمثيل كل "محرك" في النظام بواسطة ممثل يقوم بتنفيذ منطق التحولات بين الحالات ومعالجة الأحداث من أجهزة الاستشعار وإصدار أوامر التحكم. في sobjectizer ، يتم إنشاء الجهات الفاعلة بسهولة ، فقط ارث فصلك من الفئة الأساسية so_5 :: agent_t. في هذه الحالة ، يجب على المنشئ قبول ما يسمى بـ :: so_5 :: context_t السياق باعتباره الوسيطة الأولى ، ويتم تحديد الوسائط المتبقية حسب حاجة المطور.
class Drive_A: public so_5::agent_t { public: Drive_A( context_t ctx, ... ); ... }
بسبب هذه المقالة ليست تعليمية ، لذلك لن أقدم هنا نصوصًا مفصلة لأوصاف الفصول أو الأساليب. أراد المقال فقط أن يوضح مدى سهولة (في بضعة سطور) بمساعدة تطبيق sobjectizer ، كل هذا يتم تنفيذه. اسمحوا لي أن أذكركم بأن المشروع يحتوي على وثائق مفصلة ممتازة ، مع مجموعة من الأمثلة المختلفة.
وما هي "حالات" هذه الجهات الفاعلة؟ عن ماذا تتحدث
يعد استخدام الحالات والانتقالات بينها في ACS موضوعًا عامًا بشكل عام. يناسب هذا "المفهوم" جيدًا في التعامل مع الأحداث. في sobjectizer ، يتم دعم هذا المفهوم على مستوى API. في فئة الممثل ، يتم إعلان الولايات بسهولة إلى حد ما
class Drive_A final: public so_5::agent_t { public: Drive_A( context_t ctx, ... ); virtual ~Drive_A();
وكذلك بالنسبة لكل ولاية ، يحدد المطور المعالجات الضرورية. غالبًا ما تكون بعض الإجراءات مطلوبة عند الدخول إلى الدولة وعند الخروج منها. يتم توفير ذلك أيضًا في sobjectizer ، ويمكنك بسهولة تحديد معالجاتك لهذه الأحداث ("إدخال الحالة" ، "خروج الحالة"). هناك شعور بأن المطورين في الماضي يتمتعون بخبرة واسعة في مجال ACS-shny ...
معالجات الأحداث
معالجات الأحداث ، هذا هو المكان الذي يتم فيه تطبيق منطق التطبيق الخاص بك. كما ذكر أعلاه ، يتم الاشتراك في صندوق بريد محدد ولحالة معينة من الممثل. إذا لم يكن للممثل حالات معلن عنها صراحةً في الكود ، فهذا يعني ضمناً أنه في الحالة الخاصة "default_state". في حالات مختلفة ، يمكنك تحديد معالجات مختلفة لنفس الأحداث. إذا لم تحدد معالج أي حدث في صندوق البريد هذا ، فسيتم تجاهله ببساطة (أي أنه لن يكون موجودًا للممثل).
بناء الجملة لتعريف معالجات بسيط للغاية. يكفي أن تشير إلى وظيفتك. لا توجد أنواع أو وسيطات قالب مطلوبة. يتم استخلاص كل شيء تلقائيًا من تعريف الوظيفة. على سبيل المثال:
so_subscribe(drv->so_mbox()) .in(st_base) .event( &Drive_A::on_get_info ) .event( &Drive_A::on_control ) .event( &Drive_A::off_control );
فيما يلي مثال على الاشتراك في الأحداث في مربع معين لحالة st_base. ومن المثير للاهتمام ، في هذا المثال ، st_base هي الحالة الأساسية للحالات الأخرى ، وبالتالي سيكون هذا الاشتراك صالحًا لجميع الحالات "الموروثة" من st_base. تسمح لك هذه الطريقة بالتخلص من "نسخ اللصق" لتحديد نفس المعالجات للحالات المختلفة. في نفس الوقت ، في حالة معينة ، يمكنك إما تجاوز المعالج المحدد أو "تعطيله" (قمع).
هناك طريقة أخرى لتحديد معالجات. هذا هو التعريف المباشر لوظائف lambda. هذه طريقة مريحة للغاية ، لأن غالباً ما تكون معالجات وظائف قصيرة في عدة إجراءات أو إرسال شيء إلى شخص ما أو تبديل الحالة.
so_subscribe(drv->so_mbox()) .in(st_disconnecting) .event([this](const msg_disconnected_t& m) { ... st_off.activate(); }) .event([this]( const msg_failure_t& m ) { ... st_protection.activate(); });
في البداية ، يبدو بناء الجملة هذا معقدًا. ولكن في غضون بضعة أيام فقط من التطوير النشط ، تعتاد على ذلك وحتى تبدأ في الإعجاب به. لأن المنطق الكامل لعمل الممثل في حالة واحدة أو أخرى يمكن أن يتلاءم مع رمز قصير إلى حد ما وسيكون كل ذلك أمام عينيك. على سبيل المثال ، في المثال الموضح ، في الحالة المنفصلة (st_disconnecting) ، إما الانتقال إلى الحالة المنفصلة (st_off.) أو حالة الحماية (st_protection) تحدث في حالة حدوث رسالة حول نوع من الفشل. هذا الكود سهل القراءة.
بالمناسبة ، للحالات البسيطة عندما يحتاج حدث ما إلى الدخول في حالة ما ، يوجد بناء جملة أقصر:
auto mbox = drv->so_mbox(); st_off .just_switch_to<msg_connected_t>(mbox, st_connected) .just_switch_to<msg_failure_t>(mbox, st_protection) .just_switch_to<msg_on_limit_t>(mbox, st_protection) .just_switch_to<msg_on_t>(mbox, st_on);
الإدارة
كيف تعمل إدارة كل هذا الاقتصاد؟ كما ذكر أعلاه ، يتم توفير اثنين من أجهزة التحكم عن بعد للتحكم المباشر في حركة shtankets. يوجد على كل جهاز تحكم عن بعد جهاز عرض ومناولة (كرة التتبع) والاتصال الهاتفي السريع (بالإضافة إلى "جهاز الكمبيوتر" المخفي في جهاز التحكم عن بعد الذي يدور حوله كل شيء وكل أنواع المحولات). يحتوي النظام على عدة أوضاع للتحكم في حركة الشيتانكيت. دليل و "وضع البرنامج النصي". حول "وضع السيناريو" سيتم مناقشته أكثر ، والآن قليلاً حول "الوضع اليدوي". في هذا الوضع ، يختار المشغل الشانك المرغوب ، ويعده للحركة (يربط المحرك بالعاكس) ، ويحدد العلامة (الموضع المستهدف) للشانكيت ، وبمجرد أن يحدد السرعة أكبر من الصفر ، تبدأ السناخ في الحركة. لضبط السرعة ، يتم استخدام الضابط البدني الخاص ، في شكل "مقياس الجهد مع مقبض" ، ولكن هناك أيضا "الضابط الشاشة" للسرعة. أكثر "تحول" ، و بصوت أعلى يذهب بشكل أسرع. الحد الأقصى للسرعة يقتصر على 1.5 م / ث. مقبض السرعة - واحد للجميع. أي في الوضع اليدوي ، تتحرك جميع الأكشاك المتصلة بالمشغل بنفس السرعة المحددة. على الرغم من أنها يمكن أن تتحرك في اتجاهات مختلفة (يعتمد على مكان توجيه المشغل لهم). بالطبع ، يصعب على الشخص تتبع أكثر من اثنين أو ثلاثة شيتانكيت في نفس الوقت ، لذلك عادةً ما لا يتحرك كثيرًا في الوضع اليدوي. من محطتين ، يمكن للمشغلين أن يديروا في وقت واحد كل shtankets الخاصة بهم. بالإضافة إلى ذلك ، تحتوي كل وحدة تحكم (مشغل) على وحدة التحكم في السرعة الخاصة بها.
من وجهة نظر التنفيذ ، لا يحتوي الوضع اليدوي على أي منطق خاص. يأتي أمر توصيل المحرك من الواجهة الرسومية ، ويتم تحويله إلى رسالة إلى الممثل المقابل ، الذي يعمل عليه. المرور عبر الحالات "متوقف" -> "توصيل" -> "متصل". الشيء نفسه مع تحديد الموقف لحركة stunket وتحديد السرعة. كل هذه الأحداث تصل إلى الممثل في شكل رسائل يتفاعل معها. ما لم يكن من الممكن الإشارة إلى أن الواجهة الرسومية وعملية التحكم نفسها عبارة عن عمليات مختلفة ، وهناك تفاعل "interprocess" من خلال "أجهزة الاستشعار" باستخدام libuniset2 .
وضع تنفيذ البرنامج النصي (مرة أخرى ، هؤلاء الفاعلون؟)
في الواقع ، يتم استخدام وضع التحكم اليدوي بشكل أساسي فقط للتعليق أثناء البروفات أو في الحالات البسيطة. الوضع الرئيسي الذي يكون فيه عنصر التحكم قيد التقدم هو "وضع تنفيذ البرنامج النصي" أو ، باختصار ، "وضع البرنامج النصي". في هذا الوضع ، ينتقل كل shtank إلى نقطته مع المعلمات المحددة في البرنامج النصي (السرعة وعلامة الهدف). بالنسبة للمشغل ، يتكون التحكم في هذا الوضع من أمرين بسيطين:
- الاستعداد (المجموعة الصحيحة من المحركات متصلة)
- دعنا نذهب (تبدأ المجموعة في الانتقال إلى المواضع المستهدفة المحددة لكل منها).
وينقسم السيناريو كله إلى ما يسمى "جداول الأعمال". جدول الأعمال هو حركة واحدة لمجموعة shtanket. أي يشتمل كل جدول أعمال على مجموعة من shtankets ، مع السرعة المستهدفة والعلامة التجارية التي يجب أن تأتي. في الواقع ، يتم تقسيم البرنامج النصي إلى أعمال ، وتنقسم الأعمال إلى لوحات ، وتنقسم اللوحات إلى مذكرات استدعاء ، وتتألف مذكرات الاستدعاء بالفعل من "أهداف" لشيتانكيتات محددة. ولكن من وجهة نظر الإدارة ، هذا التقسيم ليس مهماً ، لأنه إنه على جدول الأعمال أن محددات الحركة محددة في النهاية.
لتنفيذ هذا النظام ، ظهر نظام الجهات الفاعلة مرة أخرى قدر الإمكان. تم تطوير "برنامج نصي" يقوم بإنشاء مجموعة من الجهات الفاعلة الخاصة وإطلاقها. لقد قمنا بتطوير نوعين من الجهات الفاعلة: الجهات الفاعلة - الجهات الفاعلة ، المصممة لأداء المهام لشيتنكيت معين ، وممثل منسق ، الذي يوزع المهام بين المؤدين. علاوة على ذلك ، يتم إنشاء الممثلين المنفذين عند الضرورة ، إذا كان وقت الفريق التالي غير مجاني. الفاعل المنسق هو المسؤول عن إنشاء والحفاظ على مجموعة من الممثلين المنفذين. نتيجة لذلك ، تبدو الإدارة شيئًا مثل هذا:
- بيان تحميل البرنامج النصي
- "اقلبها" إلى الأجندة المرغوبة (عادة ما يتم ذلك على التوالي).
- في اللحظة المناسبة ، تضغط على الزر "تحضير" ، والذي يتم من خلاله إرسال أمر (رسالة) إلى الفاعل المنسق لكل نموذج صغير مدرج في جدول الأعمال الحالي مع معلمات الحركة.
- ينظر الممثل المنسق إلى مجموعته من الممثلين ذوي الأداء المجاني ، ويأخذ ممثلًا مجانيًا (إذا لم يقم بإنشاء واحد جديد) ويعطيه مهمة (عدد من السيقان ومعلمات الحركة).
- يبدأ كل ممثل ممثل تلقى المهمة في تنفيذ أمر "الاستعداد". أي يربط المحرك ويدخل في وضع الاستعداد لأمر "go".
- عندما يحين الوقت ، يعطي المشغل الأمر "دعنا نذهب"
- فريق "الذهاب" يأتي إلى المنسق. يرسلها إلى جميع مؤدييه النشطين حاليًا ويبدأون "الإعدام".
تجدر الإشارة إلى أن هناك في جدول الأعمال معلمات إضافية. على سبيل المثال ، ابدأ الحركة بتأخير N ثانية أو ابدأ الحركة فقط بعد أمر مشغل خاص منفصل. لذلك ، قائمة الحالات لكل ممثل أداء كبيرة جدًا: "جاهز لتنفيذ الأمر التالي" ، "جاهز للتحرك" ، "تأخر الحركة" ، "انتظار أمر المشغل" ، "الحركة" ، "التنفيذ مكتمل" ، "عطل" .
بعد أن تصل الشانكيت (أو لا) بنجاح إلى العلامة المحددة ، يقوم الممثل المؤدي بإخطار منسق المهمة المكتملة. يعطي المنسق الأمر بإيقاف تشغيل هذا المحرك (إذا لم يعد يشارك في جدول الأعمال الحالي) أو يصدر معلمات حركة جديدة. بدوره ، تلقى الممثل المؤدي أمرًا بإيقاف تشغيل المحرك أو إيقاف تشغيله والانتقال إلى حالة انتظار للأوامر الجديدة ، أو البدء في تنفيذ أمر جديد.
نظرًا لحقيقة أن sobjectizer لديه واجهة برمجة تطبيقات مدروسة ومناسبة للعمل مع الدول ، فإن رمز التنفيذ هو موجز للغاية. على سبيل المثال ، يتم وصف التأخير في الحركة بسطر واحد:
st_delay.time_limit( std::chrono::milliseconds{target->delay()}, st_moving ); st_delay.activate(); ...
تحدد الدالة time_limit حدًا زمنيًا للمقدار الذي يمكن إنفاقه في حالة معينة وما الحالة التي يجب تمريرها بعد وقت محدد (st_moving).
ممثلو الحماية
بالطبع ، أثناء العملية ، يمكن أن تحدث أعطال. النظام مطلوب للتعامل مع هذه الحالات. هنا ، أيضًا ، كان هناك مكان لاستخدام الممثلين. النظر في العديد من هذه الحماية:
- أكثر من الحماية الحالية
- حماية فشل القياس
- حماية ضد الحركة في الاتجاه المعاكس (وهذا يمكن أن يكون ، إذا كان هناك شيء خاطئ مع الاستشعار أو العداد)
- حماية ضد الحركة دون أمر
- السيطرة على تنفيذ الفريق (التحكم في أن shtanket بدأت تتحرك)
يمكنك أن ترى أن جميع أشكال الحماية هذه مستقلة (مكتفية ذاتيا) من وجهة نظر التنفيذ ، ويجب أن تعمل "بالتوازي". أي أي حالة يمكن أن تعمل. في نفس الوقت ، يكون لمنطق التحقق من ظروف التشغيل لكل حماية حماية خاصة به ، وأحيانًا يكون هناك تأخير (مؤقت) مطلوب للتشغيل ، وأحيانًا تكون المعالجة الأولية لعدة قياسات سابقة مطلوبة ، إلخ. لذلك ، فإن تنفيذ كل نوع من أنواع الحماية كممثل صغير منفصل تبين أنه مناسب للغاية. يتم إطلاق كل هذه الجهات الفاعلة بالإضافة (بالتعاون) إلى الفاعل الرئيسي الذي ينفذ منطق التحكم. هذا النهج يجعل من السهل إضافة أنواع إضافية من الدفاعات ببساطة عن طريق إضافة ممثل آخر إلى المجموعة. في الوقت نفسه ، يظل تنفيذ مثل هذا الممثل سهلاً ومفهومًا إلى حد ما ، لأنه ينفذ وظيفة واحدة فقط.
الجهات الفاعلة الحماية لديها أيضا العديد من الدول. يتم تشغيلها (انتقل إلى حالة "التشغيل") فقط عندما يكون المحرك متصلاً أو يتحرك الساق. عندما يتم تشغيل شروط الحماية ، ينشرون إشعارًا بالحماية (مع رمز الأمان وبعض التفاصيل الخاصة بالتسجيل) ، ويستجيب الممثل الرئيسي بالفعل لهذا الإخطار ، والذي إذا كان ضروريًا ، يقوم بإيقاف تشغيل المحرك ويدخل وضع الحماية.
كخلاصة ..
... بالطبع هذا المقال ليس نوعًا من "الاكتشاف". منذ فترة طويلة تم استخدام نهج الممثل بنجاح في العديد من الأنظمة. لكن بالنسبة لي كانت هذه أول تجربة لاستخدام بفعالية مقاربة الممثل لبناء خوارزميات نظام التحكم في مشروع صغير نسبيًا. وكانت التجربة ناجحة جدا. آمل أن أتمكن من إظهار أن العناصر الفاعلة متراكبة جيدًا على خوارزميات التحكم ، فقد وجدوا مكانًا حرفيًا في كل مكان.
من تجربة المشروعات السابقة ، كان من الواضح أننا ننفذ بطريقة أو بأخرى "شيئًا من هذا القبيل" (الحالات ، الرسائل ، التحكم في التدفق ، إلخ) ، لكن هذا لم يكن نهجًا موحدًا. باستخدام أداة sobjectizer ، حصلنا على أداة تطوير موجزة وخفيفة الوزن تواجه الكثير من المشكلات. لم يعد من الضروري (صريحًا) استخدام أدوات المزامنة (المزامير ، إلخ) ، ولا يوجد عمل صريح مع التدفقات ، ولا تحقيقات لجهاز الحالة. كل هذا في الإطار ، مترابط منطقياً ويقدم كواجهة برمجة تطبيقات مريحة ، علاوة على ذلك ، دون فقدان السيطرة على التفاصيل. لذا كانت التجربة ممتعة. بالنسبة لأولئك الذين لا يزالون يشكون ، أوصي بإيلاء الاهتمام لنهج الممثل وإطار sobjectizer على وجه الخصوص. يترك عواطف إيجابية.
ونهج الممثل يعمل حقا! خاصة في المسرح.