You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 16:07:06