مشروع تطبيقي: برمجة نظام تعبئة وتغليف آلي كامل
نظرة عامة على المشروع: نظام تعبئة آلي
في هذا الدرس الأخير، نُطبّق كل ما تعلمناه في مشروع واقعي: نظام تعبئة سوائل آلي يملأ زجاجات بكمية محددة، يُغلق الغطاء، ويعدّ الإنتاج.
مكونات النظام
┌──────────────────────────────────────────────────────┐
│ نظام التعبئة الآلي │
│ │
│ ┌─────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌─────┐ │
│ │دخول │→→→│تعبئة │→→→│إغلاق │→→→│ عدّ │→→→│خروج│ │
│ │الزجاجة│ │السائل│ │الغطاء│ │ وفرز │ │ │ │
│ └─────┘ └──────┘ └──────┘ └──────┘ └─────┘ │
│ ▲ ▲ ▲ ▲ │
│ حسّاس 1 صمام+حسّاس أسطوانة حسّاس 4 │
│ (قُرب) (مستوى) (هواء) (عدّاد) │
└──────────────────────────────────────────────────────┘
مراحل العمل
- الانتظار: السير يعمل حتى يكشف الحسّاس زجاجة
- التموضع: إيقاف السير وتثبيت الزجاجة
- التعبئة: فتح صمام السائل حتى يصل للمستوى المطلوب
- الإغلاق: تمديد أسطوانة إغلاق الغطاء
- الإخراج: تشغيل السير لإخراج الزجاجة وعدّها
تحليل المتطلبات: المداخل والمخارج
المداخل الرقمية (DI)
| الرقم | العنوان | الوصف | نوع المستشعر |
|---|---|---|---|
| 1 | I0.0 | زر بدء التشغيل | زر لحظي NO |
| 2 | I0.1 | زر الإيقاف | زر لحظي NC |
| 3 | I0.2 | إيقاف طوارئ | فطر أحمر NC |
| 4 | I0.3 | حسّاس دخول الزجاجة | قُرب حثّي PNP |
| 5 | I0.4 | حسّاس موضع التعبئة | قُرب حثّي PNP |
| 6 | I0.5 | حسّاس مستوى السائل | سعوي PNP |
| 7 | I0.6 | حسّاس الأسطوانة ممتدة | مغناطيسي |
| 8 | I0.7 | حسّاس الأسطوانة مرتدة | مغناطيسي |
| 9 | I1.0 | حسّاس عدّ الخروج | ضوئي PNP |
| 10 | I1.1 | حماية حرارية للسير | NC |
المخارج الرقمية (DO)
| الرقم | العنوان | الوصف | الحِمل |
|---|---|---|---|
| 1 | Q0.0 | محرك السير الناقل | كونتاكتور 2A |
| 2 | Q0.1 | صمام التعبئة | صمام 24VDC |
| 3 | Q0.2 | أسطوانة إغلاق الغطاء | صمام هواء 5/2 |
| 4 | Q0.3 | لمبة التشغيل (خضراء) | LED 24VDC |
| 5 | Q0.4 | لمبة العطل (حمراء) | LED 24VDC |
| 6 | Q0.5 | صافرة إنذار | 24VDC |
المداخل التناظرية (AI)
| الرقم | العنوان | الوصف | الإشارة |
|---|---|---|---|
| 1 | IW64 | وزن الزجاجة (خلية وزن) | 4-20mA |
تصميم البرنامج: المراحل والتسلسل
آلة الحالة الرئيسية
TYPE E_FillState :
(
ST_IDLE := 0, // خامل - انتظار أمر التشغيل
ST_READY := 10, // جاهز - السير يعمل
ST_BOTTLE_IN := 20, // زجاجة في موضع التعبئة
ST_FILLING := 30, // جاري التعبئة
ST_FILL_DONE := 40, // التعبئة اكتملت
ST_CAPPING := 50, // جاري إغلاق الغطاء
ST_CAP_DONE := 60, // الإغلاق اكتمل
ST_EJECT := 70, // إخراج الزجاجة
ST_FAULT := 99 // عطل
);
END_TYPE
مخطط التسلسل
IDLE ──(بدء)──→ READY ──(زجاجة)──→ BOTTLE_IN
▲ │
│ (تثبيت 500ms)
│ ▼
EJECT ←──(1s)── CAP_DONE ← CAPPING ← FILL_DONE ← FILLING
│ │
│ (حسّاس المستوى)
(حسّاس خروج)
│
▼
READY (دورة جديدة)
كتابة الكود: Structured Text للمراحل الرئيسية
PROGRAM FillingSystem
VAR
// حالة النظام
eState : E_FillState := ST_IDLE;
ePrevState : E_FillState;
// مداخل
bStartBtn : BOOL; // I0.0
bStopBtn : BOOL; // I0.1
bEStop : BOOL; // I0.2
bBottleEntry : BOOL; // I0.3
bBottleInPos : BOOL; // I0.4
bLevelFull : BOOL; // I0.5
bCylExtended : BOOL; // I0.6
bCylRetracted : BOOL; // I0.7
bExitSensor : BOOL; // I1.0
bThermalOK : BOOL; // I1.1
// مخارج
bConveyor : BOOL; // Q0.0
bFillValve : BOOL; // Q0.1
bCapCylinder : BOOL; // Q0.2
bGreenLamp : BOOL; // Q0.3
bRedLamp : BOOL; // Q0.4
bBuzzer : BOOL; // Q0.5
// تناظري
iRawWeight : INT; // IW64
rBottleWeight : REAL;
// مؤقتات
fbSettleTimer : TON; // استقرار الزجاجة
fbFillTimeout : TON; // مهلة التعبئة
fbCapTimeout : TON; // مهلة الإغلاق
fbEjectTimer : TON; // زمن الإخراج
fbBuzzerPulse : TP; // نبضة الصافرة
// عدّادات
fbBottleCount : CTU; // عدّاد الزجاجات
diTotalBottles : DINT; // إجمالي الإنتاج
diBatchCount : DINT; // عدد الدفعات
// إعدادات (قابلة للتعديل من HMI)
tSettleTime : TIME := T#500ms;
tFillTimeout : TIME := T#15s;
tCapTimeout : TIME := T#5s;
tEjectTime : TIME := T#1s;
iBatchSize : INT := 24;
rTargetWeight : REAL := 500.0; // غرام
END_VAR
// ═══════════════════════════════════════════
// حماية الطوارئ (تُنفّذ دائماً بغض النظر عن الحالة)
// ═══════════════════════════════════════════
IF bEStop OR NOT bThermalOK THEN
eState := ST_FAULT;
END_IF;
// ═══════════════════════════════════════════
// قراءة الوزن التناظري
// ═══════════════════════════════════════════
rBottleWeight := FC_ScaleAnalog(
iRawValue := iRawWeight,
rEngMin := 0.0,
rEngMax := 1000.0
);
// ═══════════════════════════════════════════
// آلة الحالة الرئيسية
// ═══════════════════════════════════════════
CASE eState OF
// ─── خامل: انتظار أمر التشغيل ───
ST_IDLE:
bConveyor := FALSE;
bFillValve := FALSE;
bCapCylinder := FALSE;
IF bStartBtn AND NOT bEStop AND bThermalOK THEN
eState := ST_READY;
END_IF;
// ─── جاهز: السير يعمل ───
ST_READY:
bConveyor := TRUE;
bFillValve := FALSE;
bCapCylinder := FALSE;
IF bStopBtn THEN
eState := ST_IDLE;
END_IF;
IF bBottleInPos THEN
eState := ST_BOTTLE_IN;
END_IF;
// ─── زجاجة في الموضع: إيقاف وانتظار الاستقرار ───
ST_BOTTLE_IN:
bConveyor := FALSE;
fbSettleTimer(IN := TRUE, PT := tSettleTime);
IF fbSettleTimer.Q THEN
fbSettleTimer(IN := FALSE);
eState := ST_FILLING;
END_IF;
// ─── التعبئة: فتح الصمام ───
ST_FILLING:
bFillValve := TRUE;
fbFillTimeout(IN := TRUE, PT := tFillTimeout);
// اكتملت التعبئة
IF bLevelFull OR (rBottleWeight >= rTargetWeight) THEN
bFillValve := FALSE;
fbFillTimeout(IN := FALSE);
eState := ST_FILL_DONE;
END_IF;
// تجاوز المهلة
IF fbFillTimeout.Q THEN
bFillValve := FALSE;
fbFillTimeout(IN := FALSE);
eState := ST_FAULT;
END_IF;
// ─── التعبئة اكتملت: انتقل للإغلاق ───
ST_FILL_DONE:
bFillValve := FALSE;
eState := ST_CAPPING;
// ─── إغلاق الغطاء ───
ST_CAPPING:
bCapCylinder := TRUE;
fbCapTimeout(IN := TRUE, PT := tCapTimeout);
IF bCylExtended THEN
fbCapTimeout(IN := FALSE);
eState := ST_CAP_DONE;
END_IF;
IF fbCapTimeout.Q THEN
fbCapTimeout(IN := FALSE);
eState := ST_FAULT;
END_IF;
// ─── الإغلاق اكتمل: ارجع الأسطوانة ───
ST_CAP_DONE:
bCapCylinder := FALSE;
IF bCylRetracted THEN
eState := ST_EJECT;
END_IF;
// ─── إخراج الزجاجة ───
ST_EJECT:
bConveyor := TRUE;
fbEjectTimer(IN := TRUE, PT := tEjectTime);
IF fbEjectTimer.Q AND NOT bBottleInPos THEN
fbEjectTimer(IN := FALSE);
diTotalBottles := diTotalBottles + 1;
eState := ST_READY;
END_IF;
// ─── عطل ───
ST_FAULT:
bConveyor := FALSE;
bFillValve := FALSE;
bCapCylinder := FALSE;
// إعادة ضبط بعد زوال سبب العطل
IF bStartBtn AND NOT bEStop AND bThermalOK THEN
eState := ST_IDLE;
END_IF;
END_CASE;
// ═══════════════════════════════════════════
// المخارج العامة
// ═══════════════════════════════════════════
bGreenLamp := (eState <> ST_IDLE) AND (eState <> ST_FAULT);
bRedLamp := (eState = ST_FAULT);
fbBuzzerPulse(IN := (eState = ST_FAULT), PT := T#2s);
bBuzzer := fbBuzzerPulse.Q;
// عدّاد الدفعات
IF diTotalBottles MOD iBatchSize = 0 AND diTotalBottles > 0 THEN
diBatchCount := diTotalBottles / iBatchSize;
END_IF;
شاشة HMI: واجهة المشغّل
الشاشة الرئيسية
┌────────────────────────────────────────────┐
│ نظام التعبئة الآلي - Dr.Machine │
├────────────────────────────────────────────┤
│ │
│ الحالة: [██ جاري التعبئة ██] │
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ الوزن │ │ العدد │ │الدفعات │ │
│ │ 485 غ │ │ 156 │ │ 6 │ │
│ └────────┘ └────────┘ └────────┘ │
│ │
│ السير: ██ يعمل الصمام: □ مغلق │
│ الأسطوانة: □ مرتدة الحرارة: ✓ طبيعي │
│ │
│ [ بدء ] [ إيقاف ] [ إعدادات ] │
├────────────────────────────────────────────┤
│ آخر إنذار: لا يوجد 14:32:05 │
└────────────────────────────────────────────┘
متغيرات HMI الأساسية
// للعرض على الشاشة
VAR_GLOBAL
iHMI_State : INT; // رقم الحالة
sHMI_StateName : STRING(30); // اسم الحالة بالعربية
rHMI_Weight : REAL; // الوزن الحالي
diHMI_TotalCount : DINT; // إجمالي الإنتاج
diHMI_BatchCount : DINT; // عدد الدفعات
rHMI_PartsPerMin : REAL; // معدل الإنتاج
END_VAR
// أسماء الحالات للعرض
CASE eState OF
ST_IDLE: sHMI_StateName := 'خامل';
ST_READY: sHMI_StateName := 'جاهز';
ST_FILLING: sHMI_StateName := 'جاري التعبئة';
ST_CAPPING: sHMI_StateName := 'إغلاق الغطاء';
ST_EJECT: sHMI_StateName := 'إخراج';
ST_FAULT: sHMI_StateName := 'عطل!';
END_CASE;
الاختبار والتشغيل التجريبي
مراحل الاختبار
اختبار المداخل/المخارج (I/O Test)
قبل تشغيل البرنامج، تحقق من كل مدخل ومخرج يدوياً:
قائمة فحص I/O:
□ I0.0: اضغط زر البدء → LED يضيء في جدول المراقبة
□ I0.1: اضغط زر الإيقاف → LED يضيء
□ I0.2: فعّل الطوارئ → LED يضيء
□ I0.3: ضع جسم أمام حسّاس الدخول → LED يضيء
□ I0.4: ضع جسم أمام حسّاس الموضع → LED يضيء
□ Q0.0: فعّل من جدول المراقبة → السير يعمل
□ Q0.1: فعّل من جدول المراقبة → الصمام يفتح
□ Q0.2: فعّل من جدول المراقبة → الأسطوانة تمتد
اختبار التسلسل خطوة بخطوة
// وضع الاختبار اليدوي: تقدّم خطوة بخطوة
VAR
bManualMode : BOOL; // تفعيل الوضع اليدوي
bStepForward : BOOL; // تقدّم للمرحلة التالية
END_VAR
IF bManualMode AND bStepForward THEN
CASE eState OF
ST_IDLE: eState := ST_READY;
ST_READY: eState := ST_BOTTLE_IN;
ST_BOTTLE_IN: eState := ST_FILLING;
ST_FILLING: eState := ST_FILL_DONE;
ST_FILL_DONE: eState := ST_CAPPING;
ST_CAPPING: eState := ST_CAP_DONE;
ST_CAP_DONE: eState := ST_EJECT;
ST_EJECT: eState := ST_READY;
END_CASE;
END_IF;
قائمة التحقق قبل التشغيل النهائي
□ جميع حسّاسات الطوارئ تعمل وتوقف النظام فوراً
□ الحماية الحرارية للمحرك مضبوطة على التيار الصحيح
□ المهلات الزمنية (Timeouts) مناسبة لسرعة الخط الفعلية
□ ضغط الهواء كافٍ لتشغيل الأسطوانة
□ الصمام يُغلق تماماً (لا تسريب)
□ العدّاد يعدّ بشكل صحيح
□ شاشة HMI تعرض جميع البيانات بشكل صحيح
□ الإنذارات تظهر وتُسجّل
□ وضع الاختبار اليدوي يعمل
□ النسخة الاحتياطية محفوظة
الخلاصة والخطوات القادمة
في هذه السلسلة من 12 درساً، غطّينا أساسيات برمجة PLC من المفاهيم الأولية إلى مشروع تعبئة متكامل:
- الدروس 1-2: مفهوم PLC ومكوناته المادية
- الدروس 3-4: لغتا البرمجة الأساسيتان (Ladder Logic و Structured Text)
- الدروس 5-7: أنواع البيانات والمؤقتات والكتل الوظيفية
- الدروس 8-9: المعالجة التناظرية والتحكم بالمحركات
- الدروس 10-11: الاتصالات الصناعية وتشخيص الأعطال
- الدرس 12: مشروع تطبيقي متكامل
للتعمّق أكثر
- التحكم PID: ضبط الحرارة والضغط والتدفق بدقة
- شبكات الأمان: Safety PLC ومعايير SIL/ISO 13849
- SCADA: أنظمة المراقبة والتحكم عن بعد
- Industry 4.0: ربط PLC بالسحابة وتحليل البيانات
- الروبوتات الصناعية: التكامل بين PLC والروبوت
المعرفة النظرية مهمة، لكن الخبرة الحقيقية تأتي من الممارسة العملية. ابدأ بمشاريع صغيرة وتدرّج في التعقيد.