首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何解决Master请求保存Arduino Slave的注册表值时的Pymodbus异常

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

Stack Overflow用户
提问于 2019-05-30 20:34:36
回答 3查看 1.7K关注 0票数 1

我目前正在尝试从我的Arduino从服务器接收数据到我的计算机。我成功地创建了一个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配置的屏幕截图。

Slave configurations Serial Port configurations

主服务器的Python代码:

代码语言:javascript
运行
复制
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代码:

代码语言:javascript
运行
复制
#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:

代码语言:javascript
运行
复制
'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)

它也给出了这个信息。

代码语言:javascript
运行
复制
Modbus Error: [Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 2 bytes (0 received)
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-06-02 20:52:03

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

代码语言:javascript
运行
复制
    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
EN

Stack Overflow用户

发布于 2019-05-30 20:57:53

print(result.registers)之前,请尝试以下代码片段:

代码语言:javascript
运行
复制
if not result.isError():
    print(result.registers)
else:
    print("error: {}".format(result))

另外,填写其他ModbusSerialClient()参数。

下面是您的代码片段的更新:

代码语言:javascript
运行
复制
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
    )
票数 2
EN

Stack Overflow用户

发布于 2019-05-30 22:21:16

你在你的从机中定义了保持寄存器,但是你试图将它们读取为输入寄存器,试着改变这一行:

代码语言:javascript
运行
复制
result = self.client.read_input_registers(address=1, count=2, unit=1)

至:

代码语言:javascript
运行
复制
result = self.client.read_holding_registers(address=1, count=2, unit=1)

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56378428

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档