s7-SCL-scripts/s7-1500/FB_WeldSequencer.scl
2026-02-24 11:54:19 +00:00

769 lines
45 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(*═══════════════════════════════════════════════════════════════════════════════
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 29: Clamp solenoid (energise = clamp)
Act_HeadExtend : Bool; // Step 38: Weld head extend solenoid
Act_HeadRetract : Bool; // Step 9: Weld head retract solenoid
Act_GasValve : Bool; // Step 48: Shielding gas solenoid valve
Act_WeldEnable : Bool; // Step 56: 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
);
═══════════════════════════════════════════════════════════════════════════════*)