簡體   English   中英

當Master請求保存Arduino Slave注冊表值時如何解決Pymodbus異常

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

我目前正在嘗試從Arduino從設備接收數據到計算機。 我成功創建了Arduino從站。 但是,當我嘗試使用Pymodbus庫從計算機接收數據時,我的代碼無法從Arduino接收數據,並引發了ModbusIOException。 對於我的項目規范,我正在嘗試使用Arduino構建Modbus RTU,以模擬具有隨機數作為讀數的傳感器。 Arduino代碼使用Andre Sarmento的Modbus-Arduino庫。

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

我已經檢查了我的Arduino從站是否正常工作。 我嘗試通過Modbus主站仿真器(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)

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的鏈接。

    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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM