Reading SIMOTION Axis Simulation Mode State in ST Programs

David Krause9 min read
Motion ControlSiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

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 PosAxis or DriveAxis configured 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 toggles SetPointDriverInfo.mode) — used only for verification.
Note: The axis name as it appears in the project navigator (for example 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:

  1. The axis identifier must be a qualified identifier in double quotes (because the project name M6-C3 is 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 to Axis_X112L.
  2. The configuration-data branch must begin with setconfigdata (or its alias cfg) — not with the TO root, and not with actualdata. Without setconfigdata the compiler cannot resolve SetPointDriverInfo as 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

  1. Compile and download the program. Confirm no 6003 errors and no 16024 warnings in the SCOUT / TIA build log.
  2. Open the watch table (SCOUT) or the online monitor (TIA). Add the variable GEX_000_SimulationModeActive and the path <TO>.setconfigdata.TypeOfAxis.SetPointDriverInfo.mode.
  3. With the controller in RUN and the axis currently in real mode, the boolean must read FALSE and the enumerated mode must be SETPOINT_SENSOR_INTERFACE (or whichever real-axis mode applies).
  4. Execute the axis simulation toggle script. After the STOP-RUN transition completes, re-check the watch table — the boolean must read TRUE and the mode must read SIMULATION.
  5. Toggle back to real mode and confirm the boolean returns to FALSE within one polling interval (or one controller cycle if polled directly).
  6. Force the controller to STOP and back to RUN; ensure no CPU goes STOP after downloading event occurs — this is the symptom reported when an illegal STRING-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.

Back to blog