Ir al contenido

← Calibración de corriente en lazo cerrado con Raspberry PLC

Banco de ensayo de fusiblesRaspberry PLC 19RSCPII2CControl

Calibración de corriente en lazo cerrado con Raspberry PLC — ejemplo completo

Calibración de corriente en lazo cerrado en Python: lee un shunt cada 50 ms con un ADS1015 y ajusta la consigna SCPI en pasos de 0.1 A hasta converger.

Programa completo y ejecutable para el Raspberry PLC 19R (closed-loop-current-calibration.py): incluye cabecera de conexionado, requisitos y notas de integración.

Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales

Vista de solo lectura.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
FULL EXAMPLE — Closed-loop current calibration

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

Wiring:
  - Sorensen XG power supply over SCPI/serial on /dev/ttyUSB0 (9600 baud)
  - ADS1015 over I2C (0x48): 60 mOhm shunt on A0-A1

Requirements:
  pip3 install pyserial adafruit-circuitpython-ads1x15

Idea:
  The supply delivers "its" current, but the test is certified against the
  REAL current measured at the shunt. This loop reads the shunt every 50 ms
  and trims the SCPI setpoint in ±0.1 A steps until the measurement
  converges with the target (5 s timeout).

Integration with the catalog:
  - Supply driver: sorensen-scpi-power-supply-control.py
  - Current measurement: ads1015-differential-adc-autogain.py
  - This loop runs at the start of every test sequence
    (fuse-test-sequences.py).
"""

import time
import serial

# --- Loop parameters --------------------------------------------------------
PERIOD_S = 0.05       # read the shunt every 50 ms
STEP_A = 0.1          # trim the setpoint in ±0.1 A steps
TOLERANCE_A = 0.15    # dead band: inside it the loop is considered converged
TIMEOUT_S = 5.0       # maximum calibration time

# --- Power supply (reduced version of the SCPI driver in the catalog) -------
class PowerSupply:
    def __init__(self, port="/dev/ttyUSB0"):
        self.ser = serial.Serial(port=port, baudrate=9600,
                                 bytesize=serial.EIGHTBITS,
                                 parity=serial.PARITY_NONE,
                                 stopbits=serial.STOPBITS_ONE, timeout=1)
        self._tx("*ADR 1")

    def _tx(self, cmd):
        self.ser.write((cmd + "\r").encode())
        time.sleep(0.05)

    def set_current(self, amps):
        self._tx("SOUR:CURR %.2f" % amps)

    def output(self, on):
        self._tx("OUTP %s" % ("ON" if on else "OFF"))


def read_shunt_current():
    """Real current through the 60 mOhm shunt via ADS1015 (gain x16).

    The full auto-ranging version lives in ads1015-differential-adc-autogain.py;
    this is the bench formula in short:
      current = (raw/65535) * 2.0 * 0.256 * 200.0 / 0.06 * 1.02
    """
    raw = _read_raw_ads1015()  # differential reading A0-A1
    return (raw / 65535.0) * 2.0 * 0.256 * 200.0 / 0.06 * 1.02


def _read_raw_ads1015():
    import adafruit_ads1x15.ads1015 as ADS
    from adafruit_ads1x15.analog_in import AnalogIn
    import board, busio
    ads = ADS.ADS1015(busio.I2C(board.SCL, board.SDA), address=0x48)
    ads.gain = 16
    return AnalogIn(ads, ADS.P0, ADS.P1).value


def calibrate(supply, target_a):
    """Trim the setpoint until the shunt current matches the target.

    Returns (final_setpoint, measured_current, converged).
    """
    setpoint = target_a   # first approximation: setpoint = target
    supply.set_current(setpoint)
    t0 = time.time()

    while time.time() - t0 < TIMEOUT_S:
        measured = read_shunt_current()
        error = target_a - measured

        if abs(error) <= TOLERANCE_A:
            return setpoint, measured, True  # converged

        # Fixed 0.1 A correction steps in the direction of the error
        setpoint += STEP_A if error > 0 else -STEP_A
        setpoint = max(0.0, min(setpoint, 220.0))  # XG limits
        supply.set_current(setpoint)
        time.sleep(PERIOD_S)

    return setpoint, read_shunt_current(), False  # timed out without converging


def main():
    supply = PowerSupply()
    target = 32.0  # A — e.g. non-fusing test of a 25 A fuse

    try:
        supply.output(True)
        print("Calibrating to %.1f A..." % target)
        setpoint, measured, ok = calibrate(supply, target)

        print("Final setpoint : %.2f A" % setpoint)
        print("Real current   : %.2f A" % measured)
        print("Result         : %s" % ("CONVERGED" if ok else "TIMEOUT 5 s"))
        # The test itself would start here, using the calibrated setpoint
    finally:
        supply.output(False)


if __name__ == "__main__":
    main()
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales