Skip to Content

← Automated Fuse Test Sequences with a Raspberry PLC

Fuse test benchRaspberry PLC 19RGPIOControl

Automated Fuse Test Sequences with a Raspberry PLC — full example

Run standardized fuse tests from Python on a Raspberry PLC: PD, non-fusing and fusing sequences, relay-selected holders, 500 ms monitoring and verdicts.

Complete, runnable program for the Raspberry PLC 19R (fuse-test-sequences.py): wiring header, requirements and integration notes included.

Download the full project pack — freeThis example + the related ones + bill of materials

Read-only preview.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
COMPLETE EXAMPLE — Fuse test sequences (PD, non-fusing, fusing)

Equipment: Raspberry PLC 19R (Industrial Shields)
Based on:  fuse test bench project

Wiring:
  - Sorensen XG supply over SCPI/serial (/dev/ttyUSB0)
  - ADS1015 over I2C: current through 60 mOhm shunt (A0-A1)
  - PLC relays R0.3..R0.6: fuse holder base selection
  - Inputs I0.0/I0.2/I0.3: safety interlocks

Requirements:
  pip3 install pyserial adafruit-circuitpython-ads1x15 python3-librpiplc

Standardized test types:
  PD         — dissipation measurement: rated current, record Vdrop
  NON_FUSING — 1.13·In for 1 h: the fuse must NOT blow
  FUSING     — 1.45·In: the fuse MUST blow before the time limit

Integration with the catalog:
  - Supply:      sorensen-scpi-power-supply-control.py
  - Measurement: ads1015-differential-adc-autogain.py
  - Loop:        closed-loop-current-calibration.py
  - Safety:      safety-interlocks-emergency-stop.py
  - Report:      txt-test-reports.py
"""

import time
from rpiplc_lib import rpiplc

# Relay that connects each fuse holder base to the power circuit
BASE_RELAY = {"22x58": "R0.3", "14x51": "R0.4", "10x38": "R0.5", "NH00": "R0.6"}

MONITOR_PERIOD_S = 0.5           # monitoring every 500 ms
FUSING_CRITERION = 0.5           # blown if I_measured < 0.5 * I_setpoint

# Automatic mode: setpoints per test type loaded from a reference
# file (embedded here so the example is self-contained)
TEST_TABLE = {
    "PD":         {"in_factor": 1.00, "duration_s": 180,  "must_blow": False},
    "NON_FUSING": {"in_factor": 1.13, "duration_s": 3600, "must_blow": False},
    "FUSING":     {"in_factor": 1.45, "duration_s": 3600, "must_blow": True},
}


def select_base(base):
    """Energize only the relay of the chosen base (the rest stay open)."""
    for name, relay in BASE_RELAY.items():
        rpiplc.pin_mode(relay, rpiplc.OUTPUT)
        state = rpiplc.HIGH if name == base else rpiplc.LOW
        rpiplc.digital_write(relay, state)


def run_test(supply, read_current, check_interlocks,
             test_type, fuse_in, base):
    """Run a test and return a dict with the result."""
    cfg = TEST_TABLE[test_type]
    setpoint = fuse_in * cfg["in_factor"]
    samples = []

    print("Test %s | base %s | In=%.0f A -> setpoint %.1f A"
          % (test_type, base, fuse_in, setpoint))
    select_base(base)
    supply.set_current(setpoint)   # after closed-loop calibration
    supply.output(True)

    t0 = time.time()
    verdict = "NOT_BLOWN"
    while time.time() - t0 < cfg["duration_s"]:
        # 1) safety ALWAYS first
        reason = check_interlocks()
        if reason is not None:
            supply.output(False)
            return {"type": test_type, "result": "ABORTED", "reason": reason}

        # 2) measurement and fusing criterion
        i_measured = read_current()
        samples.append(i_measured)
        if i_measured < FUSING_CRITERION * setpoint:
            verdict = "BLOWN"
            break
        time.sleep(MONITOR_PERIOD_S)

    supply.output(False)
    passed = (verdict == "BLOWN") == cfg["must_blow"]
    return {"type": test_type, "result": verdict,
            "passed": passed, "t_s": round(time.time() - t0, 1),
            "i_avg": round(sum(samples) / max(len(samples), 1), 2)}


def main():
    rpiplc.init("RPIPLC_19R")

    # Stubs to run the example without hardware: on the real bench the
    # catalog modules cited in the header are imported instead.
    class DemoSupply:
        def set_current(self, a): print("  [SCPI] SOUR:CURR %.2f" % a)
        def output(self, on): print("  [SCPI] OUTP %s" % ("ON" if on else "OFF"))

    demo_setpoint = [28.3]
    def read_current_demo():
        demo_setpoint[0] *= 0.93     # simulates a fuse gradually blowing
        return demo_setpoint[0]

    result = run_test(
        supply=DemoSupply(),
        read_current=read_current_demo,
        check_interlocks=lambda: None,
        test_type="FUSING", fuse_in=20.0, base="10x38")

    print("\nResult:", result)
    # The 'result' dict is the input of the TXT report generator


if __name__ == "__main__":
    main()
Download the full project pack — freeThis example + the related ones + bill of materials