Ошибка Modbus: [Вход / Выход] Нет ответа от удаленного устройства

Я пытаюсь подключиться с моего ноутбука Mac к устройству Modbus ( MR-SI4), используя последовательное соединение с помощью преобразователя USB RS485, который "подключается" к /dev/cu.SLAB_USBtoUART,

Это мой код:

import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

from pymodbus.constants import Endian
from pymodbus.constants import Defaults
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
from pymodbus.transaction import ModbusRtuFramer

# settings for USB-RS485 adapter
SERIAL = '/dev/cu.SLAB_USBtoUART'
BAUD = 19200


# set Modbus defaults

Defaults.UnitId = 1
Defaults.Retries = 5


client = ModbusClient(method='rtu', port=SERIAL, stopbits=1, bytesize=8, timeout=3, baudrate=BAUD, parity='E')

connection = client.connect()
print "Readout started"

#result = client.read_discrete_inputs(0)
#result = client.read_holding_registers(12,19)
result = client.read_input_registers(0,1)
print(result)

Вывод в консоли:

$ sudo python test.py 
Readout started
DEBUG:pymodbus.transaction:Running transaction 1
DEBUG:pymodbus.transaction:send: 0x1 0x4 0x0 0x0 0x0 0x1 0x31 0xca
DEBUG:pymodbus.client.sync:will sleep to wait for 3.5 char
DEBUG:pymodbus.transaction:recv: 
DEBUG:pymodbus.transaction:getting transaction 1
Modbus Error: [Input/Output] No Response received from the remote unit

Я хотел бы немного помочь понять ошибку, которую я получаю. Я пробовал с настройкой pymodbus а также с различными функциями, такими как read_discrete_inputs или же read_holding_registers, Любая помощь?

Спасибо

4 ответа

При работе с Modbus, даже если вы используете высокоуровневую библиотеку, всегда полезно иметь под рукой официальную документацию по Modbus. С помощью документации вы можете проверить, что означает каждый байт вашего кадра:

0x01 0x04 0x00 0x00 0x00 0x01 0x31 0xCA

Первый байт - это адрес устройства (0x01)

Второй байт - это код функции (0x04, Read Input Registers)

Третий и четвертый байты являются стартовой позицией (0x00, 0x00)

Пятый и шестой байты - это количество выходов (0x00, 0x01)

Последние 2 байта являются контрольной CRC (0x31, 0xCA)

Это означает, что вы просите (0x00, 0x01) регистры из входных регистров (0x04) с первой позиции в памяти (0x00, 0x00) с устройства с адресом 1 (0x01),

Фрейм сам по себе правильный, и если программное обеспечение / прошивка устройства соответствует стандарту Modbus, у вас должен быть ответ: регистр, который вы запросили, ИЛИ кадр ошибки (0x01, 0x80, crc, crc),

Тем не менее, мы можем проверить, почему вы не получаете ответ от вашего устройства. Для этого, если вы не уверены в своем коде / в том, что вы спрашиваете / как ведет себя ваше устройство, вы можете использовать внешний инструмент для сравнения результатов. Я бы посоветовал вам что-то вроде Docklight, которое поможет вам установить соединение и отправить / получить кадр Modbus.

Первым делом я проверю параметры подключения:

client = ModbusClient(method='rtu', port=SERIAL, stopbits=1, bytesize=8, timeout=3, baudrate=BAUD, parity='E')

Метод правильный, так как это протокол, который вы запрашиваете.

Порт правильный, в противном случае возвращается системная ошибка.

Тайм-аут - это то, что вызывает ошибку: в течение определенного времени ответ не был получен. В любом случае, проблема, вероятно, не в этом, поскольку вы установили высокое значение для тайм-аута.

Стопбиты не должны мешать приему кадра.

Проблема может быть в скорости передачи и четности: ошибка здесь может вызвать ошибку, вызванную вашим кодом.

Если вы не знаете правильное значение скорости передачи и / или четности, вы можете попробовать использовать наибольшую скорость передачи данных и значения четности: 'N', 'E', 'O', 'M', 'S' (означает: Нет, Четный, Нечетный, Марк, Пробел. По умолчанию Нет).

Если бы я сделал ставку, я бы начал с замены Четного паритета на Нет (parity = 'N').

Если у вас все еще есть проблема, адрес устройства (0x01может быть ошибочным. Адрес может быть представлен значением от 0 (0x00) до 255 (0xFF).

По стандарту протокола, даже если начальный адрес (0x00, 0x00) количество выходов (0x00, 0x01) или crc (0x31, 0xCA) не правы, устройство должно что-то отвечать, но это не всегда так: если вы думаете, что находитесь в такой ситуации, ищите документацию для конкретного устройства.

Последняя возможность - использовать низкоуровневую библиотеку, такую ​​как PySerial, и вы определяете свой собственный протокол.

Я смог обойти эту проблему, установив постоянную RetryOnEmpty в True,

from pymodbus.constants import Defaults
Defaults.RetryOnEmpty = True

Также может быть полезно настроить время ожидания и некоторые повторные попытки.

Defaults.Timeout = 5
Defaults.Retries = 5

https://pymodbus.readthedocs.io/en/v1.3.2/library/constants.html

У меня также была аналогичная ошибка, когда не было ответа. Адрес моего устройства был неправильным. Это была 1, т.е. единица = 1. Предполагалось, что она равна нулю. то естьclient.read_holding_registers(500,1,unit=0)

      import pymodbus
from pymodbus.client.sync import ModbusSerialClient
client = ModbusSerialClient( method = 'rtu', port = "COM4", stopbits = 1, 
bytesize = 8, baudrate=9600 , parity= 'N')
client.connect()
result = client.read_holding_registers(500,1,unit=0)
print(result)

0x0 0x3 0x1 0xf4 0x0 0x1 0xc5 0xd5

В противном случае вывод ошибки был

0x1 0x3 0x1 0xf4 0x0 0x1 0xc5 0xd5

Проверьте это Stack_post.

Вы забыли unit аргумент в .read_input_registers(0, 1, unit=<unit-ID>)

Вы должны иметь как этот фрагмент кода:

result = client.read_input_registers(0, 1, unit=<unit-ID>)

if not result.isError():
    '''isError() method implemented in pymodbus 1.4.0 and above'''

    print(result.registers)  # Note.

else:
    # Handle Error.
    print('Unable to read or there is the connection problem.')

Вы также можете использовать из .read_holding_registers():

result = client.read_holding_registers(0, 1, unit=<unit-ID>)

[ПРИМЕЧАНИЕ]:

  • Во многих случаях unit является 1 в ведомой стороне по умолчанию.
  • Во многих случаях четность RTU отсутствует: parity='N'
  • Убедитесь в праве root на вашем последовательном порту (/dev/cu.SLAB_USBtoUART).
Другие вопросы по тегам