(*═══════════════════════════════════════════════════════════════════════════════ 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 ); ═══════════════════════════════════════════════════════════════════════════════*)