Pymodbus прочитал холдинговые регистры - PullRequest
0 голосов
/ 26 октября 2018

Мне было поручено выполнить задание без какой-либо документации. У меня проблема с чтением данных из MODBUS. Вот сценарий, который мне удалось создать:

from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.client.sync import ModbusTcpClient

client = ModbusTcpClient('X.X.X.X')
connection = client.connect()

request = client.read_holding_registers(12606,2)
result = request.registers
decoder = BinaryPayloadDecoder.fromRegisters(result, Endian.Big, wordorder=Endian.Little)
print "Counter1: %0.2f" % decoder.decode_32bit_float()

request = client.read_holding_registers(12482,2)
result = request.registers
decoder = BinaryPayloadDecoder.fromRegisters(result, Endian.Big, wordorder=Endian.Little)
print "Counter2: %0.2f" % decoder.decode_32bit_float()

client.close()

Все выглядит хорошо, но данные на счетчике отличаются от данных в скрипте, например:

Value on the counter : 39558853.30 (value is decimal)
Value from the script: 58853.30
(value is decimal)

Read input registers (HEX): E54D 4765

А вот так выглядит адресная документация "

P   12458       Q2  4\DW12458 = 1\ND20_Q2\P(F)
Q   12462       Q2  4\DW12462 = 1\ND20_Q2\Q(F)
S   12466       Q2  4\DW12466 = 1\ND20_Q2\S(F)
I   12470       Q2  4\DW12470 = 1\ND20_Q2\I(F)
U   12474       Q2  4\DW12474 = 1\ND20_Q2\U(F)
f   12478       Q2  4\DW12478 = 1\ND20_Q2\f(F)
EP_POB  12482       Q2  4\DW12482 = 1\ND20_Q2\EP_POB(F)
EP_ODD  12486       Q2  4\DW12486 = 1\ND20_Q2\EP_ODD(F)
EQ_IND  12490       Q2  4\DW12490 = 1\ND20_Q2\EQ_IND(F)
EQ_POJ  12494       Q2  4\DW12494 = 1\ND20_Q2\EQ_POJ(F)
THDVL1  12498       Q2  4\DW12498 = 1\ND20_Q2\THDVL1(F)
THDVL2  12502       Q2  4\DW12502 = 1\ND20_Q2\THDVL2(F)
THDVL3  12506       Q2  4\DW12506 = 1\ND20_Q2\THDVL3(F)
THDIL1  12510       Q2  4\DW12510 = 1\ND20_Q2\THDIL1(F)
THDIL2  12514       Q2  4\DW12514 = 1\ND20_Q2\THDIL2(F)
THDIL3  12518       Q2  4\DW12518 = 1\ND20_Q2\THDIL3(F)
UL1 12522       Q2  4\DW12522 = 1\ND20_Q2\UL1(F)
UL2 12526       Q2  4\DW12526 = 1\ND20_Q2\UL2(F)
UL3 12530       Q2  4\DW12530 = 1\ND20_Q2\UL3(F)
IL1 12534       Q2  4\DW12534 = 1\ND20_Q2\IL1(F)
IL2 12538       Q2  4\DW12538 = 1\ND20_Q2\IL2(F)
IL3 12542       Q2  4\DW12542 = 1\ND20_Q2\IL3(F)
PL1 12546       Q2  4\DW12546 = 1\ND20_Q2\PL1(F)
PL2 12550       Q2  4\DW12550 = 1\ND20_Q2\PL2(F)
PL3 12554       Q2  4\DW12554 = 1\ND20_Q2\PL3(F)
QL1 12558       Q2  4\DW12558 = 1\ND20_Q2\QL1(F)
QL2 12562       Q2  4\DW12562 = 1\ND20_Q2\QL2(F)
QL3 12566       Q2  4\DW12566 = 1\ND20_Q2\QL3(F)
S1  12570       Q2  4\DW12570 = 1\ND20_Q2\S1(F)
S2  12574       Q2  4\DW12574 = 1\ND20_Q2\S2(F)
S3  12578       Q2  4\DW12578 = 1\ND20_Q2\S3(F)

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

Я почти уверен, что значение 39558853.30 слишком велико для хранения в плавающем элементе с одинарной точностью IEEE. Точность 7,22 цифры, для этого числа требуется 9 цифр. Я провел некоторые эксперименты с присвоением значения float, и двойные значения в C # подтверждают это.

Это заставляет меня верить:

1) Как предложил Беньямин Джафари, вам нужно прочитать четыре регистра. Однако это число (как двойное) в шестнадцатеричном виде равно 0x4182dcf62a666666, что, по-видимому, не соответствует никаким данным, которые вы читаете.

OR

2) Также возможно, что он возвращается как UINT32, который должен быть масштабирован на (1/100), чтобы дать вам то, что показывает счетчик. 0xE54D4765 = 3847047013 => масштабируется на 1 / 100.0 = 38470470.13, что близко к тому, что вы видите на прилавке. По моему опыту, это обычная практика в Modbus.

*

OR * 1011

3) Они используют другой (нестандартный) формат для представления данных.

Можете ли вы дать нам название продукта, модель и т.д.?

0 голосов
/ 27 октября 2018

Я улучшил ваш код следующим образом:

from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.client.sync import ModbusTcpClient

def validator(instance):
    if not instance.isError():
        '''.isError() implemented in pymodbus 1.4.0 and above.'''
        decoder = BinaryPayloadDecoder.fromRegisters(
            instance.registers,
            byteorder=Endian.Big, wordorder=Endian.Little
        )   
        return float('{0:.2f}'.format(decoder.decode_32bit_float()))

    else:
        # Error handling.
        print("There isn't the registers, Try again.")
        return None


client = ModbusTcpClient('X.X.X.X', port=502)  # Specify the port.
connection = client.connect()

if connection:
    request = client.read_holding_registers(12606, 2, unit=1)  # Specify the unit.
    data = validator(request)
    print(data)

    request = client.read_holding_registers(12482, 2, unit=1)  # Specify the unit.
    data = validator(request)
    print(data)

    client.close()

else:
    print('Connection lost, Try again')

[ ПРИМЕЧАНИЕ ]:

Вы гарантируете о желаемом декодировании float32?

  1. float AB CD == byteorder=Endian.Big, wordorder=Endian.Big
  2. float CD AB == byteorder=Endian.Big, wordorder=Endian.Little
  3. floatBA DC == byteorder=Endian.Little, wordorder=Endian.Big
  4. float DC BA == byteorder=Endian.Little, wordorder=Endian.Little

Установить unit_ID :

  • Во многих случаях unit является 1 в качестве идентификатора по умолчанию.

[ ОБНОВЛЕНИЕ ]:

Возможно, вам нужно прочитать и расшифровать как значение double / float64 в 12482 адрес регистра, потому что я думаю, что когда требуемый регистр в документе равен 12482, а следующий регистр - 12846, поэтому нам нужно прочитать 4regs ( float64 / double ):

request = client.read_holding_registers(12482, 4, unit=1)

и

return float('{0:.2f}'.format(decoder.decode_64bit_float()))
...