pyhys / minimalmodbus

Easy-to-use Modbus RTU and Modbus ASCII implementation for Python.
Apache License 2.0
306 stars 146 forks source link

Timeout after frame #122

Open pfrl opened 1 year ago

pfrl commented 1 year ago

Timeout after request frame does not take into account request length (examples below have no physical Modbus devices connected, those are only the requests).

Test script:


from minimalmodbus import _MAX_NUMBER_OF_REGISTERS_TO_WRITE, Instrument  # type: ignore

device = Instrument("/dev/ttyUSB0", 1)
if device.serial is not None:
    device.serial.baudrate = 38400
    device.serial.parity = "E"
    device.serial.timeout = 0.1

while True:
    try:
        device.write_registers(0, [0] * _MAX_NUMBER_OF_REGISTERS_TO_WRITE)
    except:
        pass
System info ```text Minimalmodbus version: 2.1.1 pySerial version: 3.5 Platform: Arch Linux x86_64 / 6.4.12-arch1-1 Filesystem encoding: 'utf-8' Byteorder: little Python version: 3.11.5 (main, Aug 28 2023, 20:02:58) [GCC 13.2.1 20230801] Python version info: sys.version_info(major=3, minor=11, micro=5, releaselevel='final', serial=0) Python flags: sys.flags(debug=0, inspect=0, interactive=0, optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, ignore_environment=0, verbose=0, bytes_warning=0, quiet=0, hash_randomization=1, isolated=0, dev_mode=False, utf8_mode=0, warn_default_encoding=0, safe_path=False, int_max_str_digits=-1) Python argv: ['/usr/bin/ipython'] Python prefix: '/usr' Python exec prefix: '/usr' Python executable: '/usr/bin/python' Float repr style: 'short' Variable __name__: minimalmodbus ```
1. Writing maximum number of registers with timeout set to 100ms. ![100ms](https://github.com/pyhys/minimalmodbus/assets/144025123/7d84af0b-e347-45a2-b0c4-ed4eed13f07b) Time between frames ~41ms
2. Writing maximum number of registers with timeout set to 50ms. Request frame "eats" away the wait period for response. ![50ms](https://github.com/pyhys/minimalmodbus/assets/144025123/5ca6fd89-3aa8-4879-abb0-dcda792623e2) Time between frames 0ms
3. Writing 40 registers with timeout set to 50ms. ![40data_50ms](https://github.com/pyhys/minimalmodbus/assets/144025123/7f05a1ab-c03b-44d2-a937-2f1b2f65ddc2) Time between frames ~29ms

To prevent the issue I've added serial.flush after serial.write in minimalmodbus.py, line 1468

        # Write request
        write_time = time.monotonic()
        self.serial.write(request)
        self.serial.flush() ## added line

After the changes:

1. Writing maximum number of registers with timeout set to 100ms. ![100ms](https://github.com/pyhys/minimalmodbus/assets/144025123/d244bee3-2f4d-4265-a834-17deba802e97)
2. Writing maximum number of registers with timeout set to 50ms. ![50ms](https://github.com/pyhys/minimalmodbus/assets/144025123/5edda5bf-4a2d-4e88-a3ab-26ee9d5c9a5e)
3. Writing 40 registers with timeout set to 50ms. ![40data_50ms](https://github.com/pyhys/minimalmodbus/assets/144025123/b73a1418-076e-4a84-8b26-8afe13d28228)

I've used flush with conviction that it is a nondestructive wait operation. I do not know if that change is adequate to be implemented.

Response times are a little bit longer then expected (possibly extended by MODBUS RTU 3.5 character time).

The issue came around when stress testing some older siemens PLC (slow response times) with faster devices.