0

I have a question, I do a communication test by Modbus TCP and each request takes approximately 200ms, is it possible to improve these times?

This is the code that I use for the tests:

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
import time
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

t1= time.time()
client = ModbusClient(method='rtu', port='COM7', baudrate=9600, timeout=1, 
parity='N')
response = client.read_holding_registers(address=13313, count=12, unit=0x02)
respuesta=response.registers[0:12]
client.close()
print(time.time()-t1)
MM87
  • 41
  • 6
  • 2
    Yes, I think 199 ms is possible. - No, really, premature optimization is the root of all evil [Donald Knuth]. What time do you *need* or does your hardware *need*? You can optimize everything, but without a requirement, it's useless. Suggestion 1: buy a faster machine. Suggestion 2: use a higher baud rate. Suggestion 3: do not instantiate a new client for each request. Reuse the client. – Thomas Weller Sep 11 '18 at 20:42
  • 1
    Well, I'd rather suggest a faster serial line. transferring a modbus message with 12 registers is likely not far off 200ms at 9600 baud – nos Sep 11 '18 at 20:56
  • Thomas sarcastic response but it works, reusing the client allowing it to be closed once a string is finished, decreasing the request time. Thank you ! – MM87 Sep 12 '18 at 13:52

2 Answers2

3

Based on your comm settings, each transmitted char/byte should be:

1 start bit
8 data bit
0 parity bits
2 stop bits (this should be 2 -> spec says 11 bits/char, but I have seen implementations that use 8N1)
-------------------------------
total: 11 bits/byte

1) Request

address:                1 byte
function code:          1 byte
starting address:       2 bytes
quantity of registers:  2 bytes
crc:                    2 bytes
-------------------------------
total: 8 bytes

Min time: 1s/9600bits * (8 bytes) * (11 bits/byte) = 9.2 ms

2) Silent Interval Between Frames

Min time: 1s/9600bits * (3.5 bytes) * (11 bits/byte) = 4.0 ms

3) Response

address:          1 byte
function code:    1 byte
byte count:       2 bytes
register values:  24 bytes (2*12)
crc:              2 bytes
-------------------------------
total: 30 bytes

Min Time = 1s/9600bits * (30 bytes) * (11 bits/byte) = 34.3 ms

Thus, the theoretical minimum round trip time is: 9.2 + 4.0 + 34.3 = 47.5 ms

So it looks like there is potentially room for improvement, but hard to know exactly where your delays are.

In addition to what others have suggested, I usually put a scope on the comm lines to see if the tx and rx frames are close to the theoretical times. You should also be able to tell about how long it takes for the server to respond by looking at the time between the end of the tx and start of the rx frames. If you can somehow trigger the scope just before you start sending the request, you can also measure the time it takes for the client to generate and start transmitting the request frame.

Marker
  • 972
  • 6
  • 9
  • Thx, reuse the client's startup and close it once only allows you to reach the times you mention (approx 0.06ms). – MM87 Sep 12 '18 at 13:53
  • @MM87, yes, my analysis did not account for any delays in the code it was purely from a hardware standpoint. There are many code and/or OS things that could be causing delays, using a scope helps to narrow down where to look. – Marker Sep 12 '18 at 14:12
  • @MM87 What took approx 0.06 ms? It takes 0.1 ms per bit at 9600, that's only 2 bits. – Marker Sep 12 '18 at 14:19
  • sorry, request take 60ms – MM87 Sep 13 '18 at 15:34
1

I get very fast results with the minimalmodbus lib. MinimalModbus API. Works with Python 3. Maybe you could try it and compare?

import minimalmodbus
import serial
import struct
import time

i = minimalmodbus.Instrument(port='COM7', slaveaddress=1, mode='rtu')
i.serial.baudrate = 19200
i.serial.bytesize = 8
i.serial.parity = serial.PARITY_NONE
i.serial.stopbits = 1
i.serial.timeout = 1
i.debug = False

start = time.time()
var1 = i.read_registers(registeraddress=13313, numberOfRegisters=2, functioncode=4)
var1_ = [var1[0], var1[1]]
var1_pack = struct.pack('HH', var1_[0], var1_[1])
var1_unpack = struct.unpack('f', var1_pack)[0]
end = time.time()

print('Result: {}. Total time: {}'.format(var1_unpack, (end - start)))

Aside from that, maxing-out your baudrate will maximize speed, but 200ms per poll is pretty slow; I don't think baudrate alone will cure that. There could also be other factors at play; what converter you're using, what cabling, how long the cabling is, etc.

ChumiestBucket
  • 868
  • 4
  • 22
  • 51