Come Inviare Comandi RS485 con Python

D

Daniel Zhang

Ultimo aggiornamento Jul 12, 2026

Python è un linguaggio di programmazione ampiamente utilizzato. L'invio di comandi Modbus tramite Python offre un modo pratico per controllare le operazioni del motore. Di seguito è riportato un semplice esempio di codice per l'invio di comandi Modbus utilizzando Python. I comandi Modbus sono tratti dall'articolo Istruzioni operative RS485 del servomotore A6, in particolare dalla Sezione 2.3, "Movimento in posizione assoluta di 5000 impulsi (Impostazione predefinita: 10000 impulsi/giro, C00.02=10000)." Questo codice è applicabile ai servoazionamenti della serie A6-RS di StepperOnline e controlla il motore in modalità posizione assoluta per 5000 impulsi.

Di seguito il codice Python:

import serial
import time
import binascii
from crcmod import crcmod

# Configurazione della porta seriale - modificare in base al dispositivo in uso
PORT = 'COM3'  # Porta seriale (Windows: 'COM3', Linux: '/dev/ttyUSB0')
BAUDRATE = 9600  # Velocità di trasmissione (valori comuni: 9600, 19200, 38400, 57600, 115200)
PARITY = serial.PARITY_NONE
STOPBITS = serial.STOPBITS_ONE
BYTESIZE = serial.EIGHTBITS
TIMEOUT = 0.5  # Timeout di lettura in secondi

# Creazione della funzione CRC16 Modbus
modbus_crc = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)

# Definizioni dei comandi (senza CRC)
commands_without_crc = [
    "010600000000",  # Imposta la modalità di controllo dell'azionamento su modalità posizione C00.00=0
    "010611010000",  # Imposta il profilo di posizione su posizionamento assoluto C11.01=0
    "010603000002",  # Imposta la sorgente del comando di posizione su incremento a passi C03.00=2
    "0106030D0001",  # Imposta la velocità di rotazione a 1 rpm C03.0D=1
    "0106030C1388",  # Imposta lo spostamento a 5000 impulsi C03.0C=5000
    "010604000022",  # Configura DI1 come abilitazione incremento di posizione a passi C04.00=34 (0x22)
    "010604110001",  # Abilita il motore e avvia l'operazione C04.11=1
    "010604010001",  # Attiva l'abilitazione DI1 C04.01=1
    "010604110000",  # Comando di arresto di emergenza, disabilita il motore C04.11=0
    "010604010000"   # Disabilita DI1 C04.01=0
]

# Descrizioni dei comandi
descriptions = [
    "Imposta la modalità di controllo dell'azionamento su modalità posizione (C00.00=0)",
    "Imposta il profilo di posizione su posizionamento assoluto (C11.01=0)",
    "Imposta la sorgente del comando di posizione su incremento a passi (C03.00=2)",
    "Imposta la velocità di rotazione a 1 rpm (C03.0D=1)",
    "Imposta lo spostamento a 5000 impulsi (C03.0C=5000)",
    "Configura DI1 come abilitazione incremento di posizione a passi (C04.00=34)",
    "Abilita il motore e avvia l'operazione (C04.11=1)",
    "Attiva l'abilitazione DI1 (C04.01=1)",
    "Comando di arresto di emergenza, disabilita il motore (C04.11=0)",
    "Disabilita DI1 (C04.01=0)"
]

def calculate_crc(hex_str):
    """Calcola il CRC16 Modbus per una stringa esadecimale"""
    data = binascii.unhexlify(hex_str)
    crc = modbus_crc(data)
    # Restituisce il CRC in formato little-endian (byte basso per primo)
    return bytes([crc & 0xFF, (crc >> 8) & 0xFF])

def format_hex(data):
    """Formatta i dati in byte come stringa esadecimale"""
    return ' '.join([f"{b:02X}" for b in data])

def send_modbus_command(ser, hex_cmd, description):
    """Invia un singolo comando Modbus e gestisce la risposta"""
    try:
        # Calcola il CRC e lo aggiunge al comando
        crc_bytes = calculate_crc(hex_cmd)
        full_cmd = binascii.unhexlify(hex_cmd) + crc_bytes

        # Invia il comando
        ser.write(full_cmd)
        print(f"\nInvio comando: {description}")
        print(f"Dati: {format_hex(full_cmd)}")

        # Attesa elaborazione del dispositivo
        time.sleep(0.3)

        # Lettura della risposta (la risposta Modbus RTU è tipicamente di 8 byte)
        response = ser.read(8)

        if response:
            print(f"Risposta del dispositivo: {format_hex(response)}")
            return True
        else:
            print("Errore: nessuna risposta ricevuta!")
            return False

    except Exception as e:
        print(f"Errore nell'invio del comando: {str(e)}")
        return False

def main():
    # Creazione della connessione seriale
    try:
        ser = serial.Serial(
            port=PORT,
            baudrate=BAUDRATE,
            parity=PARITY,
            stopbits=STOPBITS,
            bytesize=BYTESIZE,
            timeout=TIMEOUT
        )
        print(f"Connesso con successo alla porta seriale: {ser.name}\n")
    except serial.SerialException as e:
        print(f"Impossibile aprire la porta seriale: {str(e)}")
        return
    except Exception as e:
        print(f"Si è verificato un errore: {str(e)}")
        return

    # Invio di tutti i comandi
    for i, (cmd, desc) in enumerate(zip(commands_without_crc, descriptions), 1):
        print(f"Esecuzione comando {i}/{len(commands_without_crc)}")
        success = send_modbus_command(ser, cmd, desc)

        if not success:
            print("Esecuzione del comando fallita, terminazione del programma")
            break

        # Applica un ritardo maggiore per i comandi critici
        if "Abilita" in desc or "Attiva" in desc or "emergenza" in desc:
            time.sleep(1.0)  # Ritardo maggiore per i comandi relativi al movimento
        else:
            time.sleep(0.5)  # Ritardo standard per i comandi di configurazione

    # Chiusura della porta seriale
    ser.close()
    print("\nTutti i comandi elaborati, porta seriale chiusa")

if __name__ == "__main__":
    main()

Note:

a. Questo codice si basa sulla libreria crcmod per eseguire la verifica CRC sui comandi Modbus. È necessario installare le librerie richieste prima di eseguire il codice:

pip install pyserial crcmod

b. Impostare la porta COM corretta (PORT) e la velocità di trasmissione (BAUDRATE) in base alla configurazione effettiva del dispositivo. Regolare i parametri di ritardo (time.sleep) in base al tempo di risposta del dispositivo.

c. I comandi Modbus in questo esempio sono applicabili solo ai servoazionamenti della serie A6-RS di StepperOnline. Se si utilizzano altri azionamenti, come i servoazionamenti della serie DSY-RS, i servoazionamenti della serie T6 o gli azionamenti per motori passo-passo della serie RS di StepperOnline, modificare i comandi Modbus in base al manuale del rispettivo azionamento.