Upload files to "s7-1500/cylinder_monitor"
This commit is contained in:
parent
4a23d20a08
commit
3c31662da5
297
s7-1500/cylinder_monitor/DEMO_WeldCellIntegration.scl
Normal file
297
s7-1500/cylinder_monitor/DEMO_WeldCellIntegration.scl
Normal file
|
|
@ -0,0 +1,297 @@
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
DEMO_WeldCellIntegration.scl
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
Demonstrates FB_CylinderMonitor instances for all 4 sensor configurations
|
||||||
|
wired into the FB_WeldSequencer from the welding cell demo.
|
||||||
|
|
||||||
|
CYLINDERS IN THIS DEMO:
|
||||||
|
┌──────┬───────────────────────┬──────────────┬────────────────────────────┐
|
||||||
|
│ Inst │ Cylinder │ SensorConfig │ Notes │
|
||||||
|
├──────┼───────────────────────┼──────────────┼────────────────────────────┤
|
||||||
|
│ DB1 │ Clamp Cylinder │ ONE_FWD (1) │ Only clamp-closed sensor │
|
||||||
|
│ DB2 │ Weld Head │ TWO (3) │ Extended + retracted sensor │
|
||||||
|
│ DB3 │ Part Ejector │ ONE_BWD (2) │ Only retracted (home) sensor│
|
||||||
|
│ DB4 │ Gas Purge Valve │ NONE (0) │ No position sensor, timer │
|
||||||
|
└──────┴───────────────────────┴──────────────┴────────────────────────────┘
|
||||||
|
|
||||||
|
RESPONSE CONFIGURATION:
|
||||||
|
Timeout faults → PAUSE machine (operator can clear & resume)
|
||||||
|
Conflict faults → STOP machine (requires Reset before restart)
|
||||||
|
Lost position → STOP machine (requires Reset before restart)
|
||||||
|
|
||||||
|
CALL ORDER in OB (important — monitors must execute BEFORE sequencer):
|
||||||
|
1. FB_CylinderMonitor instances (DB1..DB4)
|
||||||
|
2. FB_CylFaultCollector (DB_CylFaults)
|
||||||
|
3. FB_WeldSequencer (DB_WeldSeq)
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════*)
|
||||||
|
|
||||||
|
//─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// INSTANCE DB DECLARATIONS (create these in TIA Portal project tree)
|
||||||
|
//
|
||||||
|
// DB_CylClamp : FB_CylinderMonitor
|
||||||
|
// DB_CylHead : FB_CylinderMonitor
|
||||||
|
// DB_CylEject : FB_CylinderMonitor
|
||||||
|
// DB_CylGas : FB_CylinderMonitor
|
||||||
|
// DB_CylFaults : FB_CylFaultCollector
|
||||||
|
// DB_WeldSeq : FB_WeldSequencer
|
||||||
|
//─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
// CYLINDER 1 — CLAMP (ONE_FWD: only clamp-closed sensor at FWD end)
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
// Physical setup:
|
||||||
|
// Proximity sensor mounted at closed (extended) jaw position ONLY.
|
||||||
|
// No sensor at open position — we assume open if no clamp command active.
|
||||||
|
//
|
||||||
|
// Error logic:
|
||||||
|
// Cmd_Fwd (clamp) active → Sen_Fwd (clamp closed) not confirmed in 2 s
|
||||||
|
// → FaultCode 1 (FWD timeout) → machine PAUSE
|
||||||
|
// Sen_Fwd unexpectedly active with no command? → Not detected (ONE_FWD limit)
|
||||||
|
//
|
||||||
|
// Advance in sequencer:
|
||||||
|
// Step 2 advance condition: DB_CylClamp.AtFwd
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
"DB_CylClamp"(
|
||||||
|
CylName := 'Clamp Cylinder',
|
||||||
|
SensorConfig := 1, // ONE_FWD
|
||||||
|
T_Timeout := T#2S, // 2 second fault timeout
|
||||||
|
Cmd_Fwd := "DB_WeldSeq".Act_Clamp, // Sequencer output drives FWD
|
||||||
|
Cmd_Bwd := NOT "DB_WeldSeq".Act_Clamp AND NOT "DB_WeldSeq".Seq_Faulted,
|
||||||
|
// Bwd inferred: not clamped & not faulted
|
||||||
|
Cmd_Reset := "PB_Reset",
|
||||||
|
Sen_Fwd := %I0.2, // Sen_ClampClosed hardware input
|
||||||
|
Sen_Bwd := FALSE, // No sensor at open position
|
||||||
|
Enable := "DB_WeldSeq".Seq_Running OR "DB_WeldSeq".Seq_Paused
|
||||||
|
);
|
||||||
|
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
// CYLINDER 2 — WELD HEAD (TWO sensors: extended + retracted)
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
// Physical setup:
|
||||||
|
// Sensor at fully extended (weld position) = Sen_Fwd → %I0.3
|
||||||
|
// Sensor at fully retracted (safe position) = Sen_Bwd → %I0.4
|
||||||
|
//
|
||||||
|
// Error logic:
|
||||||
|
// Extend cmd → Sen_Fwd not confirmed in 3 s → FaultCode 1 → PAUSE
|
||||||
|
// Retract cmd → Sen_Bwd not confirmed in 3 s → FaultCode 2 → PAUSE
|
||||||
|
// Both sensors TRUE simultaneously → FaultCode 3 → STOP
|
||||||
|
// Sensors both drop with no command active → FaultCode 4 (lost) → STOP
|
||||||
|
//
|
||||||
|
// Advance in sequencer:
|
||||||
|
// Step 3 advance: DB_CylHead.AtFwd
|
||||||
|
// Step 9 advance: DB_CylHead.AtBwd
|
||||||
|
//
|
||||||
|
// NOTE: Extend and Retract are separate solenoid outputs (bistable valve)
|
||||||
|
// CylCmd_FwdSafe → Act_HeadExtend solenoid
|
||||||
|
// CylCmd_BwdSafe → Act_HeadRetract solenoid
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
"DB_CylHead"(
|
||||||
|
CylName := 'Weld Head',
|
||||||
|
SensorConfig := 3, // TWO sensors
|
||||||
|
T_Timeout := T#3S, // 3 seconds (head travel takes longer)
|
||||||
|
Cmd_Fwd := "DB_WeldSeq".Act_HeadExtend,
|
||||||
|
Cmd_Bwd := "DB_WeldSeq".Act_HeadRetract,
|
||||||
|
Cmd_Reset := "PB_Reset",
|
||||||
|
Sen_Fwd := %I0.3, // Sen_HeadAtWeldPos
|
||||||
|
Sen_Bwd := %I0.4, // Sen_HeadRetracted
|
||||||
|
Enable := "DB_WeldSeq".Seq_Running OR "DB_WeldSeq".Seq_Paused
|
||||||
|
OR "DB_WeldSeq".Seq_Stopping
|
||||||
|
);
|
||||||
|
|
||||||
|
// ── Wire safe outputs back to physical DQs ───────────────────────────────
|
||||||
|
%Q0.1 := "DB_CylHead".CylCmd_FwdSafe; // Act_HeadExtend (gated)
|
||||||
|
%Q0.2 := "DB_CylHead".CylCmd_BwdSafe; // Act_HeadRetract (gated)
|
||||||
|
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
// CYLINDER 3 — PART EJECTOR (ONE_BWD: only home/retracted sensor)
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
// Physical setup:
|
||||||
|
// The ejector fires forward (extends) to push the part out.
|
||||||
|
// Sensor only at retracted (home) end — confirms ejector is clear/home.
|
||||||
|
// No sensor at extended (ejected) position.
|
||||||
|
//
|
||||||
|
// Error logic:
|
||||||
|
// Retract cmd (home return) → Sen_Bwd not confirmed in 1.5 s
|
||||||
|
// → FaultCode 2 (BWD timeout) → PAUSE
|
||||||
|
// Eject (FWD) cmd: no FWD sensor, so no timeout — just fires blind.
|
||||||
|
// After timer completes in sequencer, retract command issued.
|
||||||
|
//
|
||||||
|
// Advance in sequencer:
|
||||||
|
// Step 10 advance uses Sen_UnclampConf (%I0.7) which is separate.
|
||||||
|
// After cycle complete, this FB confirms ejector is home before next cycle.
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
"DB_CylEject"(
|
||||||
|
CylName := 'Part Ejector',
|
||||||
|
SensorConfig := 2, // ONE_BWD
|
||||||
|
T_Timeout := T#1500MS,
|
||||||
|
Cmd_Fwd := "DB_WeldSeq".Act_PartEject,
|
||||||
|
Cmd_Bwd := NOT "DB_WeldSeq".Act_PartEject
|
||||||
|
AND "DB_WeldSeq".Seq_Complete,
|
||||||
|
Cmd_Reset := "PB_Reset",
|
||||||
|
Sen_Fwd := FALSE, // No sensor at ejected position
|
||||||
|
Sen_Bwd := %I0.7, // Ejector home sensor (shared / Sen_UnclampConf area)
|
||||||
|
Enable := TRUE // Always enabled
|
||||||
|
);
|
||||||
|
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
// CYLINDER 4 — GAS PURGE VALVE (NONE: no position sensors)
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
// Physical setup:
|
||||||
|
// Simple solenoid valve — open or closed.
|
||||||
|
// No position feedback — valve assumed open when energised.
|
||||||
|
// No fault can be generated from position sensors (none exist).
|
||||||
|
//
|
||||||
|
// Error logic:
|
||||||
|
// NONE: the FB passes the command through, reports AT_FWD when commanded
|
||||||
|
// On/Off confirmed only by timer in the sequencer (Steps 4, 6, 8).
|
||||||
|
//
|
||||||
|
// NOTE: A pressure switch or flow sensor could be added here in future.
|
||||||
|
// Connect it to Sen_Fwd and change SensorConfig to ONE_FWD.
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
"DB_CylGas"(
|
||||||
|
CylName := 'Gas Purge Valve',
|
||||||
|
SensorConfig := 0, // NONE
|
||||||
|
T_Timeout := T#500MS, // Not used with NONE config (no timers start)
|
||||||
|
Cmd_Fwd := "DB_WeldSeq".Act_GasValve,
|
||||||
|
Cmd_Bwd := FALSE, // Single-acting valve — spring return
|
||||||
|
Cmd_Reset := "PB_Reset",
|
||||||
|
Sen_Fwd := FALSE,
|
||||||
|
Sen_Bwd := FALSE,
|
||||||
|
Enable := TRUE
|
||||||
|
);
|
||||||
|
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
// FAULT COLLECTOR — Aggregates all 4 cylinder faults
|
||||||
|
// Outputs feed directly into the sequencer Cmd_Pause / Cmd_Stop inputs
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
"DB_CylFaults"(
|
||||||
|
//── Fault bits ───────────────────────────────────────────────────────────
|
||||||
|
Cyl1_Fault := "DB_CylClamp".Fault_Active,
|
||||||
|
Cyl2_Fault := "DB_CylHead".Fault_Active,
|
||||||
|
Cyl3_Fault := "DB_CylEject".Fault_Active,
|
||||||
|
Cyl4_Fault := "DB_CylGas".Fault_Active,
|
||||||
|
Cyl5_Fault := FALSE,
|
||||||
|
Cyl6_Fault := FALSE,
|
||||||
|
Cyl7_Fault := FALSE,
|
||||||
|
Cyl8_Fault := FALSE,
|
||||||
|
|
||||||
|
//── Fault codes ───────────────────────────────────────────────────────────
|
||||||
|
Cyl1_FaultCode := "DB_CylClamp".FaultCode,
|
||||||
|
Cyl2_FaultCode := "DB_CylHead".FaultCode,
|
||||||
|
Cyl3_FaultCode := "DB_CylEject".FaultCode,
|
||||||
|
Cyl4_FaultCode := "DB_CylGas".FaultCode,
|
||||||
|
Cyl5_FaultCode := 0,
|
||||||
|
Cyl6_FaultCode := 0,
|
||||||
|
Cyl7_FaultCode := 0,
|
||||||
|
Cyl8_FaultCode := 0,
|
||||||
|
|
||||||
|
//── HMI fault texts ───────────────────────────────────────────────────────
|
||||||
|
Cyl1_FaultText := "DB_CylClamp".HMI_FaultText,
|
||||||
|
Cyl2_FaultText := "DB_CylHead".HMI_FaultText,
|
||||||
|
Cyl3_FaultText := "DB_CylEject".HMI_FaultText,
|
||||||
|
Cyl4_FaultText := "DB_CylGas".HMI_FaultText,
|
||||||
|
|
||||||
|
//── Machine response policy ───────────────────────────────────────────────
|
||||||
|
// Timeout → PAUSE (1): operator can check & reset, then resume
|
||||||
|
// Conflict → STOP (2): two sensors TRUE = hardware fault, needs investigation
|
||||||
|
// Lost pos → STOP (2): cylinder moved undetected = mechanical issue
|
||||||
|
Response_Timeout := 1,
|
||||||
|
Response_Conflict := 2,
|
||||||
|
Response_Lost := 2
|
||||||
|
);
|
||||||
|
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
// WELDING SEQUENCER — Wired with cylinder feedback and fault injection
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
"DB_WeldSeq"(
|
||||||
|
//── Mode & commands ─────────────────────────────────────────────────────
|
||||||
|
Mode_Auto := %I2.0,
|
||||||
|
Mode_Incr := %I2.1,
|
||||||
|
Cmd_Start := %I1.4,
|
||||||
|
Cmd_Reset := "PB_Reset",
|
||||||
|
|
||||||
|
// ── PAUSE: operator button OR cylinder fault requesting pause ──────────
|
||||||
|
Cmd_Pause := %I1.5
|
||||||
|
OR "DB_CylFaults".Cmd_MachinePause,
|
||||||
|
|
||||||
|
// ── STOP: operator button OR cylinder fault requesting stop ───────────
|
||||||
|
Cmd_Stop := %I1.6
|
||||||
|
OR "DB_CylFaults".Cmd_MachineStop,
|
||||||
|
|
||||||
|
Cmd_EStop := %I1.2,
|
||||||
|
Cmd_Incr := %I1.7,
|
||||||
|
Cmd_SkipStep := %I2.2,
|
||||||
|
StopCategory := %MW10,
|
||||||
|
|
||||||
|
//── Safety inputs ────────────────────────────────────────────────────────
|
||||||
|
Safety_DoorClosed := %I1.1,
|
||||||
|
Safety_EStopOK := %I1.0,
|
||||||
|
|
||||||
|
//── Sensors — using GATED outputs from cylinder monitors where possible ──
|
||||||
|
// Sequencer only sees "AtFwd/AtBwd" from healthy, confirmed cylinders.
|
||||||
|
// If cylinder monitor is faulted, AtFwd/AtBwd → FALSE → step never
|
||||||
|
// advances → watchdog trips → sequencer also faults. Belt & braces.
|
||||||
|
|
||||||
|
Sen_HomeFwd := %I0.0, // No cylinder monitor (robot)
|
||||||
|
Sen_HomeBwd := %I0.1,
|
||||||
|
|
||||||
|
// Step 2 clamp — uses cylinder monitor's AtFwd (confirmed clamp closed)
|
||||||
|
Sen_ClampClosed := "DB_CylClamp".AtFwd, // ← From monitor, not raw DI
|
||||||
|
|
||||||
|
// Steps 3 & 9 — weld head FWD/BWD (from monitor)
|
||||||
|
Sen_HeadAtWeldPos := "DB_CylHead".AtFwd, // ← Confirmed extended
|
||||||
|
Sen_HeadRetracted := "DB_CylHead".AtBwd, // ← Confirmed retracted
|
||||||
|
|
||||||
|
Sen_ArcDetect := %I0.5,
|
||||||
|
Sen_ArcOff := %I0.6,
|
||||||
|
|
||||||
|
// Step 10 unclamp (ejector home or unclamp sensor)
|
||||||
|
Sen_UnclampConf := "DB_CylEject".AtBwd, // ← Ejector home confirmed
|
||||||
|
|
||||||
|
//── Actuator outputs ─────────────────────────────────────────────────────
|
||||||
|
// NOTE: Act_HeadExtend and Act_HeadRetract go through the head cylinder
|
||||||
|
// monitor's gated outputs (see %Q assignments above).
|
||||||
|
// Act_Clamp goes direct here — the monitor checks it on its own scan.
|
||||||
|
Act_Clamp => %Q0.0,
|
||||||
|
Act_HeadExtend => "DB_CylHead_CmdFwd_Raw", // Internal tag; monitor gates it to %Q0.1
|
||||||
|
Act_HeadRetract => "DB_CylHead_CmdBwd_Raw", // Internal tag; monitor gates it to %Q0.2
|
||||||
|
Act_GasValve => %Q0.3,
|
||||||
|
Act_WeldEnable => %Q0.4,
|
||||||
|
Act_Unclamp => %Q0.5,
|
||||||
|
Act_PartEject => %Q0.6,
|
||||||
|
|
||||||
|
//── Status outputs ───────────────────────────────────────────────────────
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
|
// HMI WIRING SUMMARY
|
||||||
|
// Wire these tags to your WinCC/Comfort panel for operator guidance:
|
||||||
|
//
|
||||||
|
// TAG SOURCE HMI ELEMENT
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────
|
||||||
|
// DB_WeldSeq.ActiveStep → %MW20 Step indicator (1-10)
|
||||||
|
// DB_WeldSeq.SeqState → %MW22 State text list
|
||||||
|
// DB_WeldSeq.FaultCode → %MW24 Sequencer alarm
|
||||||
|
// DB_CylFaults.FirstFaultText First fault banner text
|
||||||
|
// DB_CylFaults.CylFaultWord Cylinder fault bitmask (overview)
|
||||||
|
// DB_CylFaults.ActiveFaultCount Number of active faults
|
||||||
|
// DB_CylClamp.CylState Clamp position indicator
|
||||||
|
// DB_CylClamp.HMI_StatusText Clamp status string
|
||||||
|
// DB_CylHead.CylState Head position indicator
|
||||||
|
// DB_CylHead.HMI_StatusText Head status string
|
||||||
|
// DB_CylEject.CylState Ejector status
|
||||||
|
// DB_CylHead.Moving Moving animation trigger
|
||||||
|
// DB_CylFaults.Cmd_Warning → %Q1.4 Amber warning lamp
|
||||||
|
// DB_WeldSeq.Seq_Faulted → %Q1.2 Red fault lamp
|
||||||
|
// DB_WeldSeq.IncrWaiting → %M5.1 "Press INCR" flashing indicator
|
||||||
|
//═════════════════════════════════════════════════════════════════════════════
|
||||||
581
s7-1500/cylinder_monitor/FB_CylinderMonitor.scl
Normal file
581
s7-1500/cylinder_monitor/FB_CylinderMonitor.scl
Normal file
|
|
@ -0,0 +1,581 @@
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
FB_CylinderMonitor
|
||||||
|
S7-1500 SCL — Universal Pneumatic/Hydraulic Cylinder Monitor
|
||||||
|
TIA Portal V18+ | Optimized Block Access
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
PURPOSE:
|
||||||
|
Wraps any cylinder (pneumatic or hydraulic) with:
|
||||||
|
• Configurable sensor topology (NONE / ONE_FWD / ONE_BWD / TWO)
|
||||||
|
• Timeout fault generation per motion direction
|
||||||
|
• Sensor conflict detection
|
||||||
|
• Intermediate-position detection
|
||||||
|
• HMI-ready status word, fault code, and text description
|
||||||
|
• Output gate: only passes actuator command when FB is healthy
|
||||||
|
→ plug CylCmd_Safe into your sequencer actuator output instead of
|
||||||
|
the raw command bit
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
SENSOR TOPOLOGY (SensorConfig input INT):
|
||||||
|
┌──────┬────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 0 │ NONE No position sensors. Advance purely by external timer. │
|
||||||
|
│ │ No position fault possible. ConflictFault impossible. │
|
||||||
|
│ 1 │ ONE_FWD One sensor at FORWARD (extended) end only. │
|
||||||
|
│ │ FWD cmd → timeout if Sen_Fwd not TRUE within T_Timeout │
|
||||||
|
│ │ BWD cmd → no feedback; only intermediate state reported │
|
||||||
|
│ 2 │ ONE_BWD One sensor at BACKWARD (retracted) end only. │
|
||||||
|
│ │ BWD cmd → timeout if Sen_Bwd not TRUE within T_Timeout │
|
||||||
|
│ │ FWD cmd → no feedback; only intermediate state reported │
|
||||||
|
│ 3 │ TWO Sensor at BOTH ends (most common in PLC applications) │
|
||||||
|
│ │ FWD cmd → timeout if Sen_Fwd not TRUE within T_Timeout │
|
||||||
|
│ │ BWD cmd → timeout if Sen_Bwd not TRUE within T_Timeout │
|
||||||
|
│ │ BOTH TRUE simultaneously → ConflictFault │
|
||||||
|
└──────┴────────────────────────────────────────────────────────────────────┘
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
CYLINDER STATE (CylState output INT):
|
||||||
|
0 IDLE No command active
|
||||||
|
1 MOVING_FWD FWD command active, waiting for sensor
|
||||||
|
2 AT_FWD FWD sensor confirmed (or FWD cmd active, NONE config)
|
||||||
|
3 MOVING_BWD BWD command active, waiting for sensor
|
||||||
|
4 AT_BWD BWD sensor confirmed (or BWD cmd active, NONE config)
|
||||||
|
5 INTERMEDIATE No sensor active when both sensors expected (TWO config)
|
||||||
|
6 FAULTED Timeout or conflict — CylCmd_Safe output gated OFF
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
FAULT CODES (FaultCode output INT):
|
||||||
|
0 No fault
|
||||||
|
1 FWD timeout — Sen_Fwd did not confirm within T_Timeout after FWD cmd
|
||||||
|
2 BWD timeout — Sen_Bwd did not confirm within T_Timeout after BWD cmd
|
||||||
|
3 Conflict — Sen_Fwd AND Sen_Bwd both TRUE at the same time
|
||||||
|
4 Lost — Cylinder left known position without a command (TWO only)
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
OUTPUT GATING STRATEGY:
|
||||||
|
CylCmd_FwdSafe / CylCmd_BwdSafe output ONLY when:
|
||||||
|
• Input command is TRUE
|
||||||
|
• FB is NOT faulted
|
||||||
|
• No conflict detected
|
||||||
|
Connect these "safe" outputs directly to your DQ outputs or sequencer.
|
||||||
|
─────────────────────────────────────────────────────────────────────────────
|
||||||
|
INTEGRATION WITH FB_WeldSequencer:
|
||||||
|
Each cylinder gets one FB_CylinderMonitor instance.
|
||||||
|
The sequencer reads Cyl.Fault_Active to trigger a pause or stop.
|
||||||
|
The sequencer reads Cyl.AtFwd / Cyl.AtBwd for step advance condition.
|
||||||
|
See FC_CylIntegration at the bottom of this file for wiring example.
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════*)
|
||||||
|
|
||||||
|
FUNCTION_BLOCK "FB_CylinderMonitor"
|
||||||
|
{ S7_Optimized_Access := 'TRUE' }
|
||||||
|
VERSION : 0.1
|
||||||
|
|
||||||
|
VAR_INPUT
|
||||||
|
//── CYLINDER IDENTITY ────────────────────────────────────────────────────
|
||||||
|
CylName : String[32]; // Human-readable name for HMI messages
|
||||||
|
// e.g. 'Clamp Cylinder' or 'Weld Head'
|
||||||
|
|
||||||
|
//── SENSOR CONFIGURATION ─────────────────────────────────────────────────
|
||||||
|
SensorConfig : Int; // 0=NONE 1=ONE_FWD 2=ONE_BWD 3=TWO
|
||||||
|
T_Timeout : Time; // Fault if position not reached in time
|
||||||
|
// Typical: T#2S for fast pneumatics
|
||||||
|
// T#5S for slow hydraulics
|
||||||
|
|
||||||
|
//── COMMANDS ─────────────────────────────────────────────────────────────
|
||||||
|
Cmd_Fwd : Bool; // Command cylinder to extend (FWD)
|
||||||
|
Cmd_Bwd : Bool; // Command cylinder to retract (BWD)
|
||||||
|
Cmd_Reset : Bool; // Clear fault (rising edge)
|
||||||
|
|
||||||
|
//── SENSOR INPUTS ────────────────────────────────────────────────────────
|
||||||
|
Sen_Fwd : Bool; // Forward / extended position sensor
|
||||||
|
Sen_Bwd : Bool; // Backward / retracted position sensor
|
||||||
|
// Leave FALSE if not wired (NONE/ONE)
|
||||||
|
|
||||||
|
//── ENABLE ───────────────────────────────────────────────────────────────
|
||||||
|
Enable : Bool; // FALSE = ignore commands, hold state
|
||||||
|
// Use for E-Stop or mode control
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_OUTPUT
|
||||||
|
//── SAFE GATED OUTPUTS ───────────────────────────────────────────────────
|
||||||
|
// Connect THESE to your DQ / actuator solenoid, not the raw Cmd_Fwd/Bwd
|
||||||
|
CylCmd_FwdSafe : Bool; // Gated FWD command (only if healthy)
|
||||||
|
CylCmd_BwdSafe : Bool; // Gated BWD command (only if healthy)
|
||||||
|
|
||||||
|
//── POSITION STATUS ──────────────────────────────────────────────────────
|
||||||
|
AtFwd : Bool; // Cylinder is confirmed at FWD position
|
||||||
|
AtBwd : Bool; // Cylinder is confirmed at BWD position
|
||||||
|
Intermediate : Bool; // Cylinder between positions (TWO config)
|
||||||
|
Moving : Bool; // Command active, position not yet confirmed
|
||||||
|
|
||||||
|
//── FAULT STATUS ─────────────────────────────────────────────────────────
|
||||||
|
Fault_Active : Bool; // TRUE = any fault present
|
||||||
|
Fault_FwdTimeout : Bool; // FWD timeout fault bit
|
||||||
|
Fault_BwdTimeout : Bool; // BWD timeout fault bit
|
||||||
|
Fault_Conflict : Bool; // Sensor conflict fault bit
|
||||||
|
Fault_Lost : Bool; // Lost position fault bit
|
||||||
|
|
||||||
|
//── CODES AND HMI ────────────────────────────────────────────────────────
|
||||||
|
FaultCode : Int; // Numeric fault code (0 = OK, 1-4 see header)
|
||||||
|
CylState : Int; // Cylinder state code (0-6, see header)
|
||||||
|
HMI_StatusText : String[80]; // Ready-to-display operator message
|
||||||
|
HMI_FaultText : String[80]; // Ready-to-display fault message for HMI
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR
|
||||||
|
//── TIMERS ───────────────────────────────────────────────────────────────
|
||||||
|
_timerFwd : TON; // Starts on FWD command; fault on .Q
|
||||||
|
_timerBwd : TON; // Starts on BWD command; fault on .Q
|
||||||
|
|
||||||
|
//── EDGE DETECTION ───────────────────────────────────────────────────────
|
||||||
|
_prevReset : Bool;
|
||||||
|
_prevCmdFwd : Bool;
|
||||||
|
_prevCmdBwd : Bool;
|
||||||
|
|
||||||
|
//── INTERNAL STATE ───────────────────────────────────────────────────────
|
||||||
|
_faulted : Bool; // Internal faulted latch
|
||||||
|
_faultCode : Int; // Internal fault code
|
||||||
|
_cylState : Int; // Internal state code
|
||||||
|
_lastKnownState : Int; // Last confirmed position (for lost detection)
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_TEMP
|
||||||
|
rReset : Bool;
|
||||||
|
rCmdFwd : Bool;
|
||||||
|
rCmdBwd : Bool;
|
||||||
|
t_Cfg : Int; // Local copy of SensorConfig for readability
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR CONSTANT
|
||||||
|
//── SENSOR CONFIG CONSTANTS ──────────────────────────────────────────────
|
||||||
|
CFG_NONE : Int := 0;
|
||||||
|
CFG_ONE_FWD : Int := 1;
|
||||||
|
CFG_ONE_BWD : Int := 2;
|
||||||
|
CFG_TWO : Int := 3;
|
||||||
|
|
||||||
|
//── CYLINDER STATE CONSTANTS ─────────────────────────────────────────────
|
||||||
|
CYL_IDLE : Int := 0;
|
||||||
|
CYL_MOVING_FWD : Int := 1;
|
||||||
|
CYL_AT_FWD : Int := 2;
|
||||||
|
CYL_MOVING_BWD : Int := 3;
|
||||||
|
CYL_AT_BWD : Int := 4;
|
||||||
|
CYL_INTERMEDIATE : Int := 5;
|
||||||
|
CYL_FAULTED : Int := 6;
|
||||||
|
|
||||||
|
//── FAULT CODE CONSTANTS ─────────────────────────────────────────────────
|
||||||
|
FAULT_NONE : Int := 0;
|
||||||
|
FAULT_FWD_TIMEOUT : Int := 1;
|
||||||
|
FAULT_BWD_TIMEOUT : Int := 2;
|
||||||
|
FAULT_CONFLICT : Int := 3;
|
||||||
|
FAULT_LOST : Int := 4;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════
|
||||||
|
░░ SECTION 1 — EDGE DETECTION ░░
|
||||||
|
═══════════════════════════════════════════════════════════════════════════*)
|
||||||
|
rReset := Cmd_Reset AND NOT _prevReset;
|
||||||
|
rCmdFwd := Cmd_Fwd AND NOT _prevCmdFwd;
|
||||||
|
rCmdBwd := Cmd_Bwd AND NOT _prevCmdBwd;
|
||||||
|
|
||||||
|
_prevReset := Cmd_Reset;
|
||||||
|
_prevCmdFwd := Cmd_Fwd;
|
||||||
|
_prevCmdBwd := Cmd_Bwd;
|
||||||
|
|
||||||
|
t_Cfg := SensorConfig;
|
||||||
|
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════
|
||||||
|
░░ SECTION 2 — FAULT RESET ░░
|
||||||
|
═══════════════════════════════════════════════════════════════════════════*)
|
||||||
|
IF rReset THEN
|
||||||
|
_faulted := FALSE;
|
||||||
|
_faultCode := FAULT_NONE;
|
||||||
|
Fault_FwdTimeout := FALSE;
|
||||||
|
Fault_BwdTimeout := FALSE;
|
||||||
|
Fault_Conflict := FALSE;
|
||||||
|
Fault_Lost := FALSE;
|
||||||
|
// Force both timers off on reset
|
||||||
|
_timerFwd(IN := FALSE, PT := T_Timeout);
|
||||||
|
_timerBwd(IN := FALSE, PT := T_Timeout);
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════
|
||||||
|
░░ SECTION 3 — SENSOR CONFLICT CHECK (highest priority, every scan) ░░
|
||||||
|
Only possible with TWO sensor config
|
||||||
|
═══════════════════════════════════════════════════════════════════════════*)
|
||||||
|
IF (t_Cfg = CFG_TWO) AND Sen_Fwd AND Sen_Bwd THEN
|
||||||
|
_faulted := TRUE;
|
||||||
|
_faultCode := FAULT_CONFLICT;
|
||||||
|
Fault_Conflict := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════
|
||||||
|
░░ SECTION 4 — TIMEOUT TIMERS ░░
|
||||||
|
Timer IN = command active AND sensor NOT yet confirmed AND not faulted
|
||||||
|
This ensures timers only run during active motion, not in hold.
|
||||||
|
Timers auto-reset when command drops or sensor arrives.
|
||||||
|
═══════════════════════════════════════════════════════════════════════════*)
|
||||||
|
|
||||||
|
// ── FWD timeout timer ─────────────────────────────────────────────────────
|
||||||
|
// Active when: FWD commanded AND sensor not confirmed AND config allows it
|
||||||
|
CASE t_Cfg OF
|
||||||
|
CFG_ONE_FWD, CFG_TWO:
|
||||||
|
// Timer runs while FWD commanded but Sen_Fwd not yet TRUE
|
||||||
|
_timerFwd(
|
||||||
|
IN := Cmd_Fwd AND NOT Sen_Fwd AND NOT _faulted AND Enable,
|
||||||
|
PT := T_Timeout
|
||||||
|
);
|
||||||
|
ELSE:
|
||||||
|
// NONE or ONE_BWD — no FWD sensor, no FWD timeout possible
|
||||||
|
_timerFwd(IN := FALSE, PT := T_Timeout);
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
// ── BWD timeout timer ─────────────────────────────────────────────────────
|
||||||
|
CASE t_Cfg OF
|
||||||
|
CFG_ONE_BWD, CFG_TWO:
|
||||||
|
_timerBwd(
|
||||||
|
IN := Cmd_Bwd AND NOT Sen_Bwd AND NOT _faulted AND Enable,
|
||||||
|
PT := T_Timeout
|
||||||
|
);
|
||||||
|
ELSE:
|
||||||
|
_timerBwd(IN := FALSE, PT := T_Timeout);
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
// ── Trigger faults on timer expiry ─────────────────────────────────────
|
||||||
|
IF _timerFwd.Q AND NOT _faulted THEN
|
||||||
|
_faulted := TRUE;
|
||||||
|
_faultCode := FAULT_FWD_TIMEOUT;
|
||||||
|
Fault_FwdTimeout := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
IF _timerBwd.Q AND NOT _faulted THEN
|
||||||
|
_faulted := TRUE;
|
||||||
|
_faultCode := FAULT_BWD_TIMEOUT;
|
||||||
|
Fault_BwdTimeout := TRUE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════
|
||||||
|
░░ SECTION 5 — LOST POSITION DETECTION (TWO sensor config only) ░░
|
||||||
|
If both sensors go FALSE when we expect one to be TRUE,
|
||||||
|
the cylinder has moved without a command (mechanical failure, etc.)
|
||||||
|
═══════════════════════════════════════════════════════════════════════════*)
|
||||||
|
IF t_Cfg = CFG_TWO AND NOT _faulted THEN
|
||||||
|
// We had a confirmed position...
|
||||||
|
IF _lastKnownState = CYL_AT_FWD OR _lastKnownState = CYL_AT_BWD THEN
|
||||||
|
// ...but now neither sensor is active and no command is running
|
||||||
|
IF NOT Sen_Fwd AND NOT Sen_Bwd AND NOT Cmd_Fwd AND NOT Cmd_Bwd THEN
|
||||||
|
_faulted := TRUE;
|
||||||
|
_faultCode := FAULT_LOST;
|
||||||
|
Fault_Lost := TRUE;
|
||||||
|
END_IF;
|
||||||
|
END_IF;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════
|
||||||
|
░░ SECTION 6 — CYLINDER STATE MACHINE ░░
|
||||||
|
═══════════════════════════════════════════════════════════════════════════*)
|
||||||
|
IF _faulted THEN
|
||||||
|
_cylState := CYL_FAULTED;
|
||||||
|
|
||||||
|
ELSIF NOT Enable THEN
|
||||||
|
// Disabled — stay in IDLE regardless
|
||||||
|
_cylState := CYL_IDLE;
|
||||||
|
|
||||||
|
ELSIF Cmd_Fwd AND NOT Cmd_Bwd THEN
|
||||||
|
// FWD command active
|
||||||
|
CASE t_Cfg OF
|
||||||
|
CFG_NONE:
|
||||||
|
// No sensors — trust the command, immediately "at FWD"
|
||||||
|
_cylState := CYL_AT_FWD;
|
||||||
|
|
||||||
|
CFG_ONE_FWD, CFG_TWO:
|
||||||
|
IF Sen_Fwd THEN
|
||||||
|
_cylState := CYL_AT_FWD;
|
||||||
|
_lastKnownState := CYL_AT_FWD;
|
||||||
|
ELSE
|
||||||
|
_cylState := CYL_MOVING_FWD;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
CFG_ONE_BWD:
|
||||||
|
// FWD cmd but sensor is only on BWD side — report moving until BWD clears
|
||||||
|
IF NOT Sen_Bwd THEN
|
||||||
|
_cylState := CYL_AT_FWD; // Best we can say: not at BWD
|
||||||
|
ELSE
|
||||||
|
_cylState := CYL_MOVING_FWD;
|
||||||
|
END_IF;
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
ELSIF Cmd_Bwd AND NOT Cmd_Fwd THEN
|
||||||
|
// BWD command active
|
||||||
|
CASE t_Cfg OF
|
||||||
|
CFG_NONE:
|
||||||
|
_cylState := CYL_AT_BWD;
|
||||||
|
|
||||||
|
CFG_ONE_BWD, CFG_TWO:
|
||||||
|
IF Sen_Bwd THEN
|
||||||
|
_cylState := CYL_AT_BWD;
|
||||||
|
_lastKnownState := CYL_AT_BWD;
|
||||||
|
ELSE
|
||||||
|
_cylState := CYL_MOVING_BWD;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
CFG_ONE_FWD:
|
||||||
|
IF NOT Sen_Fwd THEN
|
||||||
|
_cylState := CYL_AT_BWD;
|
||||||
|
ELSE
|
||||||
|
_cylState := CYL_MOVING_BWD;
|
||||||
|
END_IF;
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
ELSIF NOT Cmd_Fwd AND NOT Cmd_Bwd THEN
|
||||||
|
// No command — check resting state
|
||||||
|
CASE t_Cfg OF
|
||||||
|
CFG_NONE:
|
||||||
|
_cylState := CYL_IDLE;
|
||||||
|
|
||||||
|
CFG_ONE_FWD:
|
||||||
|
IF Sen_Fwd THEN
|
||||||
|
_cylState := CYL_AT_FWD;
|
||||||
|
ELSE
|
||||||
|
_cylState := CYL_IDLE; // Could be at BWD, we don't know
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
CFG_ONE_BWD:
|
||||||
|
IF Sen_Bwd THEN
|
||||||
|
_cylState := CYL_AT_BWD;
|
||||||
|
ELSE
|
||||||
|
_cylState := CYL_IDLE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
CFG_TWO:
|
||||||
|
IF Sen_Fwd AND NOT Sen_Bwd THEN
|
||||||
|
_cylState := CYL_AT_FWD;
|
||||||
|
_lastKnownState := CYL_AT_FWD;
|
||||||
|
ELSIF Sen_Bwd AND NOT Sen_Fwd THEN
|
||||||
|
_cylState := CYL_AT_BWD;
|
||||||
|
_lastKnownState := CYL_AT_BWD;
|
||||||
|
ELSIF NOT Sen_Fwd AND NOT Sen_Bwd THEN
|
||||||
|
_cylState := CYL_INTERMEDIATE;
|
||||||
|
END_IF;
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
ELSIF Cmd_Fwd AND Cmd_Bwd THEN
|
||||||
|
// Both commands simultaneously → command conflict (programming error)
|
||||||
|
// Treat same as conflict fault
|
||||||
|
_faulted := TRUE;
|
||||||
|
_faultCode := FAULT_CONFLICT;
|
||||||
|
Fault_Conflict := TRUE;
|
||||||
|
_cylState := CYL_FAULTED;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════
|
||||||
|
░░ SECTION 7 — SAFE OUTPUT GATING ░░
|
||||||
|
Only energise actuator outputs when healthy and enabled.
|
||||||
|
This is the key safety pattern: raw command passes through only
|
||||||
|
if the FB is not faulted.
|
||||||
|
═══════════════════════════════════════════════════════════════════════════*)
|
||||||
|
CylCmd_FwdSafe := Cmd_Fwd AND NOT _faulted AND Enable;
|
||||||
|
CylCmd_BwdSafe := Cmd_Bwd AND NOT _faulted AND Enable;
|
||||||
|
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════
|
||||||
|
░░ SECTION 8 — STATUS BOOL OUTPUTS ░░
|
||||||
|
═══════════════════════════════════════════════════════════════════════════*)
|
||||||
|
AtFwd := (_cylState = CYL_AT_FWD);
|
||||||
|
AtBwd := (_cylState = CYL_AT_BWD);
|
||||||
|
Intermediate := (_cylState = CYL_INTERMEDIATE);
|
||||||
|
Moving := (_cylState = CYL_MOVING_FWD) OR (_cylState = CYL_MOVING_BWD);
|
||||||
|
Fault_Active := _faulted;
|
||||||
|
FaultCode := _faultCode;
|
||||||
|
CylState := _cylState;
|
||||||
|
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════
|
||||||
|
░░ SECTION 9 — HMI TEXT GENERATION ░░
|
||||||
|
Pre-formatted strings the HMI can display directly.
|
||||||
|
String 80 chars max. Use CylName to identify which cylinder.
|
||||||
|
═══════════════════════════════════════════════════════════════════════════*)
|
||||||
|
|
||||||
|
// ── Status text ───────────────────────────────────────────────────────────
|
||||||
|
CASE _cylState OF
|
||||||
|
CYL_IDLE:
|
||||||
|
HMI_StatusText := CONCAT(CylName, ': Idle / No command');
|
||||||
|
CYL_MOVING_FWD:
|
||||||
|
HMI_StatusText := CONCAT(CylName, ': Moving → FWD ...');
|
||||||
|
CYL_AT_FWD:
|
||||||
|
HMI_StatusText := CONCAT(CylName, ': At FWD position ✓');
|
||||||
|
CYL_MOVING_BWD:
|
||||||
|
HMI_StatusText := CONCAT(CylName, ': Moving ← BWD ...');
|
||||||
|
CYL_AT_BWD:
|
||||||
|
HMI_StatusText := CONCAT(CylName, ': At BWD position ✓');
|
||||||
|
CYL_INTERMEDIATE:
|
||||||
|
HMI_StatusText := CONCAT(CylName, ': INTERMEDIATE — between sensors');
|
||||||
|
CYL_FAULTED:
|
||||||
|
HMI_StatusText := CONCAT(CylName, ': *** FAULT — see fault message ***');
|
||||||
|
ELSE:
|
||||||
|
HMI_StatusText := CONCAT(CylName, ': Unknown state');
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
// ── Fault text ────────────────────────────────────────────────────────────
|
||||||
|
CASE _faultCode OF
|
||||||
|
FAULT_NONE:
|
||||||
|
HMI_FaultText := '';
|
||||||
|
|
||||||
|
FAULT_FWD_TIMEOUT:
|
||||||
|
HMI_FaultText := CONCAT(CylName,
|
||||||
|
': FWD TIMEOUT — check cylinder, solenoid and FWD sensor');
|
||||||
|
|
||||||
|
FAULT_BWD_TIMEOUT:
|
||||||
|
HMI_FaultText := CONCAT(CylName,
|
||||||
|
': BWD TIMEOUT — check cylinder, solenoid and BWD sensor');
|
||||||
|
|
||||||
|
FAULT_CONFLICT:
|
||||||
|
HMI_FaultText := CONCAT(CylName,
|
||||||
|
': SENSOR CONFLICT — FWD + BWD both active. Check wiring/sensors');
|
||||||
|
|
||||||
|
FAULT_LOST:
|
||||||
|
HMI_FaultText := CONCAT(CylName,
|
||||||
|
': LOST POSITION — cylinder moved without command. Check mechanics');
|
||||||
|
|
||||||
|
ELSE:
|
||||||
|
HMI_FaultText := CONCAT(CylName, ': Unknown fault');
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
END_FUNCTION_BLOCK
|
||||||
|
|
||||||
|
|
||||||
|
(*═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
FB_CylFaultCollector
|
||||||
|
Aggregates faults from up to 8 cylinder monitors into one summary word.
|
||||||
|
The welding sequencer reads CylFaultAny to trigger a machine pause or stop.
|
||||||
|
HMI reads CylFaultWord bitmask + individual fault strings for alarm display.
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
═══════════════════════════════════════════════════════════════════════════════*)
|
||||||
|
|
||||||
|
FUNCTION_BLOCK "FB_CylFaultCollector"
|
||||||
|
{ S7_Optimized_Access := 'TRUE' }
|
||||||
|
VERSION : 0.1
|
||||||
|
|
||||||
|
VAR_INPUT
|
||||||
|
//── FAULT INPUTS FROM UP TO 8 CYLINDER MONITORS ─────────────────────────
|
||||||
|
Cyl1_Fault : Bool;
|
||||||
|
Cyl2_Fault : Bool;
|
||||||
|
Cyl3_Fault : Bool;
|
||||||
|
Cyl4_Fault : Bool;
|
||||||
|
Cyl5_Fault : Bool;
|
||||||
|
Cyl6_Fault : Bool;
|
||||||
|
Cyl7_Fault : Bool;
|
||||||
|
Cyl8_Fault : Bool;
|
||||||
|
|
||||||
|
//── FAULT CODES (from each FB_CylinderMonitor.FaultCode) ────────────────
|
||||||
|
Cyl1_FaultCode : Int;
|
||||||
|
Cyl2_FaultCode : Int;
|
||||||
|
Cyl3_FaultCode : Int;
|
||||||
|
Cyl4_FaultCode : Int;
|
||||||
|
Cyl5_FaultCode : Int;
|
||||||
|
Cyl6_FaultCode : Int;
|
||||||
|
Cyl7_FaultCode : Int;
|
||||||
|
Cyl8_FaultCode : Int;
|
||||||
|
|
||||||
|
//── FAULT TEXTS (from each FB_CylinderMonitor.HMI_FaultText) ────────────
|
||||||
|
Cyl1_FaultText : String[80];
|
||||||
|
Cyl2_FaultText : String[80];
|
||||||
|
Cyl3_FaultText : String[80];
|
||||||
|
Cyl4_FaultText : String[80];
|
||||||
|
|
||||||
|
//── MACHINE RESPONSE CONFIGURATION ──────────────────────────────────────
|
||||||
|
// For each fault type, define machine response:
|
||||||
|
// 0 = Warning only (continue running, amber lamp)
|
||||||
|
// 1 = Pause machine (Cmd_Pause equivalent)
|
||||||
|
// 2 = Stop machine (Cmd_Stop equivalent)
|
||||||
|
Response_Timeout : Int; // Response for timeout faults (codes 1, 2)
|
||||||
|
Response_Conflict : Int; // Response for conflict fault (code 3)
|
||||||
|
Response_Lost : Int; // Response for lost position (code 4)
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR_OUTPUT
|
||||||
|
//── AGGREGATE OUTPUTS (wire to FB_WeldSequencer inputs) ──────────────────
|
||||||
|
CylFaultAny : Bool; // OR of all faults — any cylinder faulted
|
||||||
|
CylFaultWord : Word; // Bitmask: bit0=Cyl1...bit7=Cyl8
|
||||||
|
Cmd_MachinePause : Bool; // → connect to FB_WeldSequencer.Cmd_Pause
|
||||||
|
Cmd_MachineStop : Bool; // → connect to FB_WeldSequencer.Cmd_Stop
|
||||||
|
Cmd_Warning : Bool; // Amber warning lamp (non-stopping fault)
|
||||||
|
|
||||||
|
//── FIRST FAULT REPORTING (for HMI alarm banner) ─────────────────────────
|
||||||
|
FirstFaultCode : Int; // Code of first active fault
|
||||||
|
FirstFaultText : String[80]; // Text of first active fault
|
||||||
|
ActiveFaultCount : Int; // How many cylinders currently faulted
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
VAR
|
||||||
|
_faultBits : Array[1..8] OF Bool;
|
||||||
|
_faultCodes : Array[1..8] OF Int;
|
||||||
|
_i : Int;
|
||||||
|
_faultCount : Int;
|
||||||
|
_firstFound : Bool;
|
||||||
|
_anyPause : Bool;
|
||||||
|
_anyStop : Bool;
|
||||||
|
_anyWarn : Bool;
|
||||||
|
_requiredResponse : Int;
|
||||||
|
END_VAR
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
// ── Collect all faults into arrays ────────────────────────────────────────
|
||||||
|
_faultBits[1] := Cyl1_Fault; _faultCodes[1] := Cyl1_FaultCode;
|
||||||
|
_faultBits[2] := Cyl2_Fault; _faultCodes[2] := Cyl2_FaultCode;
|
||||||
|
_faultBits[3] := Cyl3_Fault; _faultCodes[3] := Cyl3_FaultCode;
|
||||||
|
_faultBits[4] := Cyl4_Fault; _faultCodes[4] := Cyl4_FaultCode;
|
||||||
|
_faultBits[5] := Cyl5_Fault; _faultCodes[5] := Cyl5_FaultCode;
|
||||||
|
_faultBits[6] := Cyl6_Fault; _faultCodes[6] := Cyl6_FaultCode;
|
||||||
|
_faultBits[7] := Cyl7_Fault; _faultCodes[7] := Cyl7_FaultCode;
|
||||||
|
_faultBits[8] := Cyl8_Fault; _faultCodes[8] := Cyl8_FaultCode;
|
||||||
|
|
||||||
|
// ── Reset aggregates ──────────────────────────────────────────────────────
|
||||||
|
CylFaultWord := 0;
|
||||||
|
CylFaultAny := FALSE;
|
||||||
|
_faultCount := 0;
|
||||||
|
_firstFound := FALSE;
|
||||||
|
FirstFaultCode := 0;
|
||||||
|
FirstFaultText := '';
|
||||||
|
_anyPause := FALSE;
|
||||||
|
_anyStop := FALSE;
|
||||||
|
_anyWarn := FALSE;
|
||||||
|
|
||||||
|
// ── Loop all 8 slots ──────────────────────────────────────────────────────
|
||||||
|
FOR _i := 1 TO 8 DO
|
||||||
|
IF _faultBits[_i] THEN
|
||||||
|
CylFaultAny := TRUE;
|
||||||
|
_faultCount := _faultCount + 1;
|
||||||
|
|
||||||
|
// Set bitmask bit (bit 0 = Cyl1)
|
||||||
|
CylFaultWord := WORD_TO_WORD(CylFaultWord OR SHL(IN := WORD#16#0001,
|
||||||
|
N := UINT_TO_INT(INT_TO_UINT(_i - 1))));
|
||||||
|
|
||||||
|
// First fault capture for HMI banner
|
||||||
|
IF NOT _firstFound THEN
|
||||||
|
_firstFound := TRUE;
|
||||||
|
FirstFaultCode := _faultCodes[_i];
|
||||||
|
CASE _i OF
|
||||||
|
1: FirstFaultText := Cyl1_FaultText;
|
||||||
|
2: FirstFaultText := Cyl2_FaultText;
|
||||||
|
3: FirstFaultText := Cyl3_FaultText;
|
||||||
|
4: FirstFaultText := Cyl4_FaultText;
|
||||||
|
ELSE: FirstFaultText := 'Cylinder fault (see fault word)';
|
||||||
|
END_CASE;
|
||||||
|
END_IF;
|
||||||
|
|
||||||
|
// Determine required machine response for this fault code
|
||||||
|
CASE _faultCodes[_i] OF
|
||||||
|
1, 2: _requiredResponse := Response_Timeout;
|
||||||
|
3: _requiredResponse := Response_Conflict;
|
||||||
|
4: _requiredResponse := Response_Lost;
|
||||||
|
ELSE: _requiredResponse := 2; // Unknown → Stop
|
||||||
|
END_CASE;
|
||||||
|
|
||||||
|
CASE _requiredResponse OF
|
||||||
|
0: _anyWarn := TRUE;
|
||||||
|
1: _anyPause := TRUE;
|
||||||
|
2: _anyStop := TRUE;
|
||||||
|
END_CASE;
|
||||||
|
END_IF;
|
||||||
|
END_FOR;
|
||||||
|
|
||||||
|
ActiveFaultCount := _faultCount;
|
||||||
|
Cmd_MachinePause := _anyPause AND NOT _anyStop; // Stop takes priority over pause
|
||||||
|
Cmd_MachineStop := _anyStop;
|
||||||
|
Cmd_Warning := _anyWarn AND NOT _anyPause AND NOT _anyStop;
|
||||||
|
|
||||||
|
END_FUNCTION_BLOCK
|
||||||
529
s7-1500/cylinder_monitor/README_CylinderMonitor.md
Normal file
529
s7-1500/cylinder_monitor/README_CylinderMonitor.md
Normal file
|
|
@ -0,0 +1,529 @@
|
||||||
|
# FB_CylinderMonitor — S7-1500 SCL Universal Cylinder Supervisor
|
||||||
|
|
||||||
|
> **Platform:** Siemens S7-1500 | TIA Portal V18+ | SCL
|
||||||
|
> **Blocks:** `FB_CylinderMonitor` · `FB_CylFaultCollector`
|
||||||
|
> **Companion to:** [`FB_WeldSequencer`](../README.md)
|
||||||
|
|
||||||
|
A drop-in cylinder monitoring library for any pneumatic or hydraulic actuator. Handles all real-world sensor configurations — zero, one, or two position sensors — generates direction-aware timeout faults, detects sensor conflicts and lost positions, gates actuator outputs for safety, and feeds structured fault data directly to an HMI and machine sequencer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [Why This Exists](#1-why-this-exists)
|
||||||
|
2. [Files](#2-files)
|
||||||
|
3. [Sensor Configuration Options](#3-sensor-configuration-options)
|
||||||
|
4. [Fault Logic Per Configuration](#4-fault-logic-per-configuration)
|
||||||
|
5. [FB_CylinderMonitor — Interface](#5-fb_cylindermonitor--interface)
|
||||||
|
6. [FB_CylFaultCollector — Interface](#6-fb_cylfaultcollector--interface)
|
||||||
|
7. [Output Gating Pattern](#7-output-gating-pattern)
|
||||||
|
8. [Integration with FB_WeldSequencer](#8-integration-with-fb_weldsequencer)
|
||||||
|
9. [Demo: Welding Cell (4 cylinders)](#9-demo-welding-cell-4-cylinders)
|
||||||
|
10. [HMI Integration](#10-hmi-integration)
|
||||||
|
11. [TIA Portal Setup](#11-tia-portal-setup)
|
||||||
|
12. [Timing Reference](#12-timing-reference)
|
||||||
|
13. [Fault Code Reference](#13-fault-code-reference)
|
||||||
|
14. [Adapting for Other Applications](#14-adapting-for-other-applications)
|
||||||
|
15. [Safety Notes](#15-safety-notes)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Why This Exists
|
||||||
|
|
||||||
|
Every cylinder in a machine needs the same boilerplate logic:
|
||||||
|
|
||||||
|
- Did it reach position in time? If not → fault
|
||||||
|
- Are both sensors TRUE at once? That's wiring or hardware failure → fault
|
||||||
|
- Did it leave position without being commanded? → fault
|
||||||
|
- What should the machine do when it faults — pause or stop?
|
||||||
|
- What should the operator see on the HMI?
|
||||||
|
|
||||||
|
Writing this 20+ times per machine is error-prone and inconsistent. `FB_CylinderMonitor` encapsulates it once, handles all sensor topologies, and gives you clean `AtFwd`/`AtBwd` booleans that replace raw sensor reads in your step advance conditions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Files
|
||||||
|
|
||||||
|
```
|
||||||
|
📁 CylinderMonitor/
|
||||||
|
├── FB_CylinderMonitor.scl # FB_CylinderMonitor + FB_CylFaultCollector
|
||||||
|
├── DEMO_WeldCellIntegration.scl # Integration demo (4 cylinders + sequencer)
|
||||||
|
└── README_CylinderMonitor.md # This file
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Sensor Configuration Options
|
||||||
|
|
||||||
|
Set `SensorConfig` (INT) on each FB instance:
|
||||||
|
|
||||||
|
| Value | Constant | Sensor Setup | Typical Use |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `0` | `CFG_NONE` | No sensors | Valves, no-feedback actuators |
|
||||||
|
| `1` | `CFG_ONE_FWD` | Sensor at FWD (extended) end only | Clamps, grippers — only care about "closed" |
|
||||||
|
| `2` | `CFG_ONE_BWD` | Sensor at BWD (retracted) end only | Ejectors — only care about "home" |
|
||||||
|
| `3` | `CFG_TWO` | Sensor at both ends | Weld heads, positioners, gates |
|
||||||
|
|
||||||
|
### Which configuration to use?
|
||||||
|
|
||||||
|
```
|
||||||
|
Q: Does the cylinder need to confirm both extended AND retracted?
|
||||||
|
YES → CFG_TWO (3)
|
||||||
|
|
||||||
|
Q: Only need to know it's closed/extended?
|
||||||
|
YES → CFG_ONE_FWD (1)
|
||||||
|
|
||||||
|
Q: Only need to know it's home/retracted?
|
||||||
|
YES → CFG_ONE_BWD (2)
|
||||||
|
|
||||||
|
Q: No sensor at all (timer-only advance)?
|
||||||
|
YES → CFG_NONE (0)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Fault Logic Per Configuration
|
||||||
|
|
||||||
|
### CFG_NONE (0) — No faults possible from position
|
||||||
|
|
||||||
|
```
|
||||||
|
Cmd_Fwd ON ──────────────────────────────────▶ CylCmd_FwdSafe ON
|
||||||
|
CylState = AT_FWD (trusted)
|
||||||
|
No sensors → no timeout → no conflict
|
||||||
|
Advance logic: use sequencer's step timer
|
||||||
|
```
|
||||||
|
|
||||||
|
### CFG_ONE_FWD (1) — Fault on FWD only
|
||||||
|
|
||||||
|
```
|
||||||
|
Cmd_Fwd ON ──┬──────────────────────▶ CylCmd_FwdSafe ON
|
||||||
|
│ Sen_Fwd? ──TRUE────▶ AtFwd = TRUE ✓ (timer reset)
|
||||||
|
│ └─FALSE───▶ T_Timeout running
|
||||||
|
│ │
|
||||||
|
│ ▼ T_Timeout elapsed
|
||||||
|
│ FaultCode = 1 (FWD TIMEOUT)
|
||||||
|
│ Fault_Active = TRUE
|
||||||
|
│ CylCmd_FwdSafe → FALSE (gated off)
|
||||||
|
│
|
||||||
|
Cmd_Bwd ON ──▶ No BWD timeout possible (no BWD sensor)
|
||||||
|
CylState reports AT_BWD when FWD sensor clears
|
||||||
|
```
|
||||||
|
|
||||||
|
### CFG_ONE_BWD (2) — Fault on BWD only
|
||||||
|
|
||||||
|
```
|
||||||
|
Cmd_Bwd ON ──┬──────────────────────▶ CylCmd_BwdSafe ON
|
||||||
|
│ Sen_Bwd? ──TRUE────▶ AtBwd = TRUE ✓ (timer reset)
|
||||||
|
│ └─FALSE───▶ T_Timeout running
|
||||||
|
│ ▼ T_Timeout elapsed
|
||||||
|
│ FaultCode = 2 (BWD TIMEOUT)
|
||||||
|
│
|
||||||
|
Cmd_Fwd ON ──▶ No FWD timeout (no FWD sensor)
|
||||||
|
CylState reports AT_FWD when BWD sensor clears
|
||||||
|
```
|
||||||
|
|
||||||
|
### CFG_TWO (3) — Full fault coverage
|
||||||
|
|
||||||
|
```
|
||||||
|
Cmd_Fwd ON ──▶ Sen_Fwd? ─TRUE──▶ AtFwd ✓ timer cancelled
|
||||||
|
└─FALSE─▶ Timeout FWD → FaultCode 1
|
||||||
|
|
||||||
|
Cmd_Bwd ON ──▶ Sen_Bwd? ─TRUE──▶ AtBwd ✓ timer cancelled
|
||||||
|
└─FALSE─▶ Timeout BWD → FaultCode 2
|
||||||
|
|
||||||
|
BOTH sensors TRUE simultaneously → FaultCode 3 (CONFLICT) → immediate fault
|
||||||
|
No cmd + was at known pos + both sensors go FALSE → FaultCode 4 (LOST)
|
||||||
|
Both Cmd_Fwd AND Cmd_Bwd TRUE → FaultCode 3 (command conflict)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. FB_CylinderMonitor — Interface
|
||||||
|
|
||||||
|
### VAR_INPUT
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `CylName` | `String[32]` | Human name, e.g. `'Clamp Cylinder'` — used in HMI text |
|
||||||
|
| `SensorConfig` | `Int` | 0=NONE, 1=ONE_FWD, 2=ONE_BWD, 3=TWO |
|
||||||
|
| `T_Timeout` | `Time` | Max time for cylinder to reach position |
|
||||||
|
| `Cmd_Fwd` | `Bool` | Extend / close command |
|
||||||
|
| `Cmd_Bwd` | `Bool` | Retract / open command |
|
||||||
|
| `Cmd_Reset` | `Bool` | Rising edge clears fault |
|
||||||
|
| `Sen_Fwd` | `Bool` | Forward / extended position sensor |
|
||||||
|
| `Sen_Bwd` | `Bool` | Backward / retracted position sensor |
|
||||||
|
| `Enable` | `Bool` | FALSE = ignore commands, hold state |
|
||||||
|
|
||||||
|
### VAR_OUTPUT
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `CylCmd_FwdSafe` | `Bool` | **Gated FWD output** — connect to DQ |
|
||||||
|
| `CylCmd_BwdSafe` | `Bool` | **Gated BWD output** — connect to DQ |
|
||||||
|
| `AtFwd` | `Bool` | Position confirmed at FWD |
|
||||||
|
| `AtBwd` | `Bool` | Position confirmed at BWD |
|
||||||
|
| `Intermediate` | `Bool` | Between positions (TWO config, no cmd) |
|
||||||
|
| `Moving` | `Bool` | Command active, not yet confirmed |
|
||||||
|
| `Fault_Active` | `Bool` | Any fault present |
|
||||||
|
| `Fault_FwdTimeout` | `Bool` | Specific fault bit |
|
||||||
|
| `Fault_BwdTimeout` | `Bool` | Specific fault bit |
|
||||||
|
| `Fault_Conflict` | `Bool` | Sensor conflict fault bit |
|
||||||
|
| `Fault_Lost` | `Bool` | Lost position fault bit |
|
||||||
|
| `FaultCode` | `Int` | Numeric code (0–4) |
|
||||||
|
| `CylState` | `Int` | State code (0–6) |
|
||||||
|
| `HMI_StatusText` | `String[80]` | Ready-to-display status |
|
||||||
|
| `HMI_FaultText` | `String[80]` | Ready-to-display fault message |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. FB_CylFaultCollector — Interface
|
||||||
|
|
||||||
|
Aggregates up to 8 cylinder monitor faults into one summary. Wire its outputs to the sequencer's `Cmd_Pause` and `Cmd_Stop`.
|
||||||
|
|
||||||
|
### Key Outputs
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `CylFaultAny` | `Bool` | OR of all cylinder faults |
|
||||||
|
| `CylFaultWord` | `Word` | Bitmask — bit 0 = Cyl1, bit 7 = Cyl8 |
|
||||||
|
| `Cmd_MachinePause` | `Bool` | **Wire to sequencer `Cmd_Pause`** |
|
||||||
|
| `Cmd_MachineStop` | `Bool` | **Wire to sequencer `Cmd_Stop`** |
|
||||||
|
| `Cmd_Warning` | `Bool` | Amber lamp — non-stopping fault |
|
||||||
|
| `FirstFaultText` | `String[80]` | First fault message for HMI banner |
|
||||||
|
| `ActiveFaultCount` | `Int` | Number of cylinders currently faulted |
|
||||||
|
|
||||||
|
### Machine Response Configuration
|
||||||
|
|
||||||
|
| Input | Value | Effect |
|
||||||
|
|---|---|---|
|
||||||
|
| `Response_Timeout` | `0` | Warning only — machine keeps running |
|
||||||
|
| `Response_Timeout` | `1` | Pause machine |
|
||||||
|
| `Response_Timeout` | `2` | Stop machine (requires Reset) |
|
||||||
|
| `Response_Conflict` | `0/1/2` | Same options |
|
||||||
|
| `Response_Lost` | `0/1/2` | Same options |
|
||||||
|
|
||||||
|
**Recommended defaults:**
|
||||||
|
|
||||||
|
```scl
|
||||||
|
Response_Timeout := 1; // Pause — timeout may be temporary, operator can check
|
||||||
|
Response_Conflict := 2; // Stop — two sensors both TRUE = hardware fault
|
||||||
|
Response_Lost := 2; // Stop — cylinder moved without command = mechanical issue
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Output Gating Pattern
|
||||||
|
|
||||||
|
The core safety pattern of this FB is **output gating**. Instead of writing:
|
||||||
|
|
||||||
|
```scl
|
||||||
|
// ❌ Unsafe — raw command goes direct to DQ
|
||||||
|
%Q0.1 := Act_HeadExtend;
|
||||||
|
```
|
||||||
|
|
||||||
|
You write:
|
||||||
|
|
||||||
|
```scl
|
||||||
|
// ✅ Safe — passes through monitor, gated off on fault
|
||||||
|
"DB_CylHead"(
|
||||||
|
Cmd_Fwd := Act_HeadExtend,
|
||||||
|
...
|
||||||
|
);
|
||||||
|
%Q0.1 := "DB_CylHead".CylCmd_FwdSafe; // Only energises if healthy
|
||||||
|
```
|
||||||
|
|
||||||
|
When a fault occurs (timeout, conflict, lost position):
|
||||||
|
|
||||||
|
1. `CylCmd_FwdSafe` → `FALSE` immediately (same scan as fault detection)
|
||||||
|
2. Solenoid valve de-energised → cylinder stops
|
||||||
|
3. `Fault_Active` → `TRUE` → collector → sequencer `Cmd_Pause` or `Cmd_Stop`
|
||||||
|
4. `HMI_FaultText` → operator message describes exactly what failed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Integration with FB_WeldSequencer
|
||||||
|
|
||||||
|
The two FBs communicate in both directions:
|
||||||
|
|
||||||
|
```
|
||||||
|
FB_CylinderMonitor FB_WeldSequencer
|
||||||
|
──────────────────── ─────────────────────────────
|
||||||
|
AtFwd ─────────────────────────────▶ Sen_ClampClosed (step 2 advance)
|
||||||
|
AtFwd ─────────────────────────────▶ Sen_HeadAtWeldPos (step 3 advance)
|
||||||
|
AtBwd ─────────────────────────────▶ Sen_HeadRetracted (step 9 advance)
|
||||||
|
Fault_Active
|
||||||
|
└──▶ FB_CylFaultCollector
|
||||||
|
Cmd_MachinePause ──────────▶ Cmd_Pause (OR with operator PB)
|
||||||
|
Cmd_MachineStop ──────────▶ Cmd_Stop (OR with operator PB)
|
||||||
|
|
||||||
|
FB_WeldSequencer FB_CylinderMonitor
|
||||||
|
───────────────────────────── ────────────────────
|
||||||
|
Act_HeadExtend ─────────────────────▶ Cmd_Fwd
|
||||||
|
Act_HeadRetract ────────────────────▶ Cmd_Bwd
|
||||||
|
Seq_Running OR Seq_Paused ──────────▶ Enable
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step Advance with Monitor vs Raw Sensor
|
||||||
|
|
||||||
|
| Without Monitor | With Monitor |
|
||||||
|
|---|---|
|
||||||
|
| `_stepAdvReady := Sen_ClampClosed` | `_stepAdvReady := "DB_CylClamp".AtFwd` |
|
||||||
|
| Advances even if clamp timed out | Will not advance if monitor is faulted |
|
||||||
|
| No timeout detection | FaultCode 1 triggers machine pause |
|
||||||
|
|
||||||
|
Using `AtFwd`/`AtBwd` from the monitor instead of raw sensor inputs means a faulted cylinder **also prevents step advance**, so the sequencer's own watchdog timer provides a belt-and-braces fallback catch.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Demo: Welding Cell (4 Cylinders)
|
||||||
|
|
||||||
|
The demo file `DEMO_WeldCellIntegration.scl` shows all four configurations side by side:
|
||||||
|
|
||||||
|
| Instance | Cylinder | Config | Timeout | Fault Response |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `DB_CylClamp` | Clamp | ONE_FWD | 2 s | Pause |
|
||||||
|
| `DB_CylHead` | Weld Head | TWO | 3 s | Pause (timeout) / Stop (conflict) |
|
||||||
|
| `DB_CylEject` | Part Ejector | ONE_BWD | 1.5 s | Pause |
|
||||||
|
| `DB_CylGas` | Gas Valve | NONE | n/a | n/a |
|
||||||
|
|
||||||
|
### Execution Order (critical)
|
||||||
|
|
||||||
|
In your OB (OB1 or OB30), call in this order:
|
||||||
|
|
||||||
|
```
|
||||||
|
1st → "DB_CylClamp"(...) FB_CylinderMonitor
|
||||||
|
2nd → "DB_CylHead"(...) FB_CylinderMonitor
|
||||||
|
3rd → "DB_CylEject"(...) FB_CylinderMonitor
|
||||||
|
4th → "DB_CylGas"(...) FB_CylinderMonitor
|
||||||
|
5th → "DB_CylFaults"(...) FB_CylFaultCollector
|
||||||
|
6th → "DB_WeldSeq"(...) FB_WeldSequencer
|
||||||
|
```
|
||||||
|
|
||||||
|
Monitors run first so that `AtFwd`/`AtBwd` and `Fault_Active` values are fresh when the sequencer evaluates step advance conditions and Cmd_Pause/Stop in the same scan.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. HMI Integration
|
||||||
|
|
||||||
|
### Recommended Screen Objects
|
||||||
|
|
||||||
|
#### Cylinder Overview Faceplate (one per cylinder)
|
||||||
|
|
||||||
|
| Element | Tag | Type |
|
||||||
|
|---|---|---|
|
||||||
|
| Status text | `DB_CylClamp.HMI_StatusText` | Text field |
|
||||||
|
| Fault text | `DB_CylClamp.HMI_FaultText` | Text field (red, visible on fault) |
|
||||||
|
| State indicator | `DB_CylClamp.CylState` | Bar/value with colour map |
|
||||||
|
| Moving animation | `DB_CylClamp.Moving` | Animated cylinder graphic |
|
||||||
|
| At FWD lamp | `DB_CylClamp.AtFwd` | Green indicator |
|
||||||
|
| At BWD lamp | `DB_CylClamp.AtBwd` | Green indicator |
|
||||||
|
| Fault lamp | `DB_CylClamp.Fault_Active` | Red indicator |
|
||||||
|
|
||||||
|
#### CylState Colour Map (for bargraph or rectangle)
|
||||||
|
|
||||||
|
| Value | Colour | Label |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 | Grey | Idle |
|
||||||
|
| 1 | Yellow | Moving FWD |
|
||||||
|
| 2 | Green | At FWD ✓ |
|
||||||
|
| 3 | Yellow | Moving BWD |
|
||||||
|
| 4 | Green | At BWD ✓ |
|
||||||
|
| 5 | Orange | Intermediate |
|
||||||
|
| 6 | Red | FAULTED |
|
||||||
|
|
||||||
|
#### Global Alarm Banner
|
||||||
|
|
||||||
|
```
|
||||||
|
Tag: DB_CylFaults.FirstFaultText
|
||||||
|
Visible: DB_CylFaults.CylFaultAny = TRUE
|
||||||
|
Background: Red
|
||||||
|
Example text: "Weld Head: FWD TIMEOUT — check cylinder, solenoid and FWD sensor"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fault Bitmask Display (overview bar)
|
||||||
|
|
||||||
|
```
|
||||||
|
Tag: DB_CylFaults.CylFaultWord (WORD)
|
||||||
|
Display as: 8 individual bit lamps
|
||||||
|
Bit 0 = Clamp Bit 1 = Head Bit 2 = Ejector Bit 3 = Gas ...
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Operator Guidance Text Logic
|
||||||
|
|
||||||
|
For each cylinder fault, the HMI_FaultText already tells the operator exactly what to check:
|
||||||
|
|
||||||
|
```
|
||||||
|
FaultCode 1 → "Clamp Cylinder: FWD TIMEOUT — check cylinder, solenoid and FWD sensor"
|
||||||
|
FaultCode 2 → "Weld Head: BWD TIMEOUT — check cylinder, solenoid and BWD sensor"
|
||||||
|
FaultCode 3 → "Weld Head: SENSOR CONFLICT — FWD + BWD both active. Check wiring/sensors"
|
||||||
|
FaultCode 4 → "Weld Head: LOST POSITION — cylinder moved without command. Check mechanics"
|
||||||
|
```
|
||||||
|
|
||||||
|
No lookup table needed — the text is generated inside the FB using the `CylName` you configured.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. TIA Portal Setup
|
||||||
|
|
||||||
|
### Create Instance DBs
|
||||||
|
|
||||||
|
For each cylinder, right-click project tree → **Add new block** → **Data Block** → Instance DB of `FB_CylinderMonitor`:
|
||||||
|
|
||||||
|
```
|
||||||
|
DB_CylClamp : FB_CylinderMonitor
|
||||||
|
DB_CylHead : FB_CylinderMonitor
|
||||||
|
DB_CylEject : FB_CylinderMonitor
|
||||||
|
DB_CylGas : FB_CylinderMonitor
|
||||||
|
DB_CylFaults : FB_CylFaultCollector
|
||||||
|
```
|
||||||
|
|
||||||
|
### Initial Parameter Setup (in startup OB or first-scan block)
|
||||||
|
|
||||||
|
```scl
|
||||||
|
// Set cylinder names and configs once at startup
|
||||||
|
// (or set directly in instance DB initial values in TIA Portal)
|
||||||
|
|
||||||
|
"DB_CylClamp".CylName := 'Clamp Cylinder';
|
||||||
|
"DB_CylClamp".SensorConfig := 1;
|
||||||
|
"DB_CylClamp".T_Timeout := T#2S;
|
||||||
|
|
||||||
|
"DB_CylHead".CylName := 'Weld Head';
|
||||||
|
"DB_CylHead".SensorConfig := 3;
|
||||||
|
"DB_CylHead".T_Timeout := T#3S;
|
||||||
|
|
||||||
|
"DB_CylEject".CylName := 'Part Ejector';
|
||||||
|
"DB_CylEject".SensorConfig := 2;
|
||||||
|
"DB_CylEject".T_Timeout := T#1500MS;
|
||||||
|
|
||||||
|
"DB_CylGas".CylName := 'Gas Purge Valve';
|
||||||
|
"DB_CylGas".SensorConfig := 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, set initial values directly in the instance DB's data view in TIA Portal — these persist through power cycles.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Timing Reference
|
||||||
|
|
||||||
|
| Cylinder Type | Recommended T_Timeout | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| Fast pneumatic (< 50 mm) | `T#1S` | Small bore, short stroke |
|
||||||
|
| Standard pneumatic | `T#2S` | Most clamps, grippers |
|
||||||
|
| Long-stroke pneumatic | `T#3S`–`T#5S` | Weld heads, gates |
|
||||||
|
| Hydraulic | `T#5S`–`T#15S` | Slower by nature |
|
||||||
|
| Spring-return valve | N/A (NONE config) | No position sensor |
|
||||||
|
|
||||||
|
**Rule of thumb:** Set timeout to 3× the expected travel time. Fast enough to catch real faults, slow enough to avoid nuisance trips on normal variation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Fault Code Reference
|
||||||
|
|
||||||
|
| Code | Name | Cause | HMI Message | Machine Action |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `0` | No fault | Normal | *(empty)* | None |
|
||||||
|
| `1` | FWD timeout | Sen_Fwd not TRUE within T_Timeout after Cmd_Fwd | `"[Name]: FWD TIMEOUT — check cylinder, solenoid and FWD sensor"` | Pause (configurable) |
|
||||||
|
| `2` | BWD timeout | Sen_Bwd not TRUE within T_Timeout after Cmd_Bwd | `"[Name]: BWD TIMEOUT — check cylinder, solenoid and BWD sensor"` | Pause (configurable) |
|
||||||
|
| `3` | Conflict | Sen_Fwd AND Sen_Bwd both TRUE, or Cmd_Fwd AND Cmd_Bwd both TRUE | `"[Name]: SENSOR CONFLICT — FWD + BWD both active. Check wiring/sensors"` | Stop (configurable) |
|
||||||
|
| `4` | Lost position | Was at known position; both sensors dropped with no command | `"[Name]: LOST POSITION — cylinder moved without command. Check mechanics"` | Stop (configurable) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Adapting for Other Applications
|
||||||
|
|
||||||
|
### Add a pressure/flow sensor as virtual FWD confirmation
|
||||||
|
|
||||||
|
```scl
|
||||||
|
// Gas valve with pressure feedback
|
||||||
|
"DB_CylGas"(
|
||||||
|
CylName := 'Gas Valve',
|
||||||
|
SensorConfig := 1, // ONE_FWD
|
||||||
|
T_Timeout := T#1S,
|
||||||
|
Cmd_Fwd := Act_GasValve,
|
||||||
|
Sen_Fwd := PressureSwitch_OK, // Add this DI
|
||||||
|
...
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Motor or servo (use as virtual "cylinder" with limit switches)
|
||||||
|
|
||||||
|
```scl
|
||||||
|
"DB_CylSlide"(
|
||||||
|
CylName := 'Transfer Slide',
|
||||||
|
SensorConfig := 3,
|
||||||
|
T_Timeout := T#4S,
|
||||||
|
Cmd_Fwd := SlideMotor_Fwd,
|
||||||
|
Cmd_Bwd := SlideMotor_Rev,
|
||||||
|
Sen_Fwd := LS_SlideForward,
|
||||||
|
Sen_Bwd := LS_SlideReverse,
|
||||||
|
...
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Changing timeout at runtime
|
||||||
|
|
||||||
|
```scl
|
||||||
|
// Speed-dependent timeout (slow mode vs normal mode)
|
||||||
|
IF SlowMode THEN
|
||||||
|
"DB_CylHead".T_Timeout := T#8S;
|
||||||
|
ELSE
|
||||||
|
"DB_CylHead".T_Timeout := T#3S;
|
||||||
|
END_IF;
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: `T_Timeout` is read by the TON each scan — changes take effect immediately on the next timer start.
|
||||||
|
|
||||||
|
### More than 8 cylinders
|
||||||
|
|
||||||
|
Extend `FB_CylFaultCollector` array declarations from `[1..8]` to `[1..N]` and add corresponding `VAR_INPUT` slots.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Safety Notes
|
||||||
|
|
||||||
|
> ⚠️ `FB_CylinderMonitor` is a **diagnostic and convenience layer**. It is NOT a safety function and should NOT be used as the sole means of protecting personnel from cylinder movement.
|
||||||
|
|
||||||
|
### This FB provides (diagnostic/operational layer):
|
||||||
|
- Timeout detection → pause or stop production
|
||||||
|
- Sensor conflict → immediate output gate + machine stop
|
||||||
|
- HMI guidance text for operator troubleshooting
|
||||||
|
- Output gating (software level only — not certified)
|
||||||
|
|
||||||
|
### This FB does NOT replace (safety layer):
|
||||||
|
- **Hardware safety valves** (5/2 safety valve with spring return for E-Stop)
|
||||||
|
- **Dual-channel safety relay** monitoring for guard interlocks
|
||||||
|
- **Safety PLC** (S7-1500F) for PLd/SIL2 applications
|
||||||
|
- **Mechanical hard stops** preventing overtravel
|
||||||
|
- **Pressure relief valves** on hydraulic systems
|
||||||
|
|
||||||
|
### Minimum safety architecture:
|
||||||
|
|
||||||
|
```
|
||||||
|
E-Stop ──▶ Safety Relay ──▶ Safety Valve ──▶ Cylinder (power removed in hardware)
|
||||||
|
│
|
||||||
|
└──▶ Safety_EStopOK input on FB_WeldSequencer (software layer)
|
||||||
|
|
||||||
|
Door open ──▶ Safety Switch ──▶ Safety Relay
|
||||||
|
│
|
||||||
|
└──▶ Safety_DoorClosed input on FB_WeldSequencer
|
||||||
|
```
|
||||||
|
|
||||||
|
The cylinder monitor's `CylCmd_FwdSafe` / `CylCmd_BwdSafe` outputs control directional valves only. Power removal for E-Stop must be done at the hardware safety relay level, not by this FB.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
| Version | Date | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| 0.1 | 2025 | Initial release — 4 sensor config types, 4 fault codes, HMI text |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
MIT — free to use and adapt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*For the full welding cell sequencer (10 steps, AUTO/INCR mode, stop categories), see [`README.md`](../README.md).*
|
||||||
Loading…
Reference in a new issue