examples/Modbus PLC Simulator/README.md
This project exercises Serial Studio's Modbus TCP/RTU support with a physics-based hydraulic test stand simulator. The simulator acts as a Modbus TCP server and produces realistic industrial telemetry, with automatic failure modes and recovery sequences.
It's a good demo of Serial Studio's Pro Modbus protocol support: real-time data acquisition, custom frame parsing, and an industrial dashboard.
Modbus support needs a Serial Studio Pro license. See serial-studio.com for details.
The simulator models a 50HP hydraulic power unit.
The 50HP VFD-controlled induction motor spins from 0 to 3600 RPM, driving a 45cc/rev 9-piston axial pump modeled with realistic efficiency curves.
The VFD ramps RPM from 0 to 1800 along a 10-second S-curve, then a PID loop holds pressure at 1500 PSI once the ramp settles. Oil temperature follows a thermodynamic model driven by pump inefficiency and valve throttling, and vibration is scored against ISO 10816 limits. Every measurement carries Ornstein-Uhlenbeck sensor noise on top of the underlying physics.
The simulator cycles through realistic test sequences:
The simulator exposes 9 holding registers (function code 0x03) starting at address 0.
| Address | Name | Range | Units | Description |
|---|---|---|---|---|
| HR[0] | E-Stop | 0-1 | Emergency stop status (0 = normal, 1 = e-stop) | |
| HR[1] | Start LED | 0-1 | Motor running indicator (0 = off, 1 = running) | |
| HR[2] | Temperature | 72-180 | °F | Hydraulic oil temperature |
| HR[3] | Pressure | 0-3000 | PSI | System pressure (alarm at 2800 PSI) |
| HR[4] | Motor RPM | 0-3600 | RPM | Motor speed |
| HR[5] | Valve Position | 0-100 | % | Control valve opening percentage |
| HR[6] | Flow Rate | 0-500 | GPM × 10 | Pump flow rate (divide by 10) |
| HR[7] | Motor Load | 0-100 | % | Motor load percentage |
| HR[8] | Vibration | 0-150 | mm/s × 10 | Vibration velocity RMS (divide by 10) |
pip install pymodbus
The simulator supports pymodbus 3.x and 4.x automatically.
The project's control script launches plc_simulator.py automatically once Serial Studio connects, so this step is only needed to run a modified copy first — for example with the FAILURE_PROBABILITY override described in Observing failure modes — before connecting:
python3 plc_simulator.py
Expected output:
========================================================================
HYDRAULIC TEST STAND SIMULATOR
========================================================================
Server: 0.0.0.0:5020 | Update: 50ms (20Hz)
Registers (FC03 Holding):
0:E-Stop 1:Start 2:Temp(°F) 3:PSI 4:RPM 5:Valve(%)
6:GPM(÷10) 7:Load(%) 8:Vibration(÷10 mm/s)
Phases: STARTUP -> RUNNING -> PRESSURE_TEST -> (FAILURE -> SHUTDOWN)
Flags: E=E-Stop A=Alarm(>2800PSI) F=Failure
========================================================================
10:30:00 [STARTUP ] - R: 0 P: 14 F: 0.0 L: 0 V:0.1 T: 72
10:30:01 [STARTUP ] - R: 180 P: 110 F: 4.8 L:17 V:1.8 T: 72
...
Modbus PLC Simulator.ssproj.Modbus.Modbus TCP.127.0.0.1 (or the IP address of the machine running the simulator).5020.1.Holding Registers (0x03).0.9.100 (recommended).The included project file (Modbus PLC Simulator.ssproj) provides:
| Widget | Shows |
|---|---|
| Status LEDs | Emergency Stop and Running indicators |
| Temperature plot | Oil temperature trend (72 to 180 °F) |
| Pressure gauge | System pressure (0 to 3000 PSI) |
| RPM gauge | Motor speed (0 to 3600 RPM) |
| Valve position bar | Control valve opening percentage |
| Flow rate graph | Real-time pump flow monitoring |
| Motor load bar | Motor load percentage |
| Vibration graph | ISO 10816 vibration monitoring |
The included modbus_plc_simulator.csv file defines the register map in a format that Serial Studio's Modbus Map Importer can read directly. That means you can auto-generate a project file from a register map definition instead of configuring registers manually.
CSV columns: address, name, type, dataType, units, min, max, scale, offset, description.
To import:
modbus_plc_simulator.csv.Serial Studio's Modbus Map Importer auto-generates a Lua frame parser based on the register map. The parser embedded in this project:
[slaveAddr, funcCode, byteCount, ...data]).plc_simulator.py: physics-based hydraulic test stand simulator with a Modbus TCP server.Modbus PLC Simulator.ssproj: project file with the dashboard, Modbus connection settings, and the embedded frame parser.modbus_plc_simulator.csv: register map definition for the Modbus Map Importer.README.md: this documentation.doc/screenshot.png: dashboard screenshot.The simulator includes realistic failure sequences that happen randomly (~0.02% probability per update):
To force a failure for testing, change the FAILURE_PROBABILITY constant in plc_simulator.py (set to 0.1 for ~10% chance).
The server speaks Modbus TCP and binds to 0.0.0.0 (all interfaces) on port 5020 by default; change the port via the SERVER_PORT constant.
Serial Studio can poll multiple non-contiguous register ranges through register groups. To poll specific registers:
This simulator can double as a template for connecting to real industrial PLCs:
Problem: Serial Studio shows "Connection Failed".
python3 plc_simulator.py).Problem: No data updates in Serial Studio.
Problem: Erratic readings or NaN values.
This example is dual-licensed under GPL-3.0 and the Serial Studio Commercial License.
For more about Serial Studio and Modbus integration, see the Serial Studio documentation.