Fixing SIMOTION Flying Saw Modulo Rollover Off-By-One Errors

David Krause17 min read
Motion ControlSiemensTroubleshooting
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

Problem Overview

A SIMOTION-controlled flying saw uses a following axis geared to an external incremental encoder configured as a modulo master (range 0 to 25000 user units). The control computes the next cut's synchronization point by adding product length, blade width, and correction factors to the current master position, subtracting the modulo range when the result exceeds 25000. A separate display variable is updated every scan by accumulating delta positions: delta = current_position - last_position, with a rollover branch that runs delta = 25000 - last_position + current_position when delta < 0. The total is captured as the cut length at each synchronization event.

The symptom is deterministic and repeatable: a cut length of 6000 mm reports correctly three times and then once as 5999 (or 6001) on the fourth piece. The error only appears at multiples of the encoder rollover boundary, never during monotonic traversal of the modulo range. The bug is not in the cut-length math itself (the next master position is always computed correctly even across rollover) but in the auxiliary LREAL accumulation used for the operator display.

A secondary symptom is observed on the SIMOTION D410 platform: at system loads approaching 90 percent, the interpolator occasionally produces a corrupted speed reference during a _moveAbsolute command, causing the saw carriage to accelerate forward and then reverse. The same project on a SIMOTION D435 runs the identical motion program at roughly 60 percent load with no anomaly.

Field note: A modulo range is a closed interval only in the mathematical sense. In SIMOTION, the position reported by a modulo-configured technology object (TO) for an external encoder rolls over at the upper boundary; treating 0 and 25000 as two distinct physical samples is the root cause of the off-by-one display error.

System Configuration

The reference hardware and firmware used in field reports:

Item Value / Part
Motion controller SIMOTION D410 (basic D controller) and SIMOTION D435 (standard D controller) — see Siemens Industry Online Support
Engineering tool SIMOTION SCOUT (or TIA Portal with SIMOTION option)
Master axis External encoder TO, modulo range 0 to 25000 user units, position type LREAL
Following axis Synchronous axis, geared to master via SIMOTION synchronous operation
Cut length 6000 mm (typical); physical saw blade width and correction factor applied in software
Servo cycle (D410) 2 ms
IPO cycle (D410) 2 ms nominal, raised to 4 ms to clear the interpolator anomaly
Servo cycle (D435) 0.5 ms
IPO cycle (D435) 1 ms
System load target ≤ 70 % CPU utilization on the motion controller (per Siemens commissioning guidance)

For the canonical D410, D425, D435, D445, and D455 controller descriptions, cycle-time limits, and memory budgets refer to the SIMOTION D4xx Commissioning and Hardware Installation Manual in the Siemens support portal. The D410 sits at the lower performance tier of the family and supports a minimum IPO cycle of 2 ms; the D435 and D445 support IPO cycles down to 0.5 ms. For a flying saw, the relationship between IPO cycle and achievable synchronization precision is direct: at 1 m/s line speed, a 1 ms IPO cycle allows 1 mm of setpoint quantization, and 0.5 ms allows 0.5 mm.

Root Cause: Modulo Boundary Semantics

When an external encoder TO is configured as a modulo axis with range 0 to 25000, the position value reported by the system lives in the closed interval [0, 25000]. Two issues interact:

  1. Displayable maximum equals the period. SIMOTION reports positions including the upper boundary, so the value 25000.0 is a valid sample. However, 0.0 and 25000.0 represent the same physical angular or linear location. Any algorithm that treats them as two distinct samples will count one extra increment per revolution.
  2. Hardware counter and modulo map are not equivalent. A real encoder that produces 25000 pulses per revolution increments its internal counter 0, 1, 2, ..., 24999, and then wraps. There is no count at index 25000. When SIMOTION maps that counter into a user-unit position with a 25000-unit modulo range, the mapping can produce either 0.0 or 25000.0 at the boundary depending on whether the conversion is done before or after the wrap, and depending on the LREAL rounding direction.

The accumulation algorithm in the source project does this:

