Skip to content

Virtual PLC (Structured Text)

Commercial

Included in the public demo Compare editions

The virtual PLC runs a Structured Text (ST) program directly in the browser. Write the program in the PLC editor, then click Deploy and Run. Once per simulation tick, it reads the twin’s PLC signals, runs your logic and writes the outputs. You need no separate build or installation. The browser compiles the program when you deploy it.

Use it to test control logic against the twin before the real controller exists, to try out a sequence quickly, or to teach PLC programming on a running machine. For simple sequences without code, use logic steps instead.

The PLC editor in the Laser Welding Assembly Station: an ST program for the curling check of station 4 is running, the watch list below the code shows the cycle counter and the probe signals, and the probe block in the 3D view is lowered

  1. Switch to the Planner workspace and click the PLC Editor button in the tool bar on the left.
  2. If the model already has PLC programs, the editor opens the first one. Otherwise the model gets a node PLC with a PLC Program component and a short template program.
  3. Edit the program. Syntax errors are marked while you type.
  4. Click Deploy to compile and load the program. Compile errors and unknown signals appear as markers in the code.
  5. Click Run. The status changes to running and the watch list shows live values.

The editor stays open when you change workspaces, and the PLC keeps running while you watch the plant. Only the Viewer workspace hides the editor.

ControlWhat it does
DeployCompiles the program and loads it with fresh timers, counters and memory
Run / StopStarts cyclic scanning, or stops it. Stop keeps all values, so Run continues where it stopped
StepRuns exactly one scan, useful while the simulation is paused
ResetResets timers, counters and memory to their start values
Statusstopped, running or error. Hover the status to read the error message. The scan time in ms is shown next to it
Insert signalOpens a signal browser and inserts the chosen signal into the program (see below)
Export / ImportSaves the program as a .st file, or loads one
Program listIn a model with several programs: every program in scan order with its state and scan time. Pick one to edit it

The watch list below the code shows the current values of all signals the program uses and the outputs of its timers and counters, such as tDwell.Q or cycles.CV. Hover a name in the code to see its type, value and signal.

A program reaches the twin through a VAR_EXTERNAL block. By default the variable name is the signal name:

VAR_EXTERNAL
SensorInFeed : BOOL; (* reads the signal SensorInFeed *)
ConveyorStart : BOOL; (* writes the signal ConveyorStart *)
END_VAR

To use a short name in the program, or a signal whose name is not a valid ST name (for example FG01_P_Camera.bReady), add the signal name as a comment:

VAR_EXTERNAL
ProbeDown : BOOL; (* @signal: FG04_Y_AxisZ_WorkPos *)
END_VAR

Insert signal writes these lines for you. Search for a signal and select it. The editor adds a declaration with a short name and the @signal comment, then inserts the name at the cursor. The browser lists signals from the model and a connected realvirtual CONNECT interface. Each entry shows direction, type and address.

The Insert signal browser filtered to FG04_Y_AxisZ: the four signals of the station 4 probe with their direction, type and TIA address

When you deploy:

  • A signal the program only reads but that does not exist gets a warning and reads FALSE or 0. Usually the name has a typo.
  • A signal the program writes but that does not exist is created under PLC/<name>.

This program for the Laser Welding Assembly Station moves the probe of the curling check down and up and switches the yellow tower light on after five cycles:

