SmoothStop

SmoothStop brings a moving axis to a controlled standstill on command.
3.30–3.34

SmoothStop brings a moving axis to a controlled standstill on command. When you raise gotoStandstill it takes over from the live motion reference, follows a jerk-limited braking profile down to zero velocity, and holds there. Release the command and it fades back to the live reference.

The stop is bounded three ways at once — by deceleration, by jerk, and by whichever of a time budget or a distance budget runs out first. If the natural profile would exceed a budget, the block computes a shorter one rather than letting the stop overrun.

flowchart LR
    i1(["u — live position reference"]) --> B["SmoothStop"]
    i2(["uDot — live velocity reference"]) --> B
    i3(["uDDot — live acceleration reference"]) --> B
    i4(["gotoStandstill"]) --> B
    i5(["resetStandstill"]) --> B
    B --> o1(["y — position output"])
    B --> o2(["ydot — velocity output"])
    B --> o3(["yddot — acceleration output"])
    B --> o4(["yss — braking profile position"])
    B --> o5(["yssDot — braking profile velocity"])
    B --> o6(["yssDDot — braking profile acceleration"])
    B --> o7(["smoothStopActive — per channel"])
    B --> o8(["isAtStandstill"])
    B --> o9(["standstillSwitchIsOn"])
    B --> o10(["standstillSwitchIsOff"])

Stopping distance from velocity $v$ with deceleration $a$ is roughly $v^2/2a$, and jerk rounds the corners at each end. The stop takes about $v/a + a/j$ seconds. maxStopJerkFactor is the fraction of the stop spent ramping the deceleration, from 0 (a pure trapezoid, sharpest) to 0.5 (a pure triangle, gentlest).

Both limits default to zero, which means “stop instantly”. With smoothStopAcc and smoothStopJerk at 0 the block jumps the output to where the axis was and holds it — a hard stop from a block called SmoothStop. Set both before you use it.

gotoStandstill is a level, not a pulse. Hold it true and the axis stays stopped; release it and the block fades back to the live reference.

Signals

Inputs

Path Unit Range Description
u m or rad unbounded The live position reference the axis normally follows. One element per channel.
uDot m/s or rad/s unbounded The live velocity reference.
uDDot m/s² or rad/s² unbounded The live acceleration reference.
gotoStandstill - - Raise it to begin stopping; hold it to stay stopped; release it to fade back to the live reference. A level, and one value for the whole block.
resetStandstill - - Makes the changeover between the live reference and the braking profile happen instantly rather than fading. Use it when a fade would itself be a disturbance.

Outputs

Path Unit Description
y m or rad The position to follow — the live reference, the braking profile, or a fade between them. This is what the axis should track.
ydot m/s or rad/s The matching velocity. Note the lower-case path name, where the input is uDot.
yddot m/s² or rad/s² The matching acceleration.
yss m or rad The braking profile’s own position, whether or not it is currently selected. Useful for watching a stop that has not been engaged.
yssDot m/s or rad/s The braking profile’s velocity — watch this to see the stop shape.
yssDDot m/s² or rad/s² The braking profile’s acceleration.
smoothStopActive - True per channel while that channel’s braking profile is still running.
isAtStandstill - True when every channel has finished stopping and is at rest. One value for the whole block.
standstillSwitchIsOn - The changeover has fully reached the braking profile.
standstillSwitchIsOff - The changeover has fully reached the live reference.

Parameters

Path Unit Default Range Effect
smoothStopAcc m/s² or rad/s² 0.0 above 0, per channel Deceleration limit. 0 means an instant stop. Higher stops sooner and harder. Negative values are used as their magnitude.
smoothStopJerk m/s³ or rad/s³ 0.0 above 0, per channel Jerk limit — how fast the deceleration may build. 0 means an instant stop. Higher gives sharper corners.
maxStopTime s 0.0 at least one task period, per channel The longest the stop may take. If the natural profile would exceed it, the block computes a harder one that fits. Corrected up to one task period if set lower.
maxStopDistance m or rad 0.0 0 upward, per channel The furthest the axis may travel while stopping. Same treatment as the time budget.
maxStopJerkFactor - 0.0 0 – 0.5, per channel Only used when a budget forces a recomputed profile. 0 gives the sharpest stop that fits, 0.5 the gentlest. Corrected silently if out of range.
startAtStandstill - false - When true, the block comes up stopped on the first cycle instead of following the reference.

All six are persistent and survive a restart, and the first five are per channel.

One parameter lives below this block: the changeover’s fade time, in the standstillSwitch sub-tree. See soft-switch.md.

Setup

  1. Set smoothStopAcc and smoothStopJerk first. Both default to zero, which makes the block stop the axis instantly. Start with the deceleration the machine uses for a normal decelerating move, and a jerk about ten times that.

  2. Set maxStopTime and maxStopDistance from the machine’s real safety budget — how long and how far the axis may keep moving after a stop is commanded.

  3. Set maxStopJerkFactor to 0.25 as a starting point. It only matters when a budget forces a shorter profile.

  4. Link u, uDot and uDDot from the motion source, and y, ydot, yddot to whatever follows. Confirm the outputs track the inputs exactly with gotoStandstill false.

  5. With the axis moving slowly, raise gotoStandstill. Watch yssDot come down to zero and isAtStandstill go true.

    Step 5 stops a moving machine. Do it at low speed first, with the axis clear, and confirm the distance travelled is inside your budget before trying it at full speed.

  6. Measure the stop: time it, and measure how far the axis travelled. Compare both against maxStopTime and maxStopDistance.

  7. Release gotoStandstill and confirm the outputs fade back to the live reference without a bump.