// Original (buggy) snippet, run every servo cycle:
delta := currentPos - lastPos;
IF delta < 0.0 THEN
    // Rollover detected
    delta := 25000.0 - lastPos + currentPos;
END_IF;
totalLength := totalLength + delta;
lastPos := currentPos;

At the boundary the following sequence occurs:

  1. lastPos = 24999.9 (LREAL sample one cycle before wrap)
  2. currentPos = 0.0 (LREAL sample one cycle after wrap, encoder counter wrapped cleanly)
  3. delta = -24999.9 → branch executes → delta = 25000.0 - 24999.9 + 0.0 = 0.1. Correct so far.

But in the LREAL floating-point representation, a value that should be exactly 25000.0 can read as 24999.9999999 (one ULP low) or 25000.0000001 (one ULP high) depending on the encoder interface's last multiplication step. If lastPos ever lands at 25000.0000001 and currentPos lands at 0.0, the branch computes delta = 25000 - 25000.0000001 + 0 = -0.0000001, which is still negative but the magnitude is wrong. In the next scan, lastPos = 0.0, currentPos = small positive number, delta = small positive number, and the rollover that should have been counted has been silently consumed by the previous malformed sample.

At 6000 mm cut length the rollover happens at the 5th piece (5 × 6000 = 30000, modulo 25000 = 5000). The error manifests "every fourth piece" because three monotonic increments of 6000 are followed by a 4th interval that crosses the boundary, and the boundary traversal is the only place the accumulation can fail. The LREAL error does not appear on monotonic scans because delta stays positive and the rollover branch is never entered.

Mathematical Analysis: Why the Off-By-One Occurs

Let P(n) be the position at the end of the nth cut and C be the cut length in user units:

  • Monotonic case: P(n) = n × C with no wrap. delta = C, accumulated = n × C. Correct.
  • Wrap case: P(n) = (n × C) mod 25000. The true advance since the last cut is still C, but the observed LREAL delta is (P(n) - P(n-1)) which is negative. The correction branch must recover C from a value that has already been distorted by LREAL rounding.

For the correction branch to be exact, the equality delta_observed = 25000 - P(n-1) + P(n) must hold, which requires P(n-1) + delta_observed = P(n) + 25000. If P(n-1) is read as 25000.0 + ε and P(n) is read as 0.0, the equation gives delta_observed = -ε, which the algorithm treats as a backward move and then re-biases by adding 25000, producing a delta close to 25000 - ε. The accumulator advances by approximately 25000 instead of 0 to C. The error is bounded by ε, but its sign flips depending on the LREAL rounding direction, so the cut length reads as either 6001 (over-count) or 5999 (under-count).

The cleanest framing: the LREAL modulo value, when used as a velocity or distance source, has a count of (N + 1) distinct samples for a period of N. Treating it as a count of N samples is the mistake.

Diagnostic Procedure

Use this procedure to confirm the modulo-boundary theory before changing any code.

  1. Open the master axis online in SCOUT or TIA Portal (Online > Watch Table or a trace).
  2. Insert a watch on EncoderTO.Position as LREAL with full precision (no fixed-point display).
  3. Trigger a long trace at 1 ms or 2 ms, capturing at least 2 full modulo revolutions.
  4. Capture the value of totalLength and delta on every cycle.
  5. Filter the trace for currentPos < lastPos events (the rollover branch).
  6. For each filtered event, compute the expected delta (= 25000 - lastPos + currentPos) by hand and compare to the logged delta. Any disagreement beyond 1 × 10-9 confirms LREAL rounding is corrupting the branch.
  7. Compute the cut length as totalLength[end] - totalLength[start] for each of the last 8 cuts in the trace. The expected sequence for a 6000 mm cut is 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000. A single deviation of ±1 at a known modulo-boundary cut confirms the bug.
Tip: To force a rollover for the test, drive the master at a slow speed and watch the position trace cross 25000. Do not rely on production cut cycles for the diagnostic; the off-by-one is a rare event in absolute time but is deterministic in the cycle count since the last rollover.

Corrected LREAL Accumulation Algorithm

