Master请求保存Arduino Slave注册表值时Pymodbus异常如何解决

How to solve Pymodbus exception when Master requests for holding registry values of the Arduino Slave

我目前正在尝试从我的 Arduino slave 接收数据到我的电脑。我成功地创建了一个 Arduino slave。但是,当我尝试使用 Pymodbus 库从我的计算机接收数据时,我的代码无法从 Arduino 接收数据并引发 ModbusIOException。对于我的项目的规格,我正在尝试使用 Arduino 构建一个 Modbus RTU 来模拟一个带有随机数作为读数的传感器。 Arduino 代码使用 Andre Sarmento 的 Modbus-Arduino 库。

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

我已经检查了我的 Arduino slave 是否正常工作。我尝试通过 Modbus Master 仿真器 (QModMaster) 读取数据,它工作得很好。这可能证明问题本身来自Master的代码。此外,串行连接似乎工作正常,因为 self.client.connect() returns True.

这些是 QModMaster 配置的屏幕截图。

Slave configurations Serial Port configurations

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)

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
    )

您正在从站中定义保持寄存器,但您正试图将它们作为输入寄存器读取,请尝试更改此行:

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

收件人:

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

请注意,Modbus 规范定义了这两种不同类型的寄存器:保持和输入,具体取决于它们所在的内存区域。

在几个人的帮助下,我已经找到了解决办法。 QModMaster 使用一个名为 libmodbus 的库。由于 Arduino 模拟从机和传感器与 QModMaster 一起工作,因此更改以前的库并改用 libmodbus 会更容易。幸运的是,libmodbus 有一个 python 等价物,它是 pylibmodbus。这是库 https://github.com/stephane/pylibmodbus 的 link。

    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)