Modbus RTU slave se simulovanými senzory

Projekt Qenex_Serial_ModbusSlave_SimulatedSensors.qproj najdete ve složce Examples vedle QInsight.exe.

Co ukázka předvádí

  • QInsight jako Modbus RTU slave (unit 2) na sériovém portu — driver Serial Port (COM) + protokol Modbus Slave. Master čte z holding registrů 0 a 1 aktuální hodnoty dvou proměnných.
  • Simulované senzory ze skriptu: periodický Python skript (2 s) posouvá po pilovém průběhu teplotu oleje 0–150 °C a tlak oleje 1000–2500 kPa.
  • Dvojí zápis každé hodnoty: do proměnné slave (pro mastera) a do její virtuální kopie (pro controly), protože zápis ze skriptu na protokolu zařízení nikdy nevyvolá událost pro UI.
  • Obnovu spojení driveru Serial Port po odpojení převodníku.

Co potřebujete

  • Modbus RTU master — např. qModMaster: unit 2, holding registry od adresy 0, počet 2 (FC03), RTU, 9600 Bd, 8 bitů, bez parity, 1 stop bit.
  • Sériovou cestu k masteru: dvojici spárovaných COM portů na jednom PC (virtuální null-modem pár), nebo dva převodníky USB/RS-485 — jeden pro QInsight, druhý pro mastera.
  • Co upravit: v driveru Serial Port změňte port=COM6 na port použitý ve vašem počítači. Rámování a unitId=2 nechte, nebo změňte shodně na obou stranách. Skripty vyžadují nastavený Python.

Projekt

Drivery a protokoly

Driver Serial Port Driver (SerialPortDriver):

ParametrHodnotaVýznam
portCOM6jméno COM portu — upravte podle svého počítače
baudRate9600komunikační rychlost
dataBits8počet datových bitů
paritynonebez parity
stopBits1jeden stop bit
handshakenonebez řízení toku
reconnectDelayMs2000prodleva před dalším pokusem o otevření portu po chybě
reconnectAttempts-1pokusy bez omezení počtu, viz Obnova spojení

Pod ním protokol Modbus Slave (RTU/TCP) (ModbusSlaveProtocol):

ParametrHodnotaVýznam
moderturámování RTU (CRC16, sériová linka)
unitId2vlastní adresa slave — master ji musí uvést v dotazu
respondToAnyUnitfalsedotazy na jinou unit adresu slave ignoruje

Druhá dvojice Virtual Data Driver (VirtualDataDriver, v UI Virtual Variables Host) + Virtual Variables (VirtualDataProtocol) nemá žádná nastavení a nese obě zobrazovací kopie. Projekt nemá žádné události: slave eventRef nepotřebuje, virtuální proměnné dostávají vzorky zápisem skriptu.

Proměnné

ProměnnáNamespaceTypProtokolRegistr / Comm paramsPrezentace
OilTemp/ModbusushortModbus Slaveholding registr 0, wordOrder="big", direction="read"Temperature
OilPressure/ModbusushortModbus Slaveholding registr 1, wordOrder="big", direction="read"Pressure
OilTempView/VirtualdoubleVirtual Variables— (virtuální, bez parametrů)Temperature
OilPressureView/VirtualdoubleVirtual Variables— (virtuální, bez parametrů)Pressure

Proměnné slave jsou ushort, každá tedy obsadí jeden registr, a master je čte (direction="read"). Prezentace Temperature (0–150 °C) a Pressure (1000–2500 kPa), obě s formátem {0:F0}, používají jedinou lineární konverzi Raw (multiplier=1, offset=0) — inženýrská hodnota se rovná surové (raw) hodnotě.

Skripty

Oba skripty jsou blokující, bez timeoutu a jen pro runtime. init.py (Startup) nastaví výchozí stav simulace a hned ho publikuje do registrů slave i do zobrazovacích kopií:

# Startup script: initial state of the simulated sensors.
# The periodic script (simulate.py) ramps the values from here; the globals persist
# between script runs inside one runtime session.
oil_temp = 0.0          # degC, ramps 0 .. 150
oil_pressure = 1000.0   # kPa, ramps 1000 .. 2500
direction = 1           # +1 ramping up, -1 ramping down

