From d1088710af66279f879dad5c6ef821e91e4f1e06 Mon Sep 17 00:00:00 2001 From: Dejan Date: Tue, 24 Feb 2026 11:54:19 +0000 Subject: [PATCH] Upload files to "s7-1500" --- s7-1500/FB_WeldSequencer.scl | 768 +++++++++++++++++++++++++++++++++++ 1 file changed, 768 insertions(+) create mode 100644 s7-1500/FB_WeldSequencer.scl diff --git a/s7-1500/FB_WeldSequencer.scl b/s7-1500/FB_WeldSequencer.scl new file mode 100644 index 0000000..cbd9610 --- /dev/null +++ b/s7-1500/FB_WeldSequencer.scl @@ -0,0 +1,768 @@ +(*═══════════════════════════════════════════════════════════════════════════════ + FB_WeldSequencer + S7-1500 SCL — 10-Step Robotic Welding Cell Sequencer + TIA Portal V18+ | Optimized Block Access + ───────────────────────────────────────────────────────────────────────────── + APPLICATION: MIG/MAG Welding Cell — Clamp → Weld → Release cycle + ───────────────────────────────────────────────────────────────────────────── + + MODES: + AUTO — Steps advance automatically the moment advance condition is met + INCR — Operator must press Cmd_Incr AFTER advance condition is TRUE + (used for commissioning, fault recovery, or slow-speed prove-out) + + SEQUENCER STATES (SeqState output INT): + 0 = IDLE Waiting for Start command + 1 = RUNNING Sequence actively executing + 2 = PAUSED Outputs held; resumes from same step on Cmd_Start + 3 = STOPPING_CAT1 Controlled stop: current step finishes then halts + 4 = STOPPED CAT1/CAT2 halt complete; Reset required + 5 = FAULTED Hard fault; safety interlock; Reset + clear required + 6 = COMPLETE All 10 steps done; awaiting restart or Reset + + STOP CATEGORIES (IEC 60204-1): + CAT0 Immediate: ALL outputs de-energised instantly + Trigger: Cmd_EStop = TRUE AND StopCategory = 0 + CAT1 Controlled: current step completes its "safe motion" then stops. + A 10 s timeout (CAT1_TIMEOUT) guards against stuck conditions. + Trigger: Cmd_EStop = TRUE AND StopCategory = 1 + CAT2 Suspend & hold: outputs frozen at current state until Reset + Trigger: Cmd_Stop (always CAT2) + Cmd_EStop = TRUE AND StopCategory = 2 + + PAUSE vs STOP: + PAUSE — Soft, temporary. Cmd_Pause latches PAUSED state. All outputs held. + Cmd_Start resumes from same step / same position. + Safety interlock (door open) will NOT allow resume. + STOP — CAT2 permanent hold. Requires Cmd_Reset to return to IDLE. + Typically used for planned end-of-shift or material change. + + STEP FEATURES: + _stepEnabled[N] = FALSE → step is silently skipped every cycle + _stepSafetyLocked[N] = TRUE → operator Cmd_SkipStep is ignored + Cmd_SkipStep (rising edge) → forces advance on UN-locked steps only + _stepUseTimer[N] = TRUE → advance on timer expiry (no sensor required) + _stepTimerPreset[N] → IEC time preset for timer steps + + FAULT CODES (FaultCode output INT): + 0 No fault + 10 Safety door opened during run / pause + 11 E-Stop activated (CAT0/1/2 determined by StopCategory) + 20 CAT1 controlled-stop timeout (step overran CAT1_TIMEOUT) + 30 Sensor conflict: FWD + BWD sensors simultaneously TRUE + 40 Step watchdog timeout: step did not complete in WATCHDOG_TIME + + I/O SUMMARY — WELDING CELL: + ┌──────┬──────────────────────────┬──────────────┬────────────────────────────┐ + │ Step │ Name │ Advance │ Sensors / Timers │ + ├──────┼──────────────────────────┼──────────────┼────────────────────────────┤ + │ 1 │ Home Position Verify │ 2 Sensors │ Sen_HomeFwd + NOT HomeBwd │ + │ 2 │ Clamp Workpiece │ 1 Sensor │ Sen_ClampClosed │ + │ 3 │ Extend Weld Head │ 1 Sensor FWD │ Sen_HeadAtWeldPos (FWD) │ + │ │ │ (2 declared) │ Sen_HeadRetracted (BWD) │ + │ 4 │ Pre-Purge Gas │ Timer 2.0 s │ None │ + │ 5 │ Arc Strike │ 1 Sensor │ Sen_ArcDetect 🔒LOCKED │ + │ 6 │ Weld Travel │ Timer 4.0 s │ None │ + │ 7 │ Arc Off / Weld End │ 1 Sensor │ Sen_ArcOff 🔒LOCKED │ + │ 8 │ Post-Purge Gas │ Timer 2.5 s │ None │ + │ 9 │ Retract Weld Head │ 1 Sensor BWD │ Sen_HeadRetracted (BWD) │ + │ │ │ (2 declared) │ Sen_HeadAtWeldPos (FWD) │ + │ 10 │ Unclamp / Part Eject │ 1 Sensor │ Sen_UnclampConf │ + └──────┴──────────────────────────┴──────────────┴────────────────────────────┘ + 🔒 Safety-locked: Step 1 (home verify), Step 5 (arc confirm), Step 7 (arc off) +═══════════════════════════════════════════════════════════════════════════════*) + +FUNCTION_BLOCK "FB_WeldSequencer" +{ S7_Optimized_Access := 'TRUE' } +VERSION : 0.1 + +VAR_INPUT + //── MODE SELECTION ────────────────────────────────────────────────────── + Mode_Auto : Bool; // TRUE = Automatic continuous advance + Mode_Incr : Bool; // TRUE = Increment step-by-step mode + + //── OPERATOR COMMANDS (all rising-edge triggered unless noted) ────────── + Cmd_Start : Bool; // Start cycle / Resume after Pause + Cmd_Pause : Bool; // Pause: hold outputs, resume same step + Cmd_Stop : Bool; // CAT2 Stop: hold & require Reset + Cmd_EStop : Bool; // E-Stop: level signal (TRUE = activated) + Cmd_Reset : Bool; // Clear fault / return to IDLE + Cmd_Incr : Bool; // Increment next step (INCR mode only) + Cmd_SkipStep : Bool; // Skip current step if not safety-locked + StopCategory : Int; // E-Stop category: 0=CAT0, 1=CAT1, 2=CAT2 + + //── SAFETY MONITORING ─────────────────────────────────────────────────── + Safety_DoorClosed : Bool; // Safety gate (NC contact, TRUE = closed/safe) + Safety_EStopOK : Bool; // Safety relay feedback (TRUE = no E-Stop) + + //── PROCESS SENSORS (DI) ──────────────────────────────────────────────── + // STEP 1 — Home Position [2 sensors] + Sen_HomeFwd : Bool; // Fixture confirmed at home position + Sen_HomeBwd : Bool; // Fixture NOT in work zone (interlock sensor) + + // STEP 2 — Clamp [1 sensor] + Sen_ClampClosed : Bool; // Clamp jaw fully closed on part + + // STEP 3 + 9 — Weld Head [2 sensors: FWD + BWD shared] + Sen_HeadAtWeldPos : Bool; // Head fully EXTENDED to weld start position + Sen_HeadRetracted : Bool; // Head fully RETRACTED to safe position + + // STEP 5 — Arc Strike [1 sensor] + Sen_ArcDetect : Bool; // Welding arc current detected (TRUE = arc ON) + + // STEP 7 — Arc Off [1 sensor] + Sen_ArcOff : Bool; // Arc current extinguished (TRUE = arc OFF) + + // STEP 10 — Unclamp [1 sensor] + Sen_UnclampConf : Bool; // Clamp fully open / part cleared +END_VAR + +VAR_OUTPUT + //── ACTUATORS (DQ) ────────────────────────────────────────────────────── + Act_Clamp : Bool; // Step 2–9: Clamp solenoid (energise = clamp) + Act_HeadExtend : Bool; // Step 3–8: Weld head extend solenoid + Act_HeadRetract : Bool; // Step 9: Weld head retract solenoid + Act_GasValve : Bool; // Step 4–8: Shielding gas solenoid valve + Act_WeldEnable : Bool; // Step 5–6: Welder power enable + Act_Unclamp : Bool; // Step 10: Unclamp solenoid + Act_PartEject : Bool; // Step 10: Part ejector cylinder + + //── SEQUENCER STATUS ──────────────────────────────────────────────────── + Seq_Idle : Bool; // State = IDLE + Seq_Running : Bool; // State = RUNNING + Seq_Paused : Bool; // State = PAUSED + Seq_Stopping : Bool; // State = STOPPING_CAT1 + Seq_Stopped : Bool; // State = STOPPED + Seq_Faulted : Bool; // State = FAULTED + Seq_Complete : Bool; // State = COMPLETE + + ActiveStep : Int; // Currently executing step (0 = none) + SeqState : Int; // Numeric state code (see header) + FaultCode : Int; // Active fault code (0 = no fault) + StepAdvanceReady : Bool; // TRUE when advance condition is satisfied + IncrWaiting : Bool; // TRUE in INCR mode, condition met, waiting Incr + CycleCount : DInt; // Completed cycle counter (persistent) +END_VAR + +VAR + //── INTERNAL STATE ────────────────────────────────────────────────────── + _state : Int; // Sequencer state machine current state + _activeStep : Int; // Active step number (1..10, 0=none) + _stepAdvReady : Bool; // Advance condition for current step + + //── STEP CONFIGURATION ARRAYS [1..10] ─────────────────────────────────── + _stepEnabled : Array[1..10] OF Bool; // FALSE = disabled/skip + _stepSafetyLocked : Array[1..10] OF Bool; // TRUE = SkipStep ignored + _stepUseTimer : Array[1..10] OF Bool; // TRUE = timer-based advance + _stepTimerPreset : Array[1..10] OF Time; // Timer preset (relevant if above) + + //── TIMERS ────────────────────────────────────────────────────────────── + _stepTimer : Array[1..10] OF TON; // Per-step IEC timer + _stepWatchdog : Array[1..10] OF TON; // Per-step watchdog timeout + _cat1Timer : TON; // CAT1 controlled-stop guard timer + + //── EDGE DETECTION (previous scan values) ─────────────────────────────── + _prevStart : Bool; + _prevPause : Bool; + _prevStop : Bool; + _prevReset : Bool; + _prevIncr : Bool; + _prevSkip : Bool; + _prevEStop : Bool; + + //── LATCHED FLAGS ─────────────────────────────────────────────────────── + _incrRequest : Bool; // Latched: set on rising Cmd_Incr edge + _cat1InProgress : Bool; // TRUE during CAT1 controlled-stop sequence + _forceAdvance : Bool; // Set by SkipStep to force one advance + + //── MISCELLANEOUS ─────────────────────────────────────────────────────── + _initDone : Bool; // First-scan initialisation flag + _i : Int; // Loop variable +END_VAR + +VAR_TEMP + //── RISING-EDGE PULSES (computed each scan) ───────────────────────────── + rStart : Bool; + rPause : Bool; + rStop : Bool; + rReset : Bool; + rIncr : Bool; + rSkip : Bool; + rEStop : Bool; + nextStep : Int; // Working variable for step advance +END_VAR + +VAR CONSTANT + //── STATE CONSTANTS ───────────────────────────────────────────────────── + STATE_IDLE : Int := 0; + STATE_RUNNING : Int := 1; + STATE_PAUSED : Int := 2; + STATE_STOPPING_CAT1 : Int := 3; + STATE_STOPPED : Int := 4; + STATE_FAULTED : Int := 5; + STATE_COMPLETE : Int := 6; + + //── SEQUENCE LIMITS ───────────────────────────────────────────────────── + FIRST_STEP : Int := 1; + LAST_STEP : Int := 10; + + //── TIMING CONSTANTS ──────────────────────────────────────────────────── + CAT1_TIMEOUT : Time := T#10S; // Max time for CAT1 controlled stop + WATCHDOG_TIME : Time := T#30S; // Max time any step may take +END_VAR + +BEGIN +(*═══════════════════════════════════════════════════════════════════════════ + ░░ S E C T I O N 1 — F I R S T - S C A N I N I T I A L I S A T I O N ░░ +═══════════════════════════════════════════════════════════════════════════*) +IF NOT _initDone THEN + + FOR _i := 1 TO 10 DO + _stepEnabled[_i] := TRUE; // All steps ON by default + _stepSafetyLocked[_i] := FALSE; + _stepUseTimer[_i] := FALSE; + _stepTimerPreset[_i] := T#0S; + END_FOR; + + //── Safety-locked steps (operator Cmd_SkipStep has NO effect) ─────────── + // Step 1: Home verify — must confirm safe start position + // Step 5: Arc strike — arc MUST be detected before weld travel + // Step 7: Arc off — arc MUST be extinguished before gas purge ends + _stepSafetyLocked[1] := TRUE; + _stepSafetyLocked[5] := TRUE; + _stepSafetyLocked[7] := TRUE; + + //── Timer-advance steps (no sensor required) ──────────────────────────── + _stepUseTimer[4] := TRUE; _stepTimerPreset[4] := T#2S; // Pre-purge + _stepUseTimer[6] := TRUE; _stepTimerPreset[6] := T#4S; // Weld travel + _stepUseTimer[8] := TRUE; _stepTimerPreset[8] := T#2500MS; // Post-purge + + _state := STATE_IDLE; + _activeStep := 0; + _initDone := TRUE; +END_IF; + +(*═══════════════════════════════════════════════════════════════════════════ + ░░ S E C T I O N 2 — E D G E D E T E C T I O N ░░ +═══════════════════════════════════════════════════════════════════════════*) +rStart := Cmd_Start AND NOT _prevStart; +rPause := Cmd_Pause AND NOT _prevPause; +rStop := Cmd_Stop AND NOT _prevStop; +rReset := Cmd_Reset AND NOT _prevReset; +rIncr := Cmd_Incr AND NOT _prevIncr; +rSkip := Cmd_SkipStep AND NOT _prevSkip; +rEStop := Cmd_EStop AND NOT _prevEStop; // Rising edge for event logging + +_prevStart := Cmd_Start; +_prevPause := Cmd_Pause; +_prevStop := Cmd_Stop; +_prevReset := Cmd_Reset; +_prevIncr := Cmd_Incr; +_prevSkip := Cmd_SkipStep; +_prevEStop := Cmd_EStop; + +// Latch increment request — consumed when step actually advances +IF rIncr THEN + _incrRequest := TRUE; +END_IF; + +// Skip step — latch if current step is NOT safety-locked +IF rSkip AND (_activeStep >= FIRST_STEP) THEN + IF NOT _stepSafetyLocked[_activeStep] THEN + _forceAdvance := TRUE; + END_IF; +END_IF; + +(*═══════════════════════════════════════════════════════════════════════════ + ░░ S E C T I O N 3 — S A F E T Y M O N I T O R I N G ░░ + Evaluated EVERY SCAN and takes priority over state machine +═══════════════════════════════════════════════════════════════════════════*) + +// ── E-Stop (level-triggered, highest priority) ───────────────────────── +IF Cmd_EStop OR NOT Safety_EStopOK THEN + IF NOT _cat1InProgress THEN // Prevent re-entry if already handling + CASE StopCategory OF + 0: // CAT0 — Immediate de-energise (outputs cleared in Section 6) + _state := STATE_FAULTED; + FaultCode := 11; + + 1: // CAT1 — Allow current step to reach safe state, then stop + _cat1InProgress := TRUE; + _state := STATE_STOPPING_CAT1; + FaultCode := 11; + + 2: // CAT2 — Freeze outputs where they are + _state := STATE_STOPPED; + FaultCode := 11; + + ELSE: + _state := STATE_FAULTED; // Unknown category → safe fault + FaultCode := 11; + END_CASE; + END_IF; +END_IF; + +// ── Safety door opened while running or paused ───────────────────────── +IF NOT Safety_DoorClosed THEN + IF _state = STATE_RUNNING OR _state = STATE_PAUSED THEN + _state := STATE_FAULTED; + FaultCode := 10; + END_IF; +END_IF; + +// ── Sensor conflict: FWD and BWD sensors both TRUE simultaneously ────── +IF Sen_HeadAtWeldPos AND Sen_HeadRetracted THEN + IF _state = STATE_RUNNING OR _state = STATE_STOPPING_CAT1 THEN + _state := STATE_FAULTED; + FaultCode := 30; + END_IF; +END_IF; + +(*═══════════════════════════════════════════════════════════════════════════ + ░░ S E C T I O N 4 — M A I N S T A T E M A C H I N E ░░ +═══════════════════════════════════════════════════════════════════════════*) +CASE _state OF + + //────────────────────────────────────────────────────────────────────── + // STATE 0: IDLE — Waiting for Start + //────────────────────────────────────────────────────────────────────── + STATE_IDLE: + _activeStep := 0; + _cat1InProgress := FALSE; + _incrRequest := FALSE; + _forceAdvance := FALSE; + + // Start only if safety circuit is healthy + IF rStart AND Safety_DoorClosed AND Safety_EStopOK AND (FaultCode = 0) THEN + // Find first enabled step + nextStep := FIRST_STEP; + WHILE nextStep <= LAST_STEP AND NOT _stepEnabled[nextStep] DO + nextStep := nextStep + 1; + END_WHILE; + IF nextStep <= LAST_STEP THEN + _activeStep := nextStep; + _state := STATE_RUNNING; + END_IF; + END_IF; + + //────────────────────────────────────────────────────────────────────── + // STATE 1: RUNNING — Sequence executing + //────────────────────────────────────────────────────────────────────── + STATE_RUNNING: + + // Pause request + IF rPause THEN + _state := STATE_PAUSED; + END_IF; + + // CAT2 Stop request + IF rStop THEN + _state := STATE_STOPPED; + END_IF; + + // ── Step advance logic ──────────────────────────────────────────── + // Advance condition: sensor/timer TRUE OR forced skip + IF _stepAdvReady OR _forceAdvance THEN + + _forceAdvance := FALSE; + + // INCR mode: advance condition met — wait for operator Incr + // AUTO mode: advance immediately + IF Mode_Incr AND NOT _incrRequest THEN + // Stay on current step — IncrWaiting will be TRUE (see outputs) + ; + ELSE + // Consume the increment request + _incrRequest := FALSE; + + // Find next enabled step + nextStep := _activeStep + 1; + WHILE nextStep <= LAST_STEP AND NOT _stepEnabled[nextStep] DO + nextStep := nextStep + 1; + END_WHILE; + + IF nextStep > LAST_STEP THEN + // All steps complete + _state := STATE_COMPLETE; + _activeStep := 0; + CycleCount := CycleCount + 1; + ELSE + _activeStep := nextStep; + END_IF; + END_IF; + END_IF; + + //────────────────────────────────────────────────────────────────────── + // STATE 2: PAUSED — Outputs held, awaiting resume + //────────────────────────────────────────────────────────────────────── + STATE_PAUSED: + // Resume requires door still closed (re-check safety) + IF rStart AND Safety_DoorClosed AND Safety_EStopOK THEN + _state := STATE_RUNNING; + END_IF; + + IF rStop THEN + _state := STATE_STOPPED; + END_IF; + + //────────────────────────────────────────────────────────────────────── + // STATE 3: STOPPING_CAT1 — Controlled stop; current step finishes + //────────────────────────────────────────────────────────────────────── + STATE_STOPPING_CAT1: + + // CAT1 guard timer — prevents infinite hang + _cat1Timer(IN := TRUE, PT := CAT1_TIMEOUT); + + // Step logic still runs (see Section 5) to allow safe motion to complete + // Advance to STOPPED when step condition met OR timeout + IF _stepAdvReady THEN + _state := STATE_STOPPED; + _activeStep := 0; + _cat1InProgress := FALSE; + _cat1Timer(IN := FALSE, PT := CAT1_TIMEOUT); + + ELSIF _cat1Timer.Q THEN + // Timeout — step did not complete safely + FaultCode := 20; + _state := STATE_FAULTED; + _cat1InProgress := FALSE; + _cat1Timer(IN := FALSE, PT := CAT1_TIMEOUT); + END_IF; + + //────────────────────────────────────────────────────────────────────── + // STATE 4: STOPPED — Requires Reset to return to IDLE + //────────────────────────────────────────────────────────────────────── + STATE_STOPPED: + // Safe state: weld outputs cleared in Section 6 + IF rReset AND NOT Cmd_EStop AND Safety_EStopOK THEN + FaultCode := 0; + _activeStep := 0; + _state := STATE_IDLE; + END_IF; + + //────────────────────────────────────────────────────────────────────── + // STATE 5: FAULTED — Hard stop; all outputs cleared (CAT0 / safety fault) + //────────────────────────────────────────────────────────────────────── + STATE_FAULTED: + // Reset only when E-Stop cleared, door closed, and reset pressed + IF rReset AND NOT Cmd_EStop AND Safety_EStopOK AND Safety_DoorClosed THEN + FaultCode := 0; + _activeStep := 0; + _state := STATE_IDLE; + END_IF; + + //────────────────────────────────────────────────────────────────────── + // STATE 6: COMPLETE — Cycle finished + //────────────────────────────────────────────────────────────────────── + STATE_COMPLETE: + IF rStart AND Safety_DoorClosed AND Safety_EStopOK THEN + // Start new cycle + nextStep := FIRST_STEP; + WHILE nextStep <= LAST_STEP AND NOT _stepEnabled[nextStep] DO + nextStep := nextStep + 1; + END_WHILE; + IF nextStep <= LAST_STEP THEN + _activeStep := nextStep; + _state := STATE_RUNNING; + END_IF; + END_IF; + IF rReset THEN + _activeStep := 0; + _state := STATE_IDLE; + END_IF; + +END_CASE; // Main state machine + +(*═══════════════════════════════════════════════════════════════════════════ + ░░ S E C T I O N 5 — S T E P E X E C U T I O N ░░ + Outputs built up here. All output vars cleared to FALSE first, + then each active step energises what it needs. + This ensures outputs drop when step changes — no "stuck on" risk. +═══════════════════════════════════════════════════════════════════════════*) + +// ── Clear all actuator outputs every scan (re-energised by step logic) ── +Act_Clamp := FALSE; +Act_HeadExtend := FALSE; +Act_HeadRetract:= FALSE; +Act_GasValve := FALSE; +Act_WeldEnable := FALSE; +Act_Unclamp := FALSE; +Act_PartEject := FALSE; +_stepAdvReady := FALSE; + +// ── Step logic only active during RUNNING or STOPPING_CAT1 ────────────── +IF _state = STATE_RUNNING OR _state = STATE_STOPPING_CAT1 THEN + + IF _activeStep >= FIRST_STEP AND _activeStep <= LAST_STEP THEN + + //── Per-step timers ───────────────────────────────────────────────── + // IN driven by (activeStep = this step AND running) — auto-resets on step change + _stepTimer[1](IN := (_activeStep = 1 AND _state = STATE_RUNNING), PT := _stepTimerPreset[1]); + _stepTimer[2](IN := (_activeStep = 2 AND _state = STATE_RUNNING), PT := _stepTimerPreset[2]); + _stepTimer[3](IN := (_activeStep = 3 AND _state = STATE_RUNNING), PT := _stepTimerPreset[3]); + _stepTimer[4](IN := (_activeStep = 4 AND _state = STATE_RUNNING), PT := _stepTimerPreset[4]); + _stepTimer[5](IN := (_activeStep = 5 AND _state = STATE_RUNNING), PT := _stepTimerPreset[5]); + _stepTimer[6](IN := (_activeStep = 6 AND _state = STATE_RUNNING), PT := _stepTimerPreset[6]); + _stepTimer[7](IN := (_activeStep = 7 AND _state = STATE_RUNNING), PT := _stepTimerPreset[7]); + _stepTimer[8](IN := (_activeStep = 8 AND _state = STATE_RUNNING), PT := _stepTimerPreset[8]); + _stepTimer[9](IN := (_activeStep = 9 AND _state = STATE_RUNNING), PT := _stepTimerPreset[9]); + _stepTimer[10](IN:= (_activeStep = 10 AND _state = STATE_RUNNING), PT := _stepTimerPreset[10]); + + //── Per-step watchdog timers ───────────────────────────────────────── + _stepWatchdog[1](IN := (_activeStep = 1), PT := WATCHDOG_TIME); + _stepWatchdog[2](IN := (_activeStep = 2), PT := WATCHDOG_TIME); + _stepWatchdog[3](IN := (_activeStep = 3), PT := WATCHDOG_TIME); + _stepWatchdog[4](IN := (_activeStep = 4), PT := WATCHDOG_TIME); + _stepWatchdog[5](IN := (_activeStep = 5), PT := WATCHDOG_TIME); + _stepWatchdog[6](IN := (_activeStep = 6), PT := WATCHDOG_TIME); + _stepWatchdog[7](IN := (_activeStep = 7), PT := WATCHDOG_TIME); + _stepWatchdog[8](IN := (_activeStep = 8), PT := WATCHDOG_TIME); + _stepWatchdog[9](IN := (_activeStep = 9), PT := WATCHDOG_TIME); + _stepWatchdog[10](IN:= (_activeStep = 10), PT := WATCHDOG_TIME); + + // Watchdog trip + IF _stepWatchdog[_activeStep].Q THEN + FaultCode := 40; + _state := STATE_FAULTED; + END_IF; + + END_IF; + + //────────────────────────────────────────────────────────────────────── + CASE _activeStep OF + + //══════════════════════════════════════════════════════════════════ + // STEP 1 — HOME POSITION VERIFY + // Purpose : Confirm fixture/robot is at safe home before clamping + // Actuators: NONE (verify-only step) + // Sensors : 2 sensors — Sen_HomeFwd (at home) + Sen_HomeBwd (NOT in + // work zone). BOTH conditions required for safe start. + // Safety : 🔒 LOCKED — cannot be skipped + // Advance : Sen_HomeFwd = TRUE AND Sen_HomeBwd = FALSE + //══════════════════════════════════════════════════════════════════ + 1: + // No outputs energised — pure monitoring step + _stepAdvReady := Sen_HomeFwd AND NOT Sen_HomeBwd; + + //══════════════════════════════════════════════════════════════════ + // STEP 2 — CLAMP WORKPIECE + // Purpose : Close clamp jaw to secure part for welding + // Actuators: Act_Clamp ON + // Sensors : 1 sensor — Sen_ClampClosed (clamp jaw closed) + // Advance : Sen_ClampClosed = TRUE + //══════════════════════════════════════════════════════════════════ + 2: + Act_Clamp := TRUE; + _stepAdvReady := Sen_ClampClosed; + + //══════════════════════════════════════════════════════════════════ + // STEP 3 — EXTEND WELD HEAD TO POSITION + // Purpose : Drive weld torch to weld-start co-ordinate + // Actuators: Act_HeadExtend ON + // Sensors : 2 sensors declared (FWD + BWD shared with Step 9) + // FWD: Sen_HeadAtWeldPos → advance trigger + // BWD: Sen_HeadRetracted → conflict / interlock check + // Advance : Sen_HeadAtWeldPos = TRUE (FWD sensor) + //══════════════════════════════════════════════════════════════════ + 3: + Act_Clamp := TRUE; // Maintain clamp during all weld steps + Act_HeadExtend := TRUE; + _stepAdvReady := Sen_HeadAtWeldPos; + + //══════════════════════════════════════════════════════════════════ + // STEP 4 — PRE-PURGE GAS (TIMER ADVANCE — no sensor) + // Purpose : Flow shielding gas before arc strike to purge atmosphere + // Actuators: Act_GasValve ON + // Sensors : NONE + // Advance : Timer T#2S elapsed + //══════════════════════════════════════════════════════════════════ + 4: + Act_Clamp := TRUE; + Act_HeadExtend := TRUE; + Act_GasValve := TRUE; + _stepAdvReady:= _stepTimer[4].Q; + + //══════════════════════════════════════════════════════════════════ + // STEP 5 — ARC STRIKE + // Purpose : Enable welder; wait for arc current confirmation + // Actuators: Act_WeldEnable ON + Act_GasValve ON + // Sensors : 1 sensor — Sen_ArcDetect (arc current detected) + // Safety : 🔒 LOCKED — arc MUST be confirmed before travel + // Advance : Sen_ArcDetect = TRUE + //══════════════════════════════════════════════════════════════════ + 5: + Act_Clamp := TRUE; + Act_HeadExtend := TRUE; + Act_GasValve := TRUE; + Act_WeldEnable := TRUE; + _stepAdvReady := Sen_ArcDetect; + + //══════════════════════════════════════════════════════════════════ + // STEP 6 — WELD TRAVEL (TIMER ADVANCE — no sensor) + // Purpose : Weld torch traverses seam (robot/axis handles motion) + // SCL holds outputs stable for weld duration + // Actuators: Act_WeldEnable ON + Act_GasValve ON (all weld outputs) + // Sensors : NONE (robot reports completion via external handshake + // or fixed weld time used here for demo) + // Advance : Timer T#4S elapsed + //══════════════════════════════════════════════════════════════════ + 6: + Act_Clamp := TRUE; + Act_HeadExtend := TRUE; + Act_GasValve := TRUE; + Act_WeldEnable := TRUE; + _stepAdvReady := _stepTimer[6].Q; + + //══════════════════════════════════════════════════════════════════ + // STEP 7 — ARC OFF / WELD END + // Purpose : Command welder off; wait for arc extinction confirmation + // Actuators: Act_WeldEnable OFF, Act_GasValve ON (gas post-protection) + // Sensors : 1 sensor — Sen_ArcOff (TRUE = current < threshold) + // Safety : 🔒 LOCKED — arc MUST be extinguished before any movement + // Advance : Sen_ArcOff = TRUE + //══════════════════════════════════════════════════════════════════ + 7: + Act_Clamp := TRUE; + Act_HeadExtend := TRUE; + Act_GasValve := TRUE; + Act_WeldEnable := FALSE; // Welder OFF — waiting for arc to die + _stepAdvReady := Sen_ArcOff; + + //══════════════════════════════════════════════════════════════════ + // STEP 8 — POST-PURGE GAS (TIMER ADVANCE — no sensor) + // Purpose : Continue gas flow after arc off to protect hot weld pool + // Actuators: Act_GasValve ON + // Sensors : NONE + // Advance : Timer T#2.5S elapsed + //══════════════════════════════════════════════════════════════════ + 8: + Act_Clamp := TRUE; + Act_HeadExtend := TRUE; + Act_GasValve := TRUE; // Post-weld purge only — no WeldEnable + _stepAdvReady := _stepTimer[8].Q; + + //══════════════════════════════════════════════════════════════════ + // STEP 9 — RETRACT WELD HEAD + // Purpose : Drive torch back to safe retracted position + // Actuators: Act_HeadRetract ON, Act_HeadExtend OFF + // Sensors : 2 sensors shared with Step 3 (FWD + BWD) + // BWD: Sen_HeadRetracted → advance trigger + // FWD: Sen_HeadAtWeldPos → conflict check (should be FALSE) + // Advance : Sen_HeadRetracted = TRUE AND Sen_HeadAtWeldPos = FALSE + //══════════════════════════════════════════════════════════════════ + 9: + Act_Clamp := TRUE; + Act_HeadExtend := FALSE; + Act_HeadRetract := TRUE; + _stepAdvReady := Sen_HeadRetracted AND NOT Sen_HeadAtWeldPos; + + //══════════════════════════════════════════════════════════════════ + // STEP 10 — UNCLAMP / PART EJECT + // Purpose : Release clamp and eject finished part + // Actuators: Act_Clamp OFF, Act_Unclamp ON, Act_PartEject ON + // Sensors : 1 sensor — Sen_UnclampConf (clamp fully open / part clear) + // Advance : Sen_UnclampConf = TRUE → COMPLETE + //══════════════════════════════════════════════════════════════════ + 10: + Act_Clamp := FALSE; // Release clamp + Act_Unclamp := TRUE; // Drive unclamp solenoid + Act_PartEject := TRUE; // Fire ejector cylinder + _stepAdvReady := Sen_UnclampConf; + + END_CASE; + +END_IF; // RUNNING or STOPPING_CAT1 + +(*═══════════════════════════════════════════════════════════════════════════ + ░░ S E C T I O N 6 — O U T P U T S A F E - S T A T E O V E R R I D E ░░ + These rules override the step logic above for safety states +═══════════════════════════════════════════════════════════════════════════*) + +// ── FAULTED (CAT0 or hard safety fault): ALL outputs immediately de-energised +IF _state = STATE_FAULTED THEN + Act_Clamp := FALSE; + Act_HeadExtend := FALSE; + Act_HeadRetract := FALSE; + Act_GasValve := FALSE; + Act_WeldEnable := FALSE; + Act_Unclamp := FALSE; + Act_PartEject := FALSE; +END_IF; + +// ── IDLE / COMPLETE: weld-related outputs OFF; clamp may stay per design +IF _state = STATE_IDLE OR _state = STATE_COMPLETE THEN + Act_WeldEnable := FALSE; + Act_GasValve := FALSE; + Act_HeadExtend := FALSE; + Act_HeadRetract := FALSE; + Act_Unclamp := FALSE; + Act_PartEject := FALSE; + // NOTE: Act_Clamp intentionally left as-is here. + // Add Act_Clamp := FALSE if open-on-idle is required. +END_IF; + +(*═══════════════════════════════════════════════════════════════════════════ + ░░ S E C T I O N 7 — S T A T U S O U T P U T S ░░ +═══════════════════════════════════════════════════════════════════════════*) +ActiveStep := _activeStep; +SeqState := _state; +StepAdvanceReady := _stepAdvReady; +IncrWaiting := Mode_Incr AND _stepAdvReady AND NOT _incrRequest + AND (_state = STATE_RUNNING); + +Seq_Idle := (_state = STATE_IDLE); +Seq_Running := (_state = STATE_RUNNING); +Seq_Paused := (_state = STATE_PAUSED); +Seq_Stopping := (_state = STATE_STOPPING_CAT1); +Seq_Stopped := (_state = STATE_STOPPED); +Seq_Faulted := (_state = STATE_FAULTED); +Seq_Complete := (_state = STATE_COMPLETE); + +END_FUNCTION_BLOCK + + +(*═══════════════════════════════════════════════════════════════════════════════ + USAGE CALL EXAMPLE — FC_WeldSeq_Call (or OB_CyclicInterrupt) + + // In TIA Portal create an instance DB: DB_WeldSeq : FB_WeldSequencer + + "DB_WeldSeq"( + Mode_Auto := %I2.0, + Mode_Incr := %I2.1, + Cmd_Start := %I1.4, + Cmd_Pause := %I1.5, + Cmd_Stop := %I1.6, + Cmd_EStop := %I1.2, + Cmd_Reset := %I1.3, + Cmd_Incr := %I1.7, + Cmd_SkipStep := %I2.2, + StopCategory := %MW10, // 0, 1 or 2 — set by HMI + Safety_DoorClosed := %I1.1, + Safety_EStopOK := %I1.0, + Sen_HomeFwd := %I0.0, + Sen_HomeBwd := %I0.1, + Sen_ClampClosed := %I0.2, + Sen_HeadAtWeldPos := %I0.3, + Sen_HeadRetracted := %I0.4, + Sen_ArcDetect := %I0.5, + Sen_ArcOff := %I0.6, + Sen_UnclampConf := %I0.7, + Act_Clamp => %Q0.0, + Act_HeadExtend => %Q0.1, + Act_HeadRetract => %Q0.2, + Act_GasValve => %Q0.3, + Act_WeldEnable => %Q0.4, + Act_Unclamp => %Q0.5, + Act_PartEject => %Q0.6, + Seq_Running => %Q1.0, + Seq_Paused => %Q1.1, + Seq_Faulted => %Q1.2, + Seq_Complete => %Q1.3, + ActiveStep => %MW20, + SeqState => %MW22, + FaultCode => %MW24, + StepAdvanceReady => %M5.0, + IncrWaiting => %M5.1, + CycleCount => %MD30 + ); +═══════════════════════════════════════════════════════════════════════════════*)