1

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

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

我已经检查了我的 Arduino 奴隶是否工作正常。我尝试通过 Modbus Master 仿真器 (QModMaster) 读取数据,它工作得很好。这可能证明问题本身来自于 Master 的代码。此外,串行连接似乎工作正常,因为 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)
4

3 回答 3

2

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
    )
于 2019-05-30T12:57:53.290 回答
1

感谢少数人的帮助,我已经找到了解决方案。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)
于 2019-06-02T12:52:03.003 回答
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 规范定义了这两种不同类型的寄存器:保持和输入,具体取决于它们所在的内存区域。

于 2019-05-30T14:21:16.127 回答