PVALimiter
PVALimiter shapes a position command so the motion it produces respects a position range, a velocity limit and an acceleration limit all at once.10 minute read
PVALimiter shapes a position command so the motion it produces respects a
position range, a velocity limit and an acceleration limit all at once. It
outputs a matching position, velocity and acceleration, so whatever follows it
gets a consistent set.
Its most useful behaviour is at the position limits. Instead of clamping the position — which arrives as a wall and demands an impossible deceleration — it works out, every cycle, the fastest it could be going and still stop in time, and holds the velocity below that. The axis decelerates into the limit and arrives at zero speed.
Deprecated — scheduled for removal.
PvajLimiteris the only setpoint limiter that may be used for new work. It bounds the setpoint in jerk as well as position, velocity and acceleration, and its position guarantee holds with no tolerance where this block’s holds to about 1e-9. This block is kept only until the last machine is off it, and will then be deleted.
It is not a drop-in swap. The replacement has no input filter, so omega,
beta and enablePVAInputs have no counterpart. Feed it the position setpoint
directly and supply the derivatives on its own inputDot and inputDDot
leaves, each behind its own switch. See
PvajLimiter for the parameter reference.
flowchart LR
i1(["input — position reference"]) --> B["PVALimiter"]
i2(["inputDot — velocity reference"]) --> B
i3(["inputDDot — acceleration reference"]) --> B
i4(["disable"]) --> B
B --> o1(["output — limited position"])
B --> o2(["outputDot — limited velocity"])
B --> o3(["outputDDot — limited acceleration"])
B --> o4(["currentMaxVel — allowed velocity now"])
B --> o5(["currentMinVel"])
B --> o6(["pLimActive"])
B --> o7(["vLimActive"])
B --> o8(["aLimActive"])
B --> o9(["state"])
B --> o10(["inputFilt, inputFiltDot, inputFiltDDot"])
B --> o11(["isEnabled"])
Approaching a limit, the allowed velocity is $\sqrt{2 \times \text{distance} \times \texttt{maxBrakingAcceleration}}$ — so at 0.1 m from the limit with a braking limit of 10, the axis may travel at 1.4 m/s.
omegaandbetaset how hard the block chases the input: higheromegatracks more tightly, andbeta4 is heavily damped so it does not overshoot.
Keep maxBrakingAcceleration at or below maxAcceleration. The block sizes
its approach speed on the braking figure but can only ever deliver the
acceleration figure. Setting braking higher promises a stop the block cannot
perform, and the axis overshoots the limit.
Every instance logs a warning at startup with default settings. omega
ships at infinity, meaning “as fast as possible”, and the block corrects it to
what the task rate allows — and says so in the log. It is expected.
Signals
Inputs
| Path | Unit | Range | Description |
|---|---|---|---|
input |
m or rad | unbounded | The position reference to shape. |
inputDot |
m/s or rad/s | unbounded | The velocity reference. Only used when enablePVAInputs is set; ignored otherwise. |
inputDDot |
m/s² or rad/s² | unbounded | The acceleration reference. Same condition. |
disable |
- | - | True bypasses the block: input passes straight to output. Use it for a runtime override; use enable for the configured intent. |
Outputs
| Path | Unit | Description |
|---|---|---|
output |
m or rad | The limited position. Starts from zero after every controller start and moves to the input under its own limits — a real commanded move if the input is not near zero. |
outputDot |
m/s or rad/s | The limited velocity. It is not updated while the block is bypassed, so it holds a stale value from before. |
outputDDot |
m/s² or rad/s² | The limited acceleration. |
currentMaxVel |
m/s or rad/s | The fastest the block will currently allow, given how close the axis is to the upper limit. The single most useful output for understanding why the axis slowed down. |
currentMinVel |
m/s or rad/s | The same toward the lower limit. |
pLimActive |
- | True while the position envelope is holding the velocity down. |
vLimActive |
- | True while the velocity limit is binding. |
aLimActive |
- | True while the acceleration limit is binding — but it is forced false whenever either of the other two is true, so it under-reports. |
state |
- | The same three flags again, grouped. |
inputFilt, inputFiltDot, inputFiltDDot |
m, m/s, m/s² | The block’s internal smoothed copy of the input. Only meaningful while enablePVAInputs is false. |
isEnabled |
- | True when enable is true and disable is false. |
Parameters
| Path | Unit | Default | Range | Effect |
|---|---|---|---|---|
enable |
- | true | - | False bypasses the block. |
lowerLimit |
m or rad | −1.0 | below upperLimit |
The lowest position the output may reach. |
upperLimit |
m or rad | +1.0 | above lowerLimit |
The highest. |
maxVelocity |
m/s or rad/s | 1.0 | above 0 | Speed limit. Negative values are used as their magnitude. |
maxAcceleration |
m/s² or rad/s² | 10.0 | above 0 | How hard the block may accelerate or decelerate in practice. Used as its magnitude. |
maxBrakingAcceleration |
m/s² or rad/s² | 10.0 | at most maxAcceleration |
How hard the block assumes it can brake, when sizing the approach to a position limit. Set it at or below maxAcceleration — see Limits and errors. |
omega |
rad/s | infinity | 0 up to a task-rate ceiling | Tracking bandwidth. Higher follows the input more tightly. The infinite default means “as fast as the task rate allows” and is corrected at startup with a logged warning. |
beta |
- | 4.0 | above 0 | Tracking damping. 4 is heavily damped and does not overshoot. Lowering it makes the output chase harder and eventually ring. |
enablePLim |
- | true | - | Switches the position envelope and the hard position clamp on. False leaves only the velocity and acceleration limits. |
enablePVAInputs |
- | false | - | False: the block derives velocity and acceleration internally from input alone. True: it uses inputDot and inputDDot. This changes how the block tracks, not just what it reads — decide once and leave it. |
All ten are persistent and survive a restart. No parameters exist below this block.
Setup
-
Set
lowerLimitandupperLimitto the axis’s real travel. -
Set
maxVelocityandmaxAccelerationfrom the machine. -
Set
maxBrakingAccelerationequal to or belowmaxAcceleration. Equal is the normal choice. -
Leave
omegaalone. It corrects itself at startup and logs that it did. -
Leave
betaat 4 andenablePVAInputsfalse for a first pass. -
Set
enabletrue. Command a small move well inside the limits and confirmoutputfollowsinputclosely with all three flags false. -
Command a fast move and watch
vLimActiveandaLimActivego true in turn. -
Command a move that runs into a position limit. Watch
currentMaxVelfall as the axis approaches, and confirm the axis arrives at the limit withoutputDotat zero.Step 8 drives the axis into its travel limit deliberately. Do it at low speed first, and confirm the deceleration is inside what the machine can take before repeating it at full speed.
Tuning
- Set the three machine limits first — position, velocity, acceleration. They are properties of the hardware.
- Keep braking at or below acceleration, per Setup step 3. This is the one parameter relationship the block does not check and it is the one that causes overshoot.
- Leave
omegaat its default unless the output visibly lags the input during ordinary moves. It is already as fast as the task rate allows. - Lower
betaonly if the block is too slow to catch a fast input. Below about 1 it starts to overshoot, which for a limiter is the wrong direction. - Use
enablePVAInputswhen your source already produces a consistent position, velocity and acceleration — a setpoint generator, say. It lets the block follow without having to infer the derivatives, so it tracks much more closely. Do not switch it at runtime. - Watch
currentMaxVelduring a limit approach. It is the envelope, and it tells you directly whethermaxBrakingAccelerationis set sensibly: a larger value gives a steeper, later deceleration. - If you need jerk limited as well, this block does not do it — use a PVAJ limiter.
Read the allowed speed at any distance off the curve for your braking setting.
| Symptom | Cause | Action |
|---|---|---|
A warning about omega at every startup |
Expected: the default is infinity and the block corrects it | Ignore it, or set a finite omega |
| The axis overshoots its position limit | maxBrakingAcceleration is higher than maxAcceleration |
Set it at or below the acceleration limit |
| The axis stops well short of the limit and creeps in | maxBrakingAcceleration is very low, so the envelope is conservative |
Raise it, up to maxAcceleration |
| The axis slows down and nothing seems to be limiting | The position envelope is active — check pLimActive and currentMaxVel |
This is the block working as designed |
aLimActive never goes true |
Expected: it is suppressed whenever the position or velocity limit is also active | Watch all three flags together |
| The output lags the input during ordinary moves | omega too low, or beta too high |
Leave omega alone and try enablePVAInputs if your source provides derivatives |
| The output overshoots the input | beta too low |
Raise it back toward 4 |
Tracking changed when enablePVAInputs was switched |
Expected: it changes how the block tracks, not just what it reads | Choose one mode and keep it |
inputDot and inputDDot seem to be ignored |
Expected: they are only read when enablePVAInputs is true |
Set that parameter |
| The axis made a move immediately after a restart | Expected: the output starts at zero and travels to the input under its limits | Command the machine’s actual position first, or gate the consumer |
| The velocity output is wrong just after re-enabling | Expected: outputDot is not updated while bypassed and resumes from a stale value |
Re-enable at rest |
| The position stopped at the limit but the velocity output is not zero | The hard backstop clamped the position without zeroing the velocity — the envelope did not do its job | Check maxBrakingAcceleration against maxAcceleration |
| Motion is jerky at the start and end of moves | Expected: this block bounds acceleration, not jerk | Use a PVAJ limiter |
| A non-numeric value latched into the outputs | The block holds state and there is no reset | Bypass the block for one cycle to recover the position; restart to clear the velocity |
A starting point for an axis with 1 m of travel, 1 m/s and 10 m/s² on a 1 ms task:
enable = true
lowerLimit = -0.5
upperLimit = 0.5
maxVelocity = 1.0
maxAcceleration = 10.0
maxBrakingAcceleration = 10.0
beta = 4.0
enablePLim = true
enablePVAInputs = false
Limits and errors
| Limit | Set by | What happens | Reported |
|---|---|---|---|
maxBrakingAcceleration at most maxAcceleration |
Nothing | Not checked. A higher braking figure makes the block approach the limit faster than it can stop, and the axis overshoots | Not reported |
output position |
lowerLimit, upperLimit while enablePLim is set |
Bounded two ways: the velocity envelope decelerates the axis in, and a hard clamp catches anything the envelope missed. The clamp does not zero the velocity, so the two outputs can disagree on that cycle | pLimActive |
outputDot |
maxVelocity, and the position envelope |
Bounded by whichever is lower | vLimActive, currentMaxVel, currentMinVel |
outputDDot |
maxAcceleration |
Clamped | aLimActive, but it is suppressed whenever the position or velocity limit is also active |
| Jerk | Nothing | Not limited. Acceleration can step | Not reported |
omega |
Task rate and beta |
Corrected to a stable value at startup and on every cycle. The infinite default always triggers this | Logged as a warning each time it corrects |
beta, maxVelocity, maxAcceleration, maxBrakingAcceleration |
Sign forced | Negative values are used as their magnitude | Not reported; read them back |
| Zero acceleration limits | Fixed | Either at exactly zero forces the allowed velocity to zero, stopping the axis where it stands | pLimActive |
| Block state | Nothing | The output position and velocity are not cleared at start and there is no reset input. Bypassing recovers the position but not the velocity | Not reported |
| Channel count | Fixed | One axis per instance. Use the plural block for several | Not reported |
The block logs a warning whenever it corrects omega or beta — which with
the default settings happens once at startup for every instance. Every other
failure above shows as a value on a trace, not as a message.
Verified against motorcortex-control3 3.32.1 (340db23).