Tuning

  1. Set the deceleration from the machine — what the mechanics, the drive and the load can take. This is a physical limit, not a preference.
  2. Set the jerk from what the structure tolerates. Lower jerk gives rounder corners and a longer stop; higher jerk stops sooner and shakes more.
  3. Check the resulting stopping distance at full speed: roughly $v^2/2a$ plus a little for the jerk ramps. If it exceeds the budget, either raise the deceleration or accept that the block will override your limits.
  4. Watch yssDot on a trace during a stop. It should fall smoothly to zero with no overshoot and no residual crawl.
  5. If a budget is forcing a recomputed profile, the actual deceleration and jerk used will be higher than what you configured — and the block does not publish them. Infer them from the trace.
  6. Use maxStopJerkFactor to shape those forced stops: lower for the shortest stop that fits, higher for the gentlest.
  7. Set the changeover fade time in the standstillSwitch sub-tree so releasing the stop is smooth. The engagement is instant by design — the profile starts exactly where the axis is, so there is nothing to fade.

Velocity during a stop from 1.0 with a deceleration of 2, at three jerklimits: a jerk of 100 is nearly a straight ramp stopping at 0.53 s, 10 roundsthe corners and stops at 0.71 s, and 4 is gentlest and takes just over asecond.

Read the deceleration off the slope of the straight section and the jerk off how rounded the corners are.

Symptom Cause Action
The axis stops dead instead of smoothly smoothStopAcc or smoothStopJerk is 0 — the default Set both to real values
The stop is harsher than configured A budget forced a shorter profile Raise maxStopTime or maxStopDistance, or accept it
The stop overshoots the distance budget The budget branch cannot fully compensate when the axis is still accelerating at the moment of the stop Command the stop from a steady speed where possible, and leave margin
A jolt at the start of the stop The axis was accelerating when the stop was commanded, and the recomputed profile starts from zero acceleration Leave margin in the budgets so the natural profile is used
The stop takes longer than expected Jerk too low, so the corners dominate Raise smoothStopJerk, or lower maxStopJerkFactor
The machine shakes during the stop Jerk too high Lower smoothStopJerk, or raise maxStopJerkFactor
isAtStandstill never goes true One channel has not finished — it needs every channel stopped Check smoothStopActive per channel
The axis crawls instead of settling exactly at zero Not possible — the profile lands on exactly zero by construction Check what consumes y
A bump when the stop is released The changeover fade is too fast Lengthen the fade time in the standstillSwitch sub-tree
A bump when the stop is engaged Expected: engagement is instant, but the profile starts where the axis is, so it should be seamless. A bump means u and y had already diverged Check the outputs were tracking before the stop
The changeover jumps instead of fading resetStandstill is being held true Release it
The axis comes up stopped after a restart Expected: startAtStandstill is set Clear it if the axis should follow the reference immediately
One channel stops differently from the others Expected: all five limits are per channel Check every element
I cannot tell what deceleration is actually being used The block does not publish the limits it computes when a budget binds Measure the slope of yssDot on a trace
A non-numeric value appeared and will not clear There is no reset input Restart the controller

A starting point for an axis that decelerates at 2 units/s² and must stop within half a second and a quarter of a unit:

smoothStopAcc     = 2.0
smoothStopJerk    = 20.0
maxStopTime       = 0.5
maxStopDistance   = 0.25
maxStopJerkFactor = 0.25
startAtStandstill = false

This is a starting point, not a final tuning. Work Setup step 6 with your own machine.

Limits and errors

Limit Set by What happens Reported
smoothStopAcc, smoothStopJerk above 0 Nothing Not checked, and both default to 0, which makes the stop instant. Negative values are used as their magnitude Not reported
Stop time maxStopTime If the natural profile is longer, a harder profile is computed to fit. Corrected up to one task period if set below it Not reported; the actual limits used are not published
Stop distance maxStopDistance Same treatment. Corrected up to 0 if set negative Not reported
maxStopJerkFactor within 0 – 0.5 Fixed Corrected to the nearest edge Silently; read it back
Starting acceleration Not handled in the budget branch When a budget forces a recomputed profile, the axis’s acceleration at the moment of the stop is ignored, so the deceleration begins with a step Not reported
Actual deceleration and jerk Not published When a budget binds, the limits actually used are higher than the configured ones and cannot be read from the parameter tree Not reported
y, ydot, yddot Nothing Unbounded — the block shapes the stop, it does not bound the reference Not reported
Block state Nothing The latched profile and the changeover state are not cleared at start. There is no reset input Not reported
Non-numeric input Nothing Not guarded anywhere Not reported
Channel count Machine configuration Fixed once the controller starts Not reported

The block raises no errors or warnings. It writes one debug log line per channel at the moment a stop is triggered, recording the position, velocity and acceleration it latched. Every failure above shows as a value on a trace, not as a message.


Verified against motorcortex-control3 3.30.0 (bc348fd).