Offsets on an SMC_trafo_xxx transformation block are added directly to the commanded axis position, so the write itself sets the velocity demand: 1 mm in one 2 ms cycle is 500 mm/s. Write offsets at standstill, rate-limit any shift during motion, and bound the result with the axis configuration and bAvoidGaps on SMC_ControlAxisByPos.
Shifting the work zero on a SoftMotion CNC looks like a geometry change: same program, new place on the table. The part that stops machines is timing. The offset inputs of an SMC_trafo_xxx transformation block are added directly to the commanded axis position. The cycle in which you write the value is the cycle in which the axis is told to be somewhere else, and nothing between that write and the drive ramps, filters or bounds the change. This article works the arithmetic that turns an offset step into a velocity demand. It shows the two places where limits belong (the axis configuration and SMC_ControlAxisByPos with bAvoidGaps), and gives the write discipline that avoids creating the step at all.
What does an SMC_trafo_xxx offset do to the axis position?
An offset value on an SMC_trafo_xxx transformation block is added straight to the commanded axis position, with no ramp, no filter and no dynamic limiter in between. A 1 mm change to the offset is a 1 mm step in the position the axis is commanded to take.
The addition happens after path interpolation. SMC_Interpolator hands the transformation a Cartesian setpoint, the transformation converts it to axis coordinates and adds your offsets, and the sum is the position SMC_ControlAxisByPos writes into the axis. An offset is not queued like a programmed move and not checked like one; it takes effect in the cycle in which it is written. That is why an edit made while a job runs shows up as motion. The geometry is fine. The write is what moves the axis.
Example: what velocity does a 1 mm offset step demand at a 2 ms cycle?
One millimetre written into an offset in a single cycle of the task demands 500 mm/s from the axis for that one cycle. The arithmetic is 1 mm divided by 0.002 s, which is 500 mm/s, and the acceleration demand of an ideal step is unbounded.
The demand scales with the step and inversely with the cycle time:
| Offset change | Task cycle | Command the axis sees |
|---|---|---|
| 1 mm written at once | 2 ms | 1 mm / 0.002 s = 500 mm/s |
| 25 mm written at once | same | 12,500 mm/s |
| The same shift, rate-limited at 25 mm/s | same | 0.05 mm per cycle |
Machine case: an XZ gantry runs an SMC_trafo_xxx block from a motion task at that period. The axis configuration allows a 500 mm/s maximum velocity, and the worst path velocity measured on X is 450 mm/s, so 50 mm/s of headroom remains. An operator applies a 25 mm work shift.
Written as one value, the demand is 25 times the configured maximum, 12,500 mm/s. The drive cannot track it. The following-error monitor trips and the job stops, or the gantry lurches if that window was set loose.
At the rate-limited setting, the active offset moves 0.05 mm per cycle. The shift completes in 500 cycles, which is 1.0 s, and the worst demand on X is 450 + 25 = 475 mm/s, inside the 500 mm/s ceiling.
A slower motion task lowers the demand for the same step, since the velocity is the step divided by the cycle time. If the runtime's ability to hold that period under full load is uncertain, a load sweep finds the cycle-time limit the runtime actually delivers.
Why do interpolator limits not hold an offset step back?
The velocity, acceleration and jerk limits in the interpolator apply to the programmed path only. An offset enters downstream of SMC_Interpolator at the transformation, so the machinery that respects path limits never sees the step your offset write creates.
The path limits are applied to data the interpolator produces from the program queue. Your offset write enters after that stage, so those limits never act on it. Treat the offset input as if it were wired straight to the position command: one addition separates the value you write from the setpoint the drive receives.
What does the drive do when the step arrives?
The drive receives a position command far ahead of its actual position and reacts with a following-error fault, a torque spike that shocks the mechanics, or a fast real move. Which one depends on how tightly the axis limits and the following-error window are set.
A tight window faults the axis quickly and the machine stops in a controlled way. A loose window lets the mechanics absorb the shock, and the event tends to resurface as a load alarm. Servo drives often report exactly that; AL-18 on one common servo drive family, for instance, is documented as load demand rather than idle operation. Check the alarm list for your drive before you treat a load alarm as a mechanical fault.
Where do you limit the step in the axis configuration?
The axis configuration is the backstop. Set its maximum velocity, acceleration and deceleration to values the mechanics survive, switch on the software limit switches inside the hard travel, and set the following-error window tight enough to trip before the machine absorbs a step.
These settings bound every command the axis receives, including one created by a bug, a torn write or a typed mistake. They work by tripping: when a limit fires you get a fault and a stop, never a smooth shift. That is why the prevention belongs upstream in the write logic. Set them at commissioning, before any shifting logic exists, and treat a trip during production as evidence that a step reached the axis. Take the exact parameter names from the documentation for your project's library version, because they differ between versions.
How does bAvoidGaps on SMC_ControlAxisByPos limit the gap?
SMC_ControlAxisByPos writes the cyclic setpoint into the axis. With bAvoidGaps = TRUE it intervenes when the velocity of fSetPosition is greater than the maximum velocity configured, which bounds what a stray offset step can demand from the drive. This behavior is documented for the block in the SoftMotion CNC documentation; check your installed library version, because the inputs around bAvoidGaps have changed between versions.
This is the second place limits belong, on the block that writes the setpoint. With gap avoidance enabled, the block compares the velocity of fSetPosition with the axis's configured maximum and acts when the setpoint demands more than the axis is allowed to do. The excess is limited at the block and the remaining difference is closed as a controlled move. A gap that appears in production, with nobody shifting anything, means an offset is being written at the wrong time. Find the write, not the gap.
When can you write an offset safely?
Write offsets only when the interpolator is idle, the path velocity is zero and every axis is in position. Latch a buffered value into the transformation input in one write from the motion task.
Build the gate in the motion task: one condition that is TRUE only when the interpolator is idle, the path velocity is zero and every axis is in position. Operators edit a shadow variable, and a single Apply action copies the shadow into the active offset inside that gate. This removes two failure modes at once. A half-typed value never reaches the axis, and a value written from a slower task is never read half-updated. Which value the motion task sees when two tasks touch the same variable follows from the execution order across the task layers, so check that order before trusting any write that is not in the motion task. After an offset change made with control off, the distance between the new setpoint and the actual position is itself a gap; re-enable with the gap handling armed so the first move is bounded too.
How do you rate-limit an offset shift that must happen during motion?
Rate-limit the active offset toward its target in the motion task. Allow at most v_shift × t_cycle of movement per cycle, and choose v_shift so the shift velocity plus the worst-case path velocity stays inside the axis maximum velocity.
Call the shift speed v_shift and the motion task period t_cycle; the increment per cycle is v_shift × t_cycle. The names below are illustrative, not library names. The pattern is a rate limiter that runs in the motion task and writes the active value to the trafo input:
rOffsetTarget : REAL := 0.0; // wanted offset, mm
rOffsetActive : REAL := 0.0; // wired to the SMC_trafo_xxx offset input, mm
rShiftSpeed : REAL := 25.0; // mm/s, inside the axis velocity headroom
rCycleTime : REAL := 0.002; // s, motion task period
rDeltaMax : REAL := rShiftSpeed * rCycleTime; // 0.05 mm per cycle
rDiff : REAL := rOffsetTarget - rOffsetActive;
IF rDiff > rDeltaMax THEN
rOffsetActive := rOffsetActive + rDeltaMax;
ELSIF rDiff < -rDeltaMax THEN
rOffsetActive := rOffsetActive - rDeltaMax;
ELSE
rOffsetActive := rOffsetTarget;
END_IF
Check the result by arithmetic: with the values above, rDeltaMax is 0.05 mm per cycle. The full shift needs 500 cycles, which is 1.0 s at that task period, and the largest command change in any single cycle is 0.05 mm. The first cycle still starts the shift at full shift speed, a small velocity step; limiting the change of the per-cycle increment as well removes it. On kinematics that are not Cartesian, the same Cartesian increment can demand much more joint motion near a singularity or a travel end. Run the limiter on the joint-side values there, or keep the write gate at standstill.
What do you change first on a machine that already faults?
Set the write gate so offsets change only at standstill, switch bAvoidGaps to TRUE on SMC_ControlAxisByPos, and check that the axis configuration's maximum velocity, acceleration and software limits are mechanically safe, in that order. The gate removes the step; the other two bound whatever slips through.
Recommendation: Gate every offset write to standstill (interpolator idle, path velocity zero, axes in position) and edit through a shadow variable with one Apply action. Where the process genuinely needs a shift during motion, rate-limit the offset at a speed that fits the axis's velocity headroom, as in the worked example above, and set bAvoidGaps = TRUE on SMC_ControlAxisByPos. Keep the axis configuration's maximum velocity, acceleration and software limits at mechanically safe values as the backstop, and if one of them trips in production, stop and find the write that created the step.
Questions
Does an offset written inside the part program cause the same step?
No. Coordinate changes programmed in the part program are queued and shaped by the interpolator, so the path velocity and acceleration limits apply to them. The direct-add behavior applies to the offset inputs of the transformation block, which sit downstream of SMC_Interpolator. A programmed move of that size follows the path dynamics; the same size written to the trafo offset input does not.
Which cycle time goes into the velocity arithmetic?
The period of the task that writes the setpoint, normally the motion task. A slower cycle lowers the demand for the same step, since the velocity is the step divided by the cycle time: 1 mm is 500 mm/s at 2 ms and 100 mm/s at 10 ms, still a step the drive has to absorb.
Do I need to rate-limit an offset that just moves the zero before the next job?
No. Applied at standstill before the next program starts, the shift only defines where that program begins. Its first move then starts from the shifted zero under full path control, so the interpolator ramps it and the path limits apply. Rate limiting is only needed when the offset changes while the axes are already moving, as in a tracking correction.
Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.