PYModbus无法复现Modpoll寄存器读取功能问题求助
问题:PYModbus可写入Modbus寄存器但无法读取,Modpoll可正常读取
背景
尝试了多个PYModbus相关修复方案,能成功向寄存器写入数据,但无法读取该寄存器。已确认目标寄存器为读写(RW)类型,产品规格文档可查。
可正常工作的Modpoll命令
modpoll -m rtu -0 -1 -a 1 -b 9600 -p none -r 48 /dev/ttyUSB0
原PYModbus代码
from pymodbus.client import ModbusSerialClient as modbus # 连接Modbus设备 def connect(self) -> None: self.modbus = modbus(method='rtu', port="/dev/ttyUSB0", baudrate=9600, stopbits=1, bytesize=8, timeout=1) self.modbus.connect() # 可正常工作的寄存器写入函数 def set_voltage(self, voltage:float =0) -> None: if (voltage < self.min_volt) or (voltage > self.max_volt): raise modbusError( "Invalid voltage provided to the interface, voltage provided: {0}" .format(voltage)) self.modbus.write_register(0x0030, int(voltage*100), unit=1) # 读取寄存器函数(报错) def get_voltage_target(self) -> float: reg = self.modbus.read_holding_registers(0x0030, 1, unit=1) print(reg.registers)
报错信息
AttributeError: 'ModbusIOException' object has no attribute 'registers'
简化测试代码
from pymodbus.client import ModbusSerialClient as RTUClient import logging logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG) PowerSupplyMB = RTUClient(method='rtu', port="/dev/ttyUSB0", baudrate=9600,stopbits=1,bytesize=8,timeout=1) PowerSupplyMB.connect() PowerSupplyMB.write_register(0x0030, int(10.2*100), unit=1) mb_response = PowerSupplyMB.read_holding_registers(0x0030, 1, unit=1) if not mb_response.isError(): '''isError() method implemented in pymodbus 1.4.0 and above''' print(mb_response.registers) # 问题出在这里 else: # 错误处理 print('Error message: {}'.format(mb_response))
简化代码的调试日志
DEBUG:pymodbus.logging:Current transaction state - IDLE DEBUG:pymodbus.logging:Running transaction 1 DEBUG:pymodbus.logging:SEND: 0x0 0x3 0x0 0x30 0x0 0x1 0x85 0xd4 DEBUG:pymodbus.logging:New Transaction state "SENDING" DEBUG:pymodbus.logging:Changing transaction state from "SENDING" to "WAITING FOR REPLY" DEBUG:pymodbus.logging:Transaction failed. (Modbus Error: [Invalid Message] No response received, expected at least 4 bytes (0 received)) DEBUG:pymodbus.logging:Frame - [b''] not ready DEBUG:pymodbus.logging:Getting transaction 0 DEBUG:pymodbus.logging:Changing transaction state from "PROCESSING REPLY" to "TRANSACTION_COMPLETE" Error message: Modbus Error: [Input/Output] Modbus Error: [Invalid Message] No response received, expected at least 4 bytes (0 received)
进一步排查发现,registers返回错误:Modbus Error: [Input/Output] No Response received from the remote slave/Unable to decode response
解决方案
1. 修复RTU帧的从站地址错误
从调试日志的发送帧0x0 0x3 0x0 0x30 0x0 0x1 0x85 0xd4可以看出,帧的第一个字节是0x0,但你的设备从站地址是1,这是核心问题。PYModbus在高版本中可能存在参数传递顺序的歧义,需要显式指定参数名确保从站地址正确传入:
修改读取寄存器的代码:
def get_voltage_target(self) -> float: # 显式指定address、count、unit参数 response = self.modbus.read_holding_registers(address=0x0030, count=1, unit=1) if response.isError(): print(f"读取错误: {response}") return 0.0 return response.registers[0] / 100.0
2. 补全串口参数并延长超时
Modpoll使用无校验(-p none),虽然PYModbus默认是无校验,但显式指定可避免歧义;同时设备响应可能较慢,适当延长超时时间:
PowerSupplyMB = RTUClient(method='rtu', port="/dev/ttyUSB0", baudrate=9600, stopbits=1, bytesize=8, parity='N', # 显式指定无校验 timeout=2) # 延长超时至2秒
3. 处理事务ID异常
日志显示事务ID不匹配(发送ID为1,获取ID为0),可以手动指定事务ID并使用RTU帧格式器:
from pymodbus.transaction import ModbusRtuFramer PowerSupplyMB = RTUClient(method='rtu', port="/dev/ttyUSB0", baudrate=9600, stopbits=1, bytesize=8, parity='N', timeout=2, framer=ModbusRtuFramer) # 手动设置事务ID PowerSupplyMB.transaction_id = 1
4. 确认串口独占性
运行PYModbus前必须关闭Modpoll,确保串口没有被其他进程占用,否则无法接收设备回复。
验证修改效果
修改后查看调试日志,正确的发送帧第一个字节应为0x1(从站地址1),类似:0x1 0x3 0x0 0x30 0x0 0x1 0x85 0xd4,此时应该能正常收到设备回复。
内容的提问来源于stack exchange,提问作者Hos
相关产品推荐
相关产品推荐

