Skip to content

Virtual PLC (Structured Text)

The virtual PLC runs a Structured Text (ST) program directly in the browser. Write the program in the PLC editor, click Deploy and Run, and it scans once per simulation tick: it reads the twin’s PLC signals, runs your logic and writes the outputs. Nothing has to be built or installed — the program is compiled in the browser the moment 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 to another workspace, and the PLC keeps running — like a real controller, 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 pick it; the editor adds the declaration with a short name and the @signal comment and inserts the name at the cursor. The browser lists the model’s signals and the signals of a connected realvirtual CONNECT interface, with 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 work against each other — you have to resolve that in the model yourself.

A model can carry several PLC programs, one PLC Program component per node — like the blocks of a real PLC, one per unit of the machine. All of them scan in the same tick, one after another in the order 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

A program that reads it steps aside on its own when a real controller takes over: write nothing while it is FALSE. When the model switches to PLC, the outputs of such programs go back to their start values once, so no simulated command — a running belt, an open valve — is left behind. The welding station’s programs all work like this.

A program that does not read RV_SimulationMode keeps writing in PLC mode and works against the real controller. Stop it before you connect one.

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 and then writes all outputs together — like the process image of a real PLC. Outputs act on the drives in the same tick.

Resetting the simulation resets every program — timers, counters, memory — and sets its outputs back 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. In a project you cannot write to — such as the public demo — use Export to keep your program as a .st file and Import it again later.

A program whose Active field is set starts by itself when the model is loaded, in every workspace — like the controller of a real machine. With Active off, the program is only loaded into the editor, and Deploy and Run are up to you. Programs run in an isolated sandbox inside the browser and can only read and write signals.