Cómo enviar comandos RS485 mediante Python

D

Daniel Zhang

Última actualización el Jul 12, 2026

Python es un lenguaje de programación de uso generalizado. El envío de comandos Modbus a través de Python ofrece una forma cómoda de controlar las operaciones del motor. A continuación se muestra un ejemplo sencillo de código para enviar comandos Modbus utilizando Python. Los comandos Modbus se han tomado del artículo Instrucciones de funcionamiento RS485 del servomotor A6, concretamente de la sección 2.3, "Movimiento de posición absoluta de 5000 pulsos (configuración predeterminada: 10000 pulsos/rev, C00.02=10000)". Este código es aplicable a los servodrive StepperOnline de la serie A6-RS y controla el motor para que funcione en modo de posición absoluta durante 5000 pulsos.

A continuación se muestra el código Python:

import serial
import time
import binascii
from crcmod import crcmod

# Configuración del puerto serie - modificar según el dispositivo real
PORT = 'COM3'  # Puerto serie (Windows: 'COM3', Linux: '/dev/ttyUSB0')
BAUDRATE = 9600  # Velocidad de transmisión (valores habituales: 9600, 19200, 38400, 57600, 115200)
PARITY = serial.PARITY_NONE
STOPBITS = serial.STOPBITS_ONE
BYTESIZE = serial.EIGHTBITS
TIMEOUT = 0.5  # Tiempo de espera de lectura en segundos

# Crear función Modbus CRC16
modbus_crc = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)

# Definición de comandos (sin CRC)
commands_without_crc = [
    "010600000000",  # Establecer modo de control del drive en modo posición C00.00=0
    "010611010000",  # Establecer perfil de posición en posicionamiento absoluto C11.01=0
    "010603000002",  # Establecer fuente de comando de posición en incremento escalonado C03.00=2
    "0106030D0001",  # Establecer velocidad de funcionamiento en 1 rpm C03.0D=1
    "0106030C1388",  # Establecer desplazamiento en 5000 pulsos C03.0C=5000
    "010604000022",  # Configurar DI1 como habilitación de incremento escalonado de posición C04.00=34 (0x22)
    "010604110001",  # Habilitar motor e iniciar funcionamiento C04.11=1
    "010604010001",  # Activar habilitación de DI1 C04.01=1
    "010604110000",  # Comando de parada de emergencia, deshabilitar motor C04.11=0
    "010604010000"   # Deshabilitar DI1 C04.01=0
]

# Descripciones de los comandos
descriptions = [
    "Establecer modo de control del drive en modo posición (C00.00=0)",
    "Establecer perfil de posición en posicionamiento absoluto (C11.01=0)",
    "Establecer fuente de comando de posición en incremento escalonado (C03.00=2)",
    "Establecer velocidad de funcionamiento en 1 rpm (C03.0D=1)",
    "Establecer desplazamiento en 5000 pulsos (C03.0C=5000)",
    "Configurar DI1 como habilitación de incremento escalonado de posición (C04.00=34)",
    "Habilitar motor e iniciar funcionamiento (C04.11=1)",
    "Activar habilitación de DI1 (C04.01=1)",
    "Comando de parada de emergencia, deshabilitar motor (C04.11=0)",
    "Deshabilitar DI1 (C04.01=0)"
]

def calculate_crc(hex_str):
    """Calcular Modbus CRC16 para una cadena hexadecimal"""
    data = binascii.unhexlify(hex_str)
    crc = modbus_crc(data)
    # Devolver CRC en formato little-endian (byte bajo primero)
    return bytes([crc & 0xFF, (crc >> 8) & 0xFF])

def format_hex(data):
    """Formatear datos de bytes como cadena hexadecimal"""
    return ' '.join([f"{b:02X}" for b in data])

def send_modbus_command(ser, hex_cmd, description):
    """Enviar un único comando Modbus y gestionar la respuesta"""
    try:
        # Calcular CRC y añadirlo al comando
        crc_bytes = calculate_crc(hex_cmd)
        full_cmd = binascii.unhexlify(hex_cmd) + crc_bytes

        # Enviar comando
        ser.write(full_cmd)
        print(f"\nEnviando comando: {description}")
        print(f"Datos: {format_hex(full_cmd)}")

        # Esperar procesamiento del dispositivo
        time.sleep(0.3)

        # Leer respuesta (la respuesta Modbus RTU suele ser de 8 bytes)
        response = ser.read(8)

        if response:
            print(f"Respuesta del dispositivo: {format_hex(response)}")
            return True
        else:
            print("Error: ¡No se ha recibido respuesta!")
            return False

    except Exception as e:
        print(f"Error al enviar comando: {str(e)}")
        return False

def main():
    # Crear conexión serie
    try:
        ser = serial.Serial(
            port=PORT,
            baudrate=BAUDRATE,
            parity=PARITY,
            stopbits=STOPBITS,
            bytesize=BYTESIZE,
            timeout=TIMEOUT
        )
        print(f"Conectado correctamente al puerto serie: {ser.name}\n")
    except serial.SerialException as e:
        print(f"Error al abrir el puerto serie: {str(e)}")
        return
    except Exception as e:
        print(f"Se ha producido un error: {str(e)}")
        return

    # Enviar todos los comandos
    for i, (cmd, desc) in enumerate(zip(commands_without_crc, descriptions), 1):
        print(f"Ejecutando comando {i}/{len(commands_without_crc)}")
        success = send_modbus_command(ser, cmd, desc)

        if not success:
            print("Error en la ejecución del comando, finalizando programa")
            break

        # Aplicar un retardo mayor para comandos críticos
        if "Habilitar" in desc or "Activar" in desc or "emergencia" in desc:
            time.sleep(1.0)  # Retardo mayor para comandos relacionados con movimiento
        else:
            time.sleep(0.5)  # Retardo estándar para comandos de configuración

    # Cerrar puerto serie
    ser.close()
    print("\nTodos los comandos procesados, puerto serie cerrado")

if __name__ == "__main__":
    main()

Notas:

a. Este código utiliza la librería crcmod para realizar la verificación CRC de los comandos Modbus. Es necesario instalar las librerías requeridas antes de ejecutar el código:

pip install pyserial crcmod

b. Configure el puerto COM (PORT) y la velocidad de transmisión (BAUDRATE) correctos según la configuración real de su dispositivo. Ajuste los parámetros de retardo (time.sleep) en función del tiempo de respuesta de su dispositivo.

c. Los comandos Modbus de este ejemplo solo son aplicables a los servodrive StepperOnline de la serie A6-RS. Si utiliza otros drives, como los servodrive StepperOnline de la serie DSY-RS, los servodrive de la serie T6 o los drivers de motores paso a paso de la serie RS, modifique los comandos Modbus según el manual del drive correspondiente.