Отправка команд RS485 с помощью Python

D

Daniel Zhang

Обновлено Jul 12, 2026

Python — широко распространённый язык программирования. Отправка команд Modbus через Python обеспечивает удобный способ управления работой двигателя. Ниже приведён простой пример кода для отправки команд Modbus с помощью Python. Команды Modbus взяты из статьи Инструкция по работе с серводвигателем A6 через RS485, раздел 2.3, «Перемещение в абсолютную позицию на 5000 импульсов (настройка по умолчанию: 10000 импульсов/об, C00.02=10000)». Данный код применим к сервоприводам серии A6-RS производства StepperOnline и управляет двигателем в режиме абсолютного позиционирования на 5000 импульсов.

Ниже приведён код на Python:

import serial
import time
import binascii
from crcmod import crcmod

# Настройки последовательного порта — измените в соответствии с вашим устройством
PORT = 'COM3'  # Последовательный порт (Windows: 'COM3', Linux: '/dev/ttyUSB0')
BAUDRATE = 9600  # Скорость передачи (распространённые значения: 9600, 19200, 38400, 57600, 115200)
PARITY = serial.PARITY_NONE
STOPBITS = serial.STOPBITS_ONE
BYTESIZE = serial.EIGHTBITS
TIMEOUT = 0.5  # Таймаут чтения в секундах

# Создание функции расчёта CRC16 для Modbus
modbus_crc = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)

# Определения команд (без CRC)
commands_without_crc = [
    "010600000000",  # Установка режима управления привода в режим позиционирования C00.00=0
    "010611010000",  # Установка команды профиля позиции в абсолютное позиционирование C11.01=0
    "010603000002",  # Установка источника команды позиции в пошаговое приращение C03.00=2
    "0106030D0001",  # Установка рабочей скорости 1 об/мин C03.0D=1
    "0106030C1388",  # Установка перемещения на 5000 импульсов C03.0C=5000
    "010604000022",  # Настройка DI1 как включение пошагового приращения позиции C04.00=34 (0x22)
    "010604110001",  # Включение двигателя и запуск работы C04.11=1
    "010604010001",  # Срабатывание включения DI1 C04.01=1
    "010604110000",  # Команда аварийной остановки, отключение двигателя C04.11=0
    "010604010000"   # Отключение DI1 C04.01=0
]

# Описания команд
descriptions = [
    "Установка режима управления привода в режим позиционирования (C00.00=0)",
    "Установка профиля позиции в абсолютное позиционирование (C11.01=0)",
    "Установка источника команды позиции в пошаговое приращение (C03.00=2)",
    "Установка рабочей скорости 1 об/мин (C03.0D=1)",
    "Установка перемещения на 5000 импульсов (C03.0C=5000)",
    "Настройка DI1 как включение пошагового приращения позиции (C04.00=34)",
    "Включение двигателя и запуск работы (C04.11=1)",
    "Срабатывание включения DI1 (C04.01=1)",
    "Команда аварийной остановки, отключение двигателя (C04.11=0)",
    "Отключение DI1 (C04.01=0)"
]

def calculate_crc(hex_str):
    """Расчёт CRC16 Modbus для hex-строки"""
    data = binascii.unhexlify(hex_str)
    crc = modbus_crc(data)
    # Возврат CRC в формате little-endian (младший байт первым)
    return bytes([crc & 0xFF, (crc >> 8) & 0xFF])

def format_hex(data):
    """Форматирование байтовых данных в hex-строку"""
    return ' '.join([f"{b:02X}" for b in data])

def send_modbus_command(ser, hex_cmd, description):
    """Отправка одной команды Modbus и обработка ответа"""
    try:
        # Расчёт CRC и добавление к команде
        crc_bytes = calculate_crc(hex_cmd)
        full_cmd = binascii.unhexlify(hex_cmd) + crc_bytes

        # Отправка команды
        ser.write(full_cmd)
        print(f"\nОтправка команды: {description}")
        print(f"Данные: {format_hex(full_cmd)}")

        # Ожидание обработки устройством
        time.sleep(0.3)

        # Чтение ответа (ответ Modbus RTU обычно 8 байт)
        response = ser.read(8)

        if response:
            print(f"Ответ устройства: {format_hex(response)}")
            return True
        else:
            print("Ошибка: ответ не получен!")
            return False

    except Exception as e:
        print(f"Ошибка отправки команды: {str(e)}")
        return False

def main():
    # Создание последовательного соединения
    try:
        ser = serial.Serial(
            port=PORT,
            baudrate=BAUDRATE,
            parity=PARITY,
            stopbits=STOPBITS,
            bytesize=BYTESIZE,
            timeout=TIMEOUT
        )
        print(f"Успешное подключение к порту: {ser.name}\n")
    except serial.SerialException as e:
        print(f"Не удалось открыть последовательный порт: {str(e)}")
        return
    except Exception as e:
        print(f"Произошла ошибка: {str(e)}")
        return

    # Отправка всех команд
    for i, (cmd, desc) in enumerate(zip(commands_without_crc, descriptions), 1):
        print(f"Выполнение команды {i}/{len(commands_without_crc)}")
        success = send_modbus_command(ser, cmd, desc)

        if not success:
            print("Выполнение команды не удалось, завершение программы")
            break

        # Увеличенная задержка для критических команд
        if "Enable" in desc or "Trigger" in desc or "Emergency" in desc:
            time.sleep(1.0)  # Увеличенная задержка для команд движения
        else:
            time.sleep(0.5)  # Стандартная задержка для команд конфигурации

    # Закрытие последовательного порта
    ser.close()
    print("\nВсе команды обработаны, последовательный порт закрыт")

if __name__ == "__main__":
    main()

Примечания:

a. Данный код использует библиотеку crcmod для выполнения проверки CRC команд Modbus. Перед запуском кода необходимо установить требуемые библиотеки:

pip install pyserial crcmod

b. Укажите правильный COM-порт (PORT) и скорость передачи (BAUDRATE) в соответствии с фактической конфигурацией вашего устройства. Настройте параметры задержки (time.sleep) в зависимости от времени отклика вашего устройства.

c. Команды Modbus в данном примере применимы только к сервоприводам серии A6-RS производства StepperOnline. Если вы используете другие приводы — например, сервоприводы серии DSY-RS, сервоприводы серии T6 или шаговые приводы серии RS производства StepperOnline — измените команды Modbus в соответствии с руководством по эксплуатации соответствующего привода.