# Publish the initial values right away, both to the slave registers and to the display copies.
OilTemp.EngValue = oil_temp
OilPressure.EngValue = oil_pressure
OilTempView.EngValue = oil_temp
OilPressureView.EngValue = oil_pressure

simulate.py (Periodic, period=2;unit=s) každé 2 s posune obě veličiny o krok a na krajích rozsahu otočí směr:

# Periodic script (period=2;unit=s): saw-tooth ramp of the simulated sensors.
# Temperature moves 1 degC per step between 0 and 150, pressure 10 kPa per step between
# 1000 and 2500, so one sweep up takes 5 minutes; at either end the direction flips.
#
# Every value is written twice on purpose:
#  - OilTemp / OilPressure are the Modbus slave variables. The slave serves their current
#    value to the master (holding registers 0 and 1). A script write never raises a UI event
#    on a device protocol, so these two are not shown in any control.
#  - OilTempView / OilPressureView are virtual variables. The Virtual Data protocol publishes
#    every script write to the UI, so the graph and signal controls follow them.
oil_temp += direction * 1.0
oil_pressure += direction * 10.0

if oil_temp >= 150.0 or oil_pressure >= 2500.0:
    oil_temp, oil_pressure, direction = 150.0, 2500.0, -1
elif oil_temp <= 0.0 or oil_pressure <= 1000.0:
    oil_temp, oil_pressure, direction = 0.0, 1000.0, 1

OilTemp.EngValue = oil_temp
OilPressure.EngValue = oil_pressure
OilTempView.EngValue = oil_temp
OilPressureView.EngValue = oil_pressure

Stav simulace je uložen v běžných pythonovských proměnných — skripty projektu sdílejí jeden prostor, takže hodnoty zůstávají zachovány mezi běhy a init.py je při startu runtime vynuluje. Krok 1 °C a 10 kPa po 2 s dává 150 kroků na průběh, tedy 5 minut nahoru a 5 dolů.

Proč dvojí zápis. OilTemp a OilPressure patří protokolu Modbus Slave: zápis skriptu jejich hodnotu uloží a slave ji poskytuje masterovi, ale na protokolu zařízení zápis ze skriptu nikdy nevyvolá událost pro UI — v controlech by se hodnoty těchto proměnných neaktualizovaly. Proto skript tutéž hodnotu zapíše i do OilTempView a OilPressureView na protokolu Virtual Variables, který každý zápis publikuje jako vzorek s časovou značkou. Zápis přes EngValue je s konverzí 1:1 totéž jako raw; u ushort se hodnota převádí na celé číslo, což kroky 1,0 a 10,0 splňují.

Workspace

Workspace Simulated sensors má tři controly, všechny navázané na virtuální kopie, ne na proměnné slave: Graph „Simulated sensors (virtual copies of the slave registers)“ s oknem 300 s (OilTempView červeně na levé ose 0–150, OilPressureView modře na pravé ose 1000–2500) a dva Single-Signal controly (obnova 250 ms) s aktuální teplotou a tlakem.

Co uvidíte a co vyzkoušet

  • Po Start runtime kreslí graf pilový průběh (okno 300 s = jeden průběh nahoru) a Single-Signal controly ukazují aktuální hodnoty. Master čte z registru 0 teplotu a z registru 1 tlak — tytéž hodnoty, po 2 s o 1 °C a 10 kPa jinak.
  • Dotaz na jinou unit adresu než 2 zůstane bez odpovědi (respondToAnyUnit=false); čtení zasahující do registru 2 a vyšších slave odmítne jako celek.
  • Odpojte a znovu připojte převodník. Driver Serial Port přejde do stavu Faulted, v logu se objevují varování s číslem pokusu a driver se pokouší port otevřít každé 2 s (reconnectDelayMs=2000) bez omezení (reconnectAttempts=-1); skript i graf běží dál. Po opětovném připojení driver port automaticky otevře a master čte aktuální hodnoty bez zásahu obsluhy.
  • Zkraťte periodu skriptu (period=500;unit=ms) nebo změňte krok v simulate.py — master ani workspace se měnit nemusí.

Související kapitoly