PROGRAM Main
VAR_EXTERNAL
ProbeDown : BOOL; (* @signal: FG04_Y_AxisZ_WorkPos *)
ProbeUp : BOOL; (* @signal: FG04_Y_AxisZ_HomePos *)
ProbeIsDown : BOOL; (* @signal: FG04_Y_AxisZ_InWork *)
ProbeIsUp : BOOL; (* @signal: FG04_Y_AxisZ_InHome *)
TowerGreen : BOOL; (* @signal: SignalTower_Green *)
TowerYellow : BOOL; (* @signal: SignalTower_Yellow *)
END_VAR
VAR
seq : INT;
tDwell : TON;
cycles : CTU;
END_VAR
CASE seq OF
0: ProbeUp := FALSE;
ProbeDown := TRUE;
IF ProbeIsDown THEN seq := 1; END_IF;
1: tDwell(IN := TRUE, PT := T#1s);
IF tDwell.Q THEN tDwell(IN := FALSE); seq := 2; END_IF;
2: ProbeDown := FALSE;
ProbeUp := TRUE;
IF ProbeIsUp THEN seq := 3; END_IF;
3: tDwell(IN := TRUE, PT := T#2s);
IF tDwell.Q THEN tDwell(IN := FALSE); seq := 0; END_IF;
END_CASE;
cycles(CU := seq = 3, R := FALSE, PV := 5);
TowerGreen := TRUE;
TowerYellow := cycles.Q;
END_PROGRAM

The welding station’s own program Station04 drives these outputs too. To try the example there, pick Station04 in the program list and Stop it first, then deploy and run your program.

The virtual PLC runs independently of a model’s logic steps. If both write the same outputs, they conflict. You must resolve this in the model yourself.

A model can carry several PLC programs, with one PLC Program component per node. Like blocks in a real PLC, these can represent individual machine units. All programs scan in the same tick, one after another, as set by their Order field. An output written by two programs is reported as a conflict.

The Laser Welding Assembly Station is controlled this way: eleven programs under the node PLC_Programs — operating modes, transport, the two lifts, the buffer, the entry and the five stations.

A program can read the model’s control mode through the read-only system variable RV_SimulationMode:

VAR_EXTERNAL
RV_SimulationMode : BOOL; (* TRUE = Simulation, FALSE = a real PLC owns the outputs *)
END_VAR

ST programs keep scanning in both modes. To stop writing when a real controller takes over, you check RV_SimulationMode in the program and write nothing while it is FALSE. When the model switches to PLC, running programs that use this variable get a one-time reset of their outputs to their start values. The welding station’s programs all work like this.

A program without this check keeps writing in PLC mode and works against the real controller. Stop it before you connect one.

For logic steps, you set Active on each logic root: Always, Connected, Disconnected or Never. Only roots set to Disconnected stop in PLC mode. Editor-created containers run Always. When a root stops, the outputs it owns return to their start values.

Who writes the model outputs Three writers feed the model outputs: logic steps, ST PLC programs and the real PLC through CONNECT. Only logic roots with Active set to Disconnected stop in PLC mode; their outputs return to start values. ST PLC programs scan in both modes. A check of RV_SimulationMode must stop output writes in PLC mode; running programs using that variable receive a one-time output reset when PLC mode starts. An ST program without the check competes with the real PLC. The real PLC takes over on its first model output write, and the saved mode returns when the connection ends. Who writes the model outputs Logic steps per logic root Active setting Active = Disconnected → stops in PLC mode owned outputs → start values Always / Connected / Disconnected / Never Editor-created containers: Always ST PLC programs scan in both modes checks RV_SimulationMode → stops writing in PLC mode; one-time reset on entry IF NOT RV_SimulationMode ... no check → competing writer Stop before you connect a real PLC Real PLC through CONNECT PLC mode = taken over first model output write Model outputs (drives, cylinders, lamps…)
You control which writers reach the model outputs through the logic root's Active setting and the ST program's RV_SimulationMode check. The saved mode returns when the real PLC connection ends.

The PLC supports a practical subset of IEC 61131-3 Structured Text. Keywords are not case-sensitive; comments are written (* … *) or // ….

AreaSupported
ProgramOne PROGRAM … END_PROGRAM with VAR and VAR_EXTERNAL blocks
Statements:=, IF / ELSIF / ELSE, CASE (single integer labels and ELSE), FOR … BY, WHILE, REPEAT … UNTIL, function block calls with := parameters
TypesBOOL, INT, DINT, REAL, TIME
Literals123, 1.5, 16#FF, TRUE / FALSE, T#2s, T#500ms, T#1m30s
Operators+ - * /, MOD, = <> < <= > >=, AND OR XOR NOT

Not supported yet: strings, arrays, structures, your own functions or function blocks, EXIT / RETURN, CASE ranges, bit operations on integers and => output parameters. The compiler reports them as errors instead of running something unexpected.

BlockInputs → outputsWhat it does
TONIN, PT → Q, ETOn-delay: Q turns on after IN has been on for PT
TOFIN, PT → Q, ETOff-delay: Q turns off PT after IN turns off
TPIN, PT → Q, ETPulse of length PT on a rising edge of IN
CTUCU, R, PV → Q, CVCounts up on each rising edge of CU; Q when CV ≥ PV
CTDCD, LD, PV → Q, CVCounts down from PV; Q when CV ≤ 0
CTUDCU, CD, R, LD, PV → QU, QD, CVUp/down counter
R_TRIG / F_TRIGCLK → QQ for one scan on a rising / falling edge
RS / SRS, R1 → Q1 / S1, R → Q1Reset-dominant / set-dominant flip-flop

Timers run on simulation time: when you pause the simulation, timers pause too.

The PLC scans once per simulation tick (60 times per second). Each scan reads all inputs at once, runs the program from top to bottom, then writes all outputs together. This works like the process image of a real PLC. Outputs act on the drives in the same tick.

Resetting the simulation resets every program’s timers, counters and memory. It also restores outputs to their start values: the values they had when the model was loaded.

If a scan runs too long (more than 50 ms, for example an endless loop), uses too much memory or hits an error such as a division by zero, the PLC stops with the status error. Fix the program and click Run again; the PLC restarts with fresh values.

Each program is stored in the model, on its PLC Program component. Changes are saved with the model and can be undone. If you cannot write to a project, such as the public demo, use Export to save a .st file. Use Import to load it again later.

A program whose Active field is set starts automatically when the model loads, in every workspace. With Active off, the program only loads into the editor; click Deploy and Run to start it. Programs run in an isolated sandbox inside the browser and can only read and write signals.