Upload files to "s7-1500"

This commit is contained in:
Dejan 2026-02-24 11:54:19 +00:00
parent 58a7106cc8
commit d1088710af

View file

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