← 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