Ir al contenido

← Schneider Altivar 320 por Modbus TCP desde Raspberry Pi

Riego agrícola automatizadoRaspberry Pi (Docker)Modbus TCPControl

Schneider Altivar 320 por Modbus TCP desde Raspberry Pi — ejemplo completo

Arranca, para y supervisa un Schneider Altivar 320 por Modbus TCP desde Raspberry Pi: máquina de estados DriveCom, consigna de velocidad y presión.

Programa completo y ejecutable para el Raspberry Pi (Docker) (altivar320-modbus-tcp-control.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 -*-
#
# COMPLETE EXAMPLE — Control of a Schneider Altivar 320 VFD over Modbus TCP
#
# Hardware:  Raspberry Pi (Docker) + Schneider Altivar 320 (Modbus TCP module)
# Based on:  automated agricultural irrigation project
#
# Requirements:
#   pip install pymodbus>=3.0
#   - VFD with Modbus TCP communication configured ([COM] menu of the ATV320).
#   - The ATV320 responds on Unit ID 255 (adapter default value).
#   - 4-20 mA pressure transducer (0-10 bar) wired to analog input AI3.
#
# What it does:
#   1. Drives the DriveCom (CiA402) state machine of the VFD:
#      Shutdown -> Switch On -> Enable Operation, writing the CMD register.
#   2. Sets the speed setpoint in rpm (LFRD register).
#   3. Reads status (ETA), actual speed (RFRD) and current (LCR).
#   4. Reads the irrigation network pressure from AI3 and converts it to bar.

import time
import sys

from pymodbus.client import ModbusTcpClient

# ---------------------------------------------------------------------------
# Configuration (adjust to your installation)
# ---------------------------------------------------------------------------
ATV_IP = "192.168.1.110"     # IP address of the Altivar 320
ATV_PORT = 502
UNIT_ID = 255                # Default Unit ID of the ATV320 over Modbus TCP

# Modbus registers of the ATV320 (see communication manual NVE41308)
REG_CMD = 8501               # CMDD  - DriveCom command word
REG_LFRD = 8602              # LFRD  - speed setpoint (rpm)
REG_ETA = 3201               # ETAD  - DriveCom status word
REG_RFRD = 8604              # RFRD  - actual speed (rpm)
REG_LCR = 3204               # LCR   - motor current (0.1 A)
REG_AI3 = 5270               # AI3C  - AI3 physical value (0.01 mA) — adjust
                             #         if it differs in your firmware version

# DriveCom command words (CiA402)
CMD_SHUTDOWN = 0x0006        # Ready to switch on
CMD_SWITCH_ON = 0x0007       # Switched on
CMD_ENABLE_OP = 0x000F       # Operation enabled (run)
CMD_STOP = 0x0006            # Back to Ready = ramp stop

IRRIGATION_SPEED_RPM = 2200  # Pump setpoint during the irrigation cycle


def read_reg(client, reg):
    rr = client.read_holding_registers(reg, count=1, slave=UNIT_ID)
    if rr.isError():
        raise IOError(f"Modbus error reading register {reg}: {rr}")
    return rr.registers[0]


def write_reg(client, reg, value):
    wr = client.write_register(reg, value, slave=UNIT_ID)
    if wr.isError():
        raise IOError(f"Modbus error writing register {reg}: {wr}")


def pressure_bar(client):
    """AI3 in 0.01 mA -> pressure in bar (4-20 mA transducer = 0-10 bar)."""
    ma = read_reg(client, REG_AI3) / 100.0      # actual mA at the input
    ma = max(4.0, min(20.0, ma))                # clamp to the sensor range
    return (ma - 4.0) / 16.0 * 10.0             # linear scaling to 0-10 bar


def start_pump(client, rpm):
    """Full DriveCom sequence to put the VFD into run state."""
    write_reg(client, REG_LFRD, rpm)            # setpoint before the run command
    for cmd in (CMD_SHUTDOWN, CMD_SWITCH_ON, CMD_ENABLE_OP):
        write_reg(client, REG_CMD, cmd)
        time.sleep(0.1)                         # margin between transitions
    print(f"Pump running, setpoint {rpm} rpm")


def stop_pump(client):
    write_reg(client, REG_CMD, CMD_STOP)        # stop with deceleration ramp
    print("Stop command sent (ramp)")


def status(client):
    eta = read_reg(client, REG_ETA)
    rpm = read_reg(client, REG_RFRD)
    amp = read_reg(client, REG_LCR) / 10.0
    bar = pressure_bar(client)
    fault = bool(eta & 0x0008)                  # bit 3 of ETA = fault
    print(
        f"ETA=0x{eta:04X} | {rpm:5d} rpm | {amp:5.1f} A | "
        f"{bar:4.2f} bar | {'FAULT' if fault else 'OK'}"
    )
    return fault


def main():
    client = ModbusTcpClient(ATV_IP, port=ATV_PORT)
    if not client.connect():
        print(f"ERROR: no connection to the ATV320 at {ATV_IP}")
        sys.exit(1)

    try:
        start_pump(client, IRRIGATION_SPEED_RPM)
        # Supervision for 60 s: in production this loop is handled by Node-RED
        for _ in range(12):
            if status(client):
                print("VFD fault: aborting irrigation cycle")
                break
            time.sleep(5)
    finally:
        stop_pump(client)
        client.close()


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