Как устранить исключение Pymodbus, когда Master запрашивает хранение значений реестра ведомого устройства Arduino - PullRequest
1 голос
/ 30 мая 2019

Я сейчас пытаюсь получить данные от моего ведомого Arduino на мой компьютер.Я успешен в создании Arduino-раба.Однако, когда я пытаюсь получить данные с моего компьютера с помощью библиотеки Pymodbus, мой код не получает данные от Arduino и вызывает исключение ModbusIOException.Для спецификаций моего проекта я пытаюсь построить Modbus RTU с Arduino для имитации датчика со случайными числами в качестве показаний.В коде Arduino используется библиотека Modbus-Arduino Андре Сарменто.

https://github.com/andresarmento/modbus-arduino

Я уже проверил свое ведомое устройство Arduino, если оно работает.Я попытался прочитать данные через эмулятор Modbus Master (QModMaster), и он работал просто отлично.Это может доказать, что сама проблема в коде Мастера.Более того, похоже, что последовательное соединение работает нормально, так как self.client.connect () возвращает True.

Это скриншоты конфигураций QModMaster.

Конфигурации ведомых Конфигурации последовательного порта

Код Python для мастера:

class ModbusRTU:
    def __init__(self, graph_name, port, baudrate=9600, 
                 stopbits=1, bytesize=8, parity='N', 
                 timeout=1):                                       
        self.graph_name = graph_name
        self.client = ModbusSerialClient(method='rtu', 
                                         port=port, 
                                         baudrate=baudrate, 
                                         parity=parity, 
                                         timeout=timeout)
        self.connection = self.client.connect()
        result = self.client.read_holding_registers(address=0, 
                                                  count=2, 
                                                  unit=1)
        print(result.registers) 

if __name__ == '__main__':
    modbus = ModbusRTU(graph_name='/dev/ttyACM0', 
                       port='/dev/ttyACM0', baudrate=9600, 
                       stopbits=1, bytesize=8, parity='N', 
                       timeout=1)
    print(modbus.check_connection())

Код Arduino для моделируемого подчиненного устройства и датчика:

#include <Modbus.h>
#include <ModbusSerial.h>

ModbusSerial mb;
const int READING = 0;
const int DECIMAL = 1;

void setup() {
  mb.config(&Serial, 9600, SERIAL_8N1);
  mb.setSlaveId(1);
  mb.addHreg(READING);
  mb.addHreg(DECIMAL);
}

void loop() {
  mb.task();
  mb.Hreg(READING, random(1, 201));
  mb.Hreg(DECIMAL, random(0, 4));
}

Попечать results.registers, это предположительно список целых чисел.Тем не менее, он просто вызывает ModbusIOException с сообщением:

'ModbusIOException' object has no attribute 'registers'
  File "/home/kebaranas/PythonProjects/ThirsyWell/tools/utilities.py", line 21, in __init__
    print(result.registers)
  File "/home/kebaranas/PythonProjects/ThirsyWell/tools/utilities.py", line 29, in <module>
    timeout=1)

Это также дает это сообщение.

Modbus Error: [Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 2 bytes (0 received)

Ответы [ 3 ]

2 голосов
/ 30 мая 2019

До print(result.registers) попробуйте следующий фрагмент кода:

if not result.isError():
    print(result.registers)
else:
    print("error: {}".format(result))

Также введите другой аргумент ModbusSerialClient().

Вот обновленный фрагмент вашего кода:

from pymodbus.client.sync import ModbusSerialClient

class ModbusRTU:
    def __init__(self, graph_name, port, baudrate=9600,
                 stopbits=1, bytesize=8, parity='N',
                 timeout=1):
        self.graph_name = graph_name
        self.client = ModbusSerialClient(
            method='rtu',
            port=port,
            baudrate=baudrate,
            parity=parity,
            timeout=timeout,
            stopbits=stopbits,
            bytesize=bytesize
        )
        self.connection = self.client.connect()
        result = self.client.read_input_registers(address=1,
                                                  count=2,
                                                  unit=1)
        if not result.isError():
            print(result.registers)
        else:
            print("error: {}".format(result))

if __name__ == '__main__':
    modbus = ModbusRTU(
        graph_name='/dev/ttyACM0',
        port='/dev/ttyACM0', baudrate=9600,
        stopbits=1, bytesize=8, parity='N',
        timeout=1
    )
1 голос
/ 02 июня 2019

Я уже нашел решение для этого, спасибо за помощь немногим. QModMaster использует библиотеку под названием libmodbus. Так как Arduino моделировал ведомое устройство и датчик работал с QModMaster, было бы легче изменить предыдущую библиотеку и вместо этого использовать libmodbus. К счастью, для libmodbus есть эквивалент python, который называется pylibmodbus. Это ссылка на библиотеку https://github.com/stephane/pylibmodbus.

    from pylibmodbus import ModbusRtu


    class ModbusRTU:
        def __init__(self, port, baudrate=9600, databit=8, parity='None', 
                     stopbit=1, timeout=1000):
            self.parity = {'Odd': 'O', 'Even': 'E', 'None': 'N'}
            self.modbus = ModbusRtu(device=port.encode('ascii'),   
                                    data_bit=databit, baud=baudrate,
                                    parity=self.parity[parity] \
                                           .encode('ascii'), 
                                    stop_bit=stopbit)
            self.modbus.set_response_timeout(timeout/1000)
            self.modbus.connect()
            self.modbus.set_slave(1)
            result = self.modbus.read_registers(0, 2)
            print(result)
            self.modbus.close()


    if __name__ == '__main__':
        main = ModbusRTU('/dev/ttyACM0', baudrate=9600, databit=8, 
                         parity='None', stopbit=1)
1 голос
/ 30 мая 2019

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

result = self.client.read_input_registers(address=1, count=2, unit=1)

Кому:

result = self.client.read_holding_registers(address=1, count=2, unit=1)

BeПомните, что спецификация Modbus определяет эти два различных типа регистров: хранение и ввод, в зависимости от области памяти, в которой они находятся.

...