The root fix is to drop the LREAL subtraction and instead track the rollover explicitly. A 32-bit DINT (or 64-bit LINT) rollover counter and the raw modulo position together produce an unambiguous total. The display value is computed only for human use and is never used for further motion math.

// Corrected accumulation in SIMOTION ST:
IF currentPos < lastPos THEN
    // Rollover detected. Threshold should be a value that cannot occur
    // during normal monotonic motion (typically modulo_range / 2).
    rolloverCount := rolloverCount + 1;
END_IF;
lastPos := currentPos;
totalLength := INT_TO_LREAL(rolloverCount) * 25000.0 + currentPos;

With this algorithm:

  • Monotonic scans: rolloverCount is unchanged, totalLength advances by the raw LREAL delta between scans.
  • Rollover scans: rolloverCount increments by exactly 1, totalLength jumps by (25000 - lastPos + currentPos) regardless of LREAL rounding at the boundary.
  • The error from LREAL precision is bounded to the increment between two consecutive scans, which is at most the maximum line speed times the scan period. For 5 m/s line speed at 2 ms servo cycle, that is 10 mm per scan, not 1 mm per scan, so the corrected algorithm cannot produce a 1 mm error.

A more defensive variant uses a threshold for the rollover detection:

// Defensive variant — only treat as rollover if delta is implausibly negative
delta := currentPos - lastPos;
IF delta < -12500.0 THEN  // half the modulo range
    rolloverCount := rolloverCount + 1;
END_IF;
lastPos := currentPos;
totalLength := INT_TO_LREAL(rolloverCount) * 25000.0 + currentPos;

The 12500 threshold (half the modulo range) prevents a single corrupted LREAL sample from being mistaken for a rollover. The legitimate rollover produces a delta close to -25000 plus a small forward step; a single-LREAL noise spike rarely exceeds -12500.

Hardware Counter Migration (32-bit / 64-bit)

For installations with high line speed and long production runs, the LREAL accumulator still accumulates a small per-scan rounding error. The robust solution is to read the raw 32-bit hardware counter from the encoder interface (where available) and perform the modulo math in DINT.

On SIMOTION D410 and D435, the external encoder TO exposes the position in user units (LREAL) and, depending on the encoder interface module (e.g., SMC30, TM PosInput), the raw counter value. Where the raw counter is available:

// Read the raw 32-bit up-counter that never wraps in user space.
// This counter is the cleanest source for total length.
rawCount := EncoderTO.CounterValue;        // DINT, monotonic within a hardware wrap
hardwareWrapCount := EncoderTO.WrapCount;   // DINT, increments on each hardware wrap
totalCounts := INT_TO_DINT(hardwareWrapCount) * 2147483647 + rawCount;
totalLength := INT_TO_LREAL(totalCounts) * userUnitsPerCount;

If the encoder interface does not expose a separate wrap count, install one in the encoder TO configuration: in SCOUT, navigate to the external encoder TO, open Properties > Encoder > Signal evaluation, and enable the option to capture the absolute counter. Consult the relevant SIMOTION Sensor Connection manual for the specific SMC30 or TM PosInput version in use for the exact register addresses and the supported counter width.

Warning: When migrating from a custom LREAL accumulator to a hardware counter, do not reuse the LREAL totalLength variable for any control decision (cut point, gear disengage, saw trigger) until the new source has been correlated with a manual measurement over at least 10 full modulo revolutions. The LREAL value that drives the operator HMI is the only place this fix should be inserted first.

SIMOTION Configuration Best Practices

For a flying saw using a modulo master, apply the following configuration in SCOUT or TIA Portal:

  • Configure the external encoder TO with Modulo = Yes, Modulo range = 0 to 25000, and Position type = LREAL. Do not change to DINT; the LREAL is the correct user-unit type and the DINT migration applies only to the internal counter.
  • Set the encoder's Unit to mm (or the user unit of the conveyor) and the Resolution to 25000 increments per revolution. This is the source of the 25000 count figure.
  • On the synchronous axis, set the Gear type to synchronous operation with Synchronization position derived from the next master position. The gear ratio is 1:1 (or whatever the mechanical ratio of the saw carriage is).
  • Place the corrected accumulation in a BackgroundTask or the IPO-synchronized user task. Do not place it in the ServoTask; servo tasks should be reserved for time-critical control code.
  • When commissioning, set the IPO cycle to 4 ms on a D410 (as the source project did) and verify the interpolator anomaly is gone before tightening it back toward 2 ms.

