Reading SIMOTION Axis Simulation Mode State in ST Programs
This reference describes how an ST (Structured Text) program on a SIMOTION controller can detect, on a per-axis basis, whether the axis is currently being run in SIMULATION mode. It covers the correct configuration-data path, why a STRING-based dispatch table fails with compiler error 6003 (Variable ID expected), why warning 16024 (ID hides technology object ID) appears, and how to implement a universal, scalable polling function using an ARRAY OF PosAxis.
1. Overview
SIMOTION distinguishes between a real axis and a simulated axis by the value stored in the configuration variable TypeOfAxis.SetPointDriverInfo.mode. When this field is SIMULATION, every motion command is executed inside the runtime instead of being issued to the drive via PROFIdrive / PROFIBUS / PROFINET. Many projects must branch user-program logic on this state — for example, suppressing hardware-dependent messages, skipping I/O reads, gating trace triggers, or hiding alarms that only make sense on a real drive.
The challenge is that the simulation flag is a configuration datum on a technology object (TO), not a freely writable user variable. Direct ST access requires either the fully qualified path or — for a dynamic, project-spanning function — a typed reference (instance) to the TO. Attempting to glue the axis name together from a STRING variable is a common pattern that fails at compile time, because the ST compiler cannot resolve a runtime-composed identifier into a variable ID.
2. Prerequisites
- SIMOTION controller (SIMOTION D4xx, SIMOTION C240, or SIMOTION P) running firmware V4.4 or later (paths verified on V5.x).
- SIMOTION SCOUT / TIA Portal with the SIMOTION option package installed.
- At least one TO of type
PosAxisorDriveAxisconfigured under the controller. - License for SIMOTION IT DIAG / OPC UA (only required if you also want to expose the flag externally).
- Axis simulation script
AxisSimulationOnOff_V1_3_2(or any equivalent script that togglesSetPointDriverInfo.mode) — used only for verification.
Axis_X112L) is identical to the technology-object identifier. Renaming the TO in SCOUT/TIA also renames the identifier that the ST compiler recognizes.
3. SIMOTION Axis Simulation Architecture
Every speed/position axis in SIMOTION carries two parallel trees of system variables:
| Tree | Prefix | Typical prefix in path | Persistence | Use case |
|---|---|---|---|---|
| Configuration data |
cfg: or setconfigdata
|
<TO>.setconfigdata.… |
Compile-time configuration | Type of axis, simulation flag, encoder interface, setpoint driver info |
| Actual / status data | (none) or actualdata
|
<TO>.actualdata.… |
Runtime-updated | Current velocity, position error, following distance, alarms |
The simulation flag lives in the configuration tree, specifically in:
<TO name>.setconfigdata.TypeOfAxis.SetPointDriverInfo.mode
The enumerated values for mode are:
| Enumerated value | Meaning | Drive traffic |
|---|---|---|
SIMULATION |
Axis is simulated entirely inside the runtime | None |
SETPOINT_OUTPUT |
Axis drives a real drive via setpoint channel | PROFIdrive / analog |
SENSOR_INTERFACE |
Axis has sensor-side connection only | Encoder interface active |
SETPOINT_SENSOR_INTERFACE |
Full real axis (setpoint + encoder) | PROFIdrive + encoder |
Switching the mode requires a STOP-RUN transition of the TO, or runtime execution of _enableAxisSimulation() / _disableAxisSimulation() from the axis simulation FB. Once the flag flips, the value visible to ST changes accordingly — the user program can read it without subscribing to any event.
4. The Correct Path in an ST Program
Direct ST access — for a single, statically known axis — looks like this:
PROGRAM P_AxisSimulationLatch
VAR
GEX_000_SimulationModeActive : BOOL;
END_VAR
IF "M6-C3".Axis_X112L.setconfigdata
.TypeOfAxis.SetPointDriverInfo.mode = SIMULATION THEN
GEX_000_SimulationModeActive := TRUE;
END_IF;
END_PROGRAM
Two syntax points determine whether the compiler accepts the expression:
- The axis identifier must be a qualified identifier in double quotes (because the project name
M6-C3is part of the device name). Inside SCOUT, the qualified form is"M6-C3".Axis_X112L. Inside TIA Portal, depending on the controller, it may reduce toAxis_X112L. - The configuration-data branch must begin with
setconfigdata(or its aliascfg) — not with the TO root, and not withactualdata. Withoutsetconfigdatathe compiler cannot resolveSetPointDriverInfoas a valid sub-structure.
A common failure mode is writing "M03-C3".Axis_X111L.TypeOfAxis.SetPointDriverInfo.mode. Because no setconfigdata qualifier is present, the parser treats TypeOfAxis as a member of the TO root, which is not the case — leading to error 6003: Variable ID expected.
5. Why STRING-Based Dispatch Fails
A scalable polling function would ideally iterate over many axes without writing one IF per axis. The intuitive approach is to keep axis names in a STRING array and concatenate them into the access path at runtime:
VAR
Axis : ARRAY[1..24] OF STRING;
AxisExists : ARRAY[1..24] OF BOOL;
iIndex : USINT;
END_VAR
Axis[1] := 'Axis_X111L';
Axis[2] := 'Axis_X111R';
Axis[3] := 'Axis_X112L';
...
FOR iIndex := 1 TO 6 BY 1 DO
IF AxisExists[iIndex] = TRUE THEN
// ❌ illegal: ST cannot resolve "Axis[iIndex]" as a variable
GEX_000_SimulationModeActive :=
("M6-C3".Axis[iIndex].setconfigdata
.TypeOfAxis.SetPointDriverInfo.mode = SIMULATION);
EXIT;
END_IF;
END_FOR;
The ST compiler performs static name resolution: identifiers must be known at compile time. A subscripted STRING element is a value, not an identifier, so the parser raises error 6003 — Variable ID expected. The same restriction rules out building names with CONCAT, MID, or any other string function.
5.1 The Right Primitive: ARRAY OF PosAxis
The TO itself can be referenced as a typed pointer. Declare an array element type of PosAxis (or DriveAxis for a virtual drive axis). Each element then becomes a first-class reference, addressable by index, and the compiler can validate its members:
VAR
AxisRef : ARRAY[1..6] OF PosAxis;
AxisExists : ARRAY[1..6] OF BOOL;
iIndex : USINT;
GEX_000_SimulationModeActive : BOOL;
END_VAR
AxisRef[1] := Axis_X111L;
AxisRef[2] := Axis_X111R;
AxisRef[3] := Axis_X112L;
AxisRef[4] := Axis_X112R;
AxisRef[5] := Axis_X113L;
AxisRef[6] := Axis_X113R;
GEX_000_SimulationModeActive := FALSE;
FOR iIndex := 1 TO 6 BY 1 DO
IF AxisExists[iIndex] = TRUE THEN
IF AxisRef[iIndex].setconfigdata
.TypeOfAxis.SetPointDriverInfo.mode = SIMULATION THEN
GEX_000_SimulationModeActive := TRUE;
EXIT;
END_IF;
END_IF;
END_FOR;
This compiles cleanly, iterates over a configurable set of axes, and exits on the first axis reported as simulated — matching the user's original intent.
6. Diagnostic Messages: 6003 and 16024
6.1 Error 6003 — Variable ID expected
Triggered whenever the parser encounters a token where it expects a variable identifier. Typical SIMOTION cases:
| Code | Reason | Fix |
|---|---|---|
| 6003 | Subscripted STRING used as identifier |
Replace STRING array with ARRAY OF PosAxis
|
| 6003 | Missing setconfigdata qualifier before TypeOfAxis
|
Insert .setconfigdata
|
| 6003 | Axis name spelled without quotes around the device prefix | Use "<device>".<TO> form |
| 6003 | Trailing dot in path | Remove empty member |
6.2 Warning 16024 — ID hides technology object ID
The warning 16024: ID "Axis_X112L" hides technology object ID on the device fires when you declare a local symbol (a variable, constant, or FB instance) whose identifier collides with a TO identifier that exists on the same device. SIMOTION allows it, but downstream code may resolve to the local symbol and bypass the TO. The fix is to never reuse TO names as local identifiers — keep the local Axis_112L : STRING; example out of the VAR block, or rename the local to e.g. sAxis_112L.
7. Implementation Notes and Best Practices
7.1 Cache the result
The simulation flag does not change on every cycle. Latch the value on a slow timer (for example 250 ms) to keep the access cost low:
PROGRAM P_AxisSimulationLatch250ms
VAR
tPoll : TON;
bResult : BOOL;
END_VAR
tPoll(IN := NOT tPoll.Q, PT := T#250ms);
IF tPoll.Q THEN
bResult := F_AxisSimulationActive(AxisRef := AxisRef,
AxisExists := AxisExists);
END_IF;
7.2 Encapsulate as a function block
Reusability is best served by lifting the loop into a parameterized FB:
FUNCTION_BLOCK FB_AxisSimulationMonitor
VAR_INPUT
AxisRef : ARRAY[1..24] OF PosAxis;
AxisExists : ARRAY[1..24] OF BOOL;
END_VAR
VAR_OUTPUT
bAnySimulated : BOOL;
iFirstSimulated : USINT;
END_VAR
VAR
i : USINT;
END_VAR
bAnySimulated := FALSE;
iFirstSimulated := 0;
FOR i := 1 TO 24 BY 1 DO
IF AxisExists[i] THEN
IF AxisRef[i].setconfigdata
.TypeOfAxis.SetPointDriverInfo.mode = SIMULATION THEN
bAnySimulated := TRUE;
iFirstSimulated := i;
EXIT;
END_IF;
END_IF;
END_FOR;
END_FUNCTION_BLOCK
7.3 Per-axis gating
When the goal is to clear messages on a specific axis only when that axis is simulated, read the flag locally rather than broadcasting a global boolean:
IF Axis_X112L.setconfigdata.TypeOfAxis.SetPointDriverInfo.mode
= SIMULATION THEN
_resetAxisError(Axis := Axis_X112L);
END_IF;
7.4 Drive axis variant
For TO type DriveAxis (virtual axis connected to a SINAMICS drive), the same path applies. There is no separate flag — drive simulation is reported through the same SetPointDriverInfo.mode field. If you also need to know whether the connected SINAMICS is in simulated mode at the drive side, read r978 on the SINAMICS via the cyclic PROFIdrive telegram — but that is a different flag from the SIMOTION SIMULATION flag.
7.5 Watching transitions
If the simulation flag must trigger a one-shot action (e.g., clear HMI messages on rising edge), latch the previous value and detect the edge:
VAR RETAIN
bSimPrev : BOOL;
END_VAR
IF bAnySimulated AND NOT bSimPrev THEN
MsgClearAll();
END_IF;
bSimPrev := bAnySimulated;
8. Verification
- Compile and download the program. Confirm no 6003 errors and no 16024 warnings in the SCOUT / TIA build log.
- Open the watch table (SCOUT) or the online monitor (TIA). Add the variable
GEX_000_SimulationModeActiveand the path<TO>.setconfigdata.TypeOfAxis.SetPointDriverInfo.mode. - With the controller in RUN and the axis currently in real mode, the boolean must read
FALSEand the enumerated mode must beSETPOINT_SENSOR_INTERFACE(or whichever real-axis mode applies). - Execute the axis simulation toggle script. After the STOP-RUN transition completes, re-check the watch table — the boolean must read
TRUEand the mode must readSIMULATION. - Toggle back to real mode and confirm the boolean returns to
FALSEwithin one polling interval (or one controller cycle if polled directly). - Force the controller to STOP and back to RUN; ensure no
CPU goes STOP after downloadingevent occurs — this is the symptom reported when an illegalSTRING-based access was downloaded.
9. Troubleshooting Matrix
| Symptom | Root cause | Resolution |
|---|---|---|
| Error 6003 on access path |
setconfigdata qualifier missing |
Insert .setconfigdata before .TypeOfAxis
|
| Error 6003 inside a FOR loop | Subscripted STRING used as TO identifier | Replace ARRAY OF STRING with ARRAY OF PosAxis
|
| Warning 16024 | Local identifier shadows a TO identifier | Rename the local symbol |
| CPU STOP after download | Runtime evaluated illegal dynamic name and trapped | Use PosAxis array reference, not STRING |
| Boolean never becomes TRUE | Reading actualdata instead of setconfigdata
|
Switch to setconfigdata.TypeOfAxis.SetPointDriverInfo.mode
|
| Boolean latched TRUE even after disabling simulation | Polling timer never elapsed after the toggle | Re-arm timer or remove timer entirely |
| Variable not visible in watch table | Wrong device prefix in qualifier | Match SCOUT/TIA device name exactly |
| Returns UNKNOWN on real axis | Axis not yet configured | Ensure TO is downloaded to the target |
10. Frequently Asked Questions
Which SIMOTION system variable reports whether an axis is simulated?
Read <TO>.setconfigdata.TypeOfAxis.SetPointDriverInfo.mode; compare the enumerated value against SIMULATION. Values include SIMULATION, SETPOINT_OUTPUT, SENSOR_INTERFACE, and SETPOINT_SENSOR_INTERFACE.
Why does my ST program fail with error 6003 "Variable ID expected"?
The ST compiler cannot resolve a runtime-built identifier. Replace any ARRAY OF STRING used to dispatch axis names with an ARRAY OF PosAxis (or DriveAxis) so each entry is a typed reference the compiler can validate.
Why does the warning "16024: ID hides technology object ID on the device" appear?
A local variable, constant, or FB instance shares its identifier with a TO on the same device. Rename the local symbol (for example, prefix it with s or loc) to remove the shadowing.
Can I read the simulation flag from MCC / LAD / FBD instead of ST?
Yes. SIMOTION exposes the same configuration variables in every language. In MCC, drop a Read system variable block and select setconfigdata.TypeOfAxis.SetPointDriverInfo.mode; in LAD/FBD, use the Variable access contact on the same path.
Does the simulation flag update instantly when I run the axis simulation script?
The mode change requires a STOP-RUN transition of the TO, which the axis simulation FB performs internally. The flag is current immediately after the transition completes; the user ST program can read it on the very next cycle.