[英]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.