SIMOTION D410 vs D435 Cycle Time and Load Behavior

The cycle time hierarchy on a SIMOTION D controller is:

Cycle Purpose D410 minimum D435 minimum
Servo Position control loop, current/torque control interface 1 ms (2 ms in some firmware builds) 0.5 ms
IPO Interpolator, setpoint generation, MCC chart execution, user BackgroundTask hooks 2 ms 1 ms
DP / PN PROFIBUS DP or PROFINET I/O cycle for distributed I/O 1 ms 0.5 ms

The D410 CPU budget is consumed by the same firmware stack as the D435 but at a lower clock rate and with less memory bandwidth. A D410 running a flying saw with the following load profile is at the edge of its capability:

  • 2 ms Servo
  • 2 ms IPO (MCC chart with several motion commands, gear enable, gear disable, move-absolute sequences)
  • 2 ms DP (PROFIBUS DP cycle for the drive and I/O)
  • BackgroundTask at 10 ms for HMI data and accumulator

Siemens commissioning guidance is to keep total CPU load below 80 percent for any controller in the SIMOTION family, and ideally below 70 percent on a D410 because the headroom is needed for the interpolator. Above 80 percent, the IPO cycle can be missed; above 90 percent, the interpolator's output setpoint can be a stale or partially computed value. The user observed the second case: every 10 to 30 cycles, the interpolator produced a velocity reference that had the magnitude of a forward move but the sign of a return move, causing the carriage to accelerate forward and then snap back.

The D435 in the same project runs 0.5 ms Servo and 1 ms IPO with a 60 percent load. The extra headroom is enough to absorb the interpolator workload even when the motion program crosses a gear transition (enable, disable, move-absolute). If the D410 cannot be made stable at the desired cycle times, the upgrade path is to a D435 or D445 with the existing program reloaded; the program is portable across the D4xx family. See the SIMOTION Motion Control — Function Manual for the controller comparison table and the recommended load limits.

The Interpolator Speed Reference Anomaly

The exact mechanism of the D410 anomaly is not an LREAL issue; it is a CPU budget issue. When the IPO task overruns its cycle time, the runtime can take one of the following actions depending on the firmware build:

  • Skip the current IPO pass and reuse the previous setpoint (silent starvation; motion continues but with one cycle of latency).
  • Output a zero or default setpoint (the drive holds position; usually recoverable).
  • Output a setpoint computed from a partially executed MCC chart (the visible glitch: the carriage gets a forward then a reverse command in successive cycles).

The third option matches the reported symptom. The fix has three layers:

  1. Increase the IPO cycle to give the CPU more headroom. 4 ms is a reasonable compromise for a flying saw on a D410; the synchronization precision loss is small compared to the saw blade width.
  2. Reduce the number of MCC commands per cycle. A sequence of _enableGear, _disableGear, _moveAbsolute in a single IPO pass is borderline; consider executing only one of these per cycle and queuing the rest.
  3. Upgrade the controller if the application demands an IPO cycle of 2 ms or less with the full motion sequence.
Diagnostic tip: Enable the SIMOTION diagnostic buffer (Diagnostic Overview in SCOUT) and watch for entries of the form IPO cycle time exceeded or Servo cycle time exceeded. The pattern of these entries matches the pattern of the visible glitch. On a stable system, the diagnostic buffer is empty.

