使用Python通过IP读取Modbus控制器数据遇AttributeError求助
问题:读取Modbus控制器数据时触发AttributeError错误
尝试通过IP地址从Modbus控制器读取数据,使用的Python代码如下:
from pymodbus.client.sync import ModbusTcpClient as ModbusClient client = ModbusClient("10.98.237.80", port=502, auto_open=True) client.connect() rr = client.read_holding_registers(60, 2, unit=1) print (rr.registers)
运行后出现如下异常:
2023-04-03 14:57:18,678 MainThread DEBUG sync :216 Connection to Modbus server established. Socket ('10.80.144.99', 64492) 2023-04-03 14:57:18,680 MainThread DEBUG transaction :140 Current transaction state - IDLE 2023-04-03 14:57:18,681 MainThread DEBUG transaction :145 Running transaction 1 2023-04-03 14:57:18,682 MainThread DEBUG transaction :273 SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x3 0x0 0x3c 0x0 0x2 2023-04-03 14:57:18,683 MainThread DEBUG sync :76 New Transaction state 'SENDING' 2023-04-03 14:57:18,684 MainThread DEBUG transaction :287 Changing transaction state from 'SENDING' to 'WAITING FOR REPLY' 2023-04-03 14:57:20,082 MainThread DEBUG transaction :375 Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY' 2023-04-03 14:57:20,083 MainThread DEBUG transaction :297 RECV: 0x0 0x1 0x0 0x0 0x0 0x3 0x1 0x83 0xfc 2023-04-03 14:57:20,084 MainThread DEBUG socket_framer :147 Processing: 0x0 0x1 0x0 0x0 0x0 0x3 0x1 0x83 0xfc 2023-04-03 14:57:20,084 MainThread DEBUG factory :266 Factory Response[131] 2023-04-03 14:57:20,085 MainThread DEBUG transaction :454 Adding transaction 1 2023-04-03 14:57:20,085 MainThread DEBUG transaction :465 Getting transaction 1 2023-04-03 14:57:20,086 MainThread DEBUG transaction :224 Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE' --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-11-1ea661f8edc1> in <module> 6 rr = client.read_holding_registers(60, 2, unit=1) 7 ----> 8 print (rr.registers) AttributeError: 'ExceptionResponse' object has no attribute 'registers'
解决方案
1. 错误原因解析
报错'ExceptionResponse' object has no attribute 'registers'说明Modbus控制器返回了错误响应,而非正常的寄存器数据。从日志里的响应数据0x1 0x83 0xfc可以看出:
0x83是错误版的读保持寄存器功能码(正常功能码为0x03,错误响应会在功能码上加0x80);0xfc是控制器返回的错误码,这个不属于标准Modbus错误码,需要参考设备说明书确认含义。
2. 代码优化:先判断响应类型
修改代码,先检查响应是否为异常,避免直接访问registers报错,同时打印错误信息方便排查:
from pymodbus.client.sync import ModbusTcpClient as ModbusClient client = ModbusClient("10.98.237.80", port=502, auto_open=True) client.connect() rr = client.read_holding_registers(60, 2, unit=1) # 先判断是否为正常响应 if hasattr(rr, 'registers'): print("读取到的寄存器数据:", rr.registers) else: print(f"Modbus错误码: {hex(rr.exception_code)}") # 标准Modbus错误码对应说明,供参考 error_map = { 0x01: "非法功能码:控制器不支持读保持寄存器操作", 0x02: "非法数据地址:起始地址60超出控制器的保持寄存器范围", 0x03: "非法数据值:读取的寄存器数量2不符合设备要求", 0x04: "从站故障:控制器内部出现错误", 0x05: "确认失败:设备无法执行请求", 0x06: "从站忙:设备正在处理其他请求" } print(error_map.get(rr.exception_code, "未知错误码,请参考设备说明书"))
3. 关键排查点
- 从站地址(unit参数):确认控制器的Modbus从站地址是否为
1,部分设备默认地址为0或其他值; - 寄存器地址:注意Modbus有两种地址表示方式:基于0的索引和基于1的编号。pymodbus的
read_holding_registers第一个参数是基于0的索引,如果设备文档里的地址是基于1的,需要减1后再传入; - 寄存器类型:如果要读取的是输入寄存器(而非保持寄存器),需要改用
read_input_registers方法(对应功能码0x04); - 网络与服务状态:确认客户端与控制器在同一网段/路由可达,防火墙未阻挡502端口,且控制器的Modbus TCP服务已开启并监听502端口;
- 设备说明书:针对返回的
0xfc错误码,查看控制器的官方文档,确认具体错误原因。
内容的提问来源于stack exchange,提问作者SM079
相关产品推荐
相关产品推荐