Verification and Commissioning Tests

  1. Install the corrected accumulation algorithm with the DINT rollover counter.
  2. Run a controlled test with a known cut length (e.g., 6000 mm) at slow master speed. Capture totalLength, currentPos, and lastPos in a trace over 10 full modulo revolutions.
  3. Verify that totalLength[end] - totalLength[start] equals the expected total advance (cut length × number of cuts) to within the LREAL rounding tolerance, which is well under 0.001 mm at the relevant cycle times.
  4. Run the same test at production line speed. The off-by-one error must not reappear at any cut count within 1000 pieces.
  5. On the D410, set the IPO cycle to 4 ms and run the full motion sequence (enable gear, disable gear, move-absolute) for at least 1000 cycles. The diagnostic buffer must remain empty, and the carriage must not exhibit the forward-then-reverse glitch.
  6. On the D435, run the same sequence with the original 1 ms IPO cycle. The 60 percent load must remain stable, and no diagnostic buffer entries must appear.
  7. Confirm with the operator HMI that the cut length display matches the actual measured piece length within 1 mm on every cut, including the cuts that cross a modulo boundary.

Edge Cases and Robustness Improvements

Three edge cases deserve explicit handling:

  • Power cycle during a cut: The LREAL position is reread from the encoder on power-up. If the cut was active at the moment of power-down, the next synchronization can compute a master position offset by one or more rollovers. Persist the rolloverCount to a retentive variable (e.g., a data set on the SIMOTION retain area) so that the count survives a power cycle. On startup, recompute totalLength from the persisted rolloverCount and the current LREAL position.
  • Master direction reversal: A flying saw normally runs the master in one direction. If the line can run in reverse (e.g., for a recycle path), the rolloverCount must be decremented when the delta is positive and exceeds the half-modulo threshold. The defensive variant above handles this by allowing negative rollovers; the user only needs to track the sign.
  • Encoder index pulse: If the external encoder has an index pulse (Z signal), use it to reset the rolloverCount to zero on each revolution. The SMC30 and TM PosInput modules expose a homing function that captures the counter on index. Configure the encoder TO with Homing mode = Use homing mark and the index pulse will zero the counter and the modulo position together, eliminating any drift between them.

For the operator HMI, expose three values: the current modulo position, the rollover count, and the total length. The maintenance technician can read these three to diagnose any future discrepancy without needing a SCOUT trace.

FAQ

Why does the off-by-one error only appear every fourth piece in a SIMOTION flying saw with 25000-count modulo?

At a 6000 mm cut length the encoder rolls over every 4.17 pieces. The error appears only on the piece that crosses the boundary because the LREAL subtraction and the half-modulo correction branch are both subject to ULP-level rounding at exactly 25000.0. Monotonic scans (no rollover) compute the correct delta because the rollover branch is never entered.

Should the SIMOTION modulo range be configured as 0 to 24999 or 0 to 25000?

Keep the range at 0 to 25000 to match the encoder resolution (25000 increments per revolution). The off-by-one is not a configuration problem; it is a sampling problem. Fix the algorithm to track rollovers explicitly rather than changing the modulo range, which would shift the LREAL rounding point to a different boundary and only postpone the symptom.

How do I eliminate the LREAL rounding error at the modulo boundary?

Replace the LREAL delta with a DINT (or LINT) rollover counter incremented only when the current position is less than the last position. The corrected total length is (rolloverCount × modulo_range) + currentPos, computed in LREAL only for display. For installations with a hardware up-counter, use the raw counter value as the source.

What cycle time is required on a SIMOTION D410 to avoid the interpolator glitch?

Raise the IPO cycle to 4 ms and keep the CPU load below 70 percent. The D410 cannot reliably run a flying saw with a 2 ms IPO when the motion program includes enable-gear, disable-gear, and move-absolute commands in the same cycle. The D435 and D445 controllers run the same program at 0.5 to 1 ms IPO with no anomaly.

How do I detect a missed IPO cycle on a SIMOTION D controller?

Open the SIMOTION diagnostic buffer in SCOUT (or the equivalent TIA Portal view). Entries with text matching IPO cycle time exceeded or Servo cycle time exceeded indicate a missed cycle. An empty buffer during the motion sequence confirms the cycle times are sustainable.

Back to blog