HardLimitVector

HardLimitVector limits the length of a vector rather than each of its components.
3.30–3.34

HardLimitVector limits the length of a vector rather than each of its components. When the vector is too long every component is scaled down by the same factor, so the direction is preserved exactly and only the size changes.

That is why it exists. Clamping a Cartesian velocity component by component turns a diagonal move into a different diagonal — the axis that reaches its bound first stops growing while the others carry on, and the commanded direction rotates. Scaling the whole vector keeps the direction and just slows the move down.

flowchart LR
    i1(["input — the vector's components"]) --> B["HardLimitVector"]
    i2(["disable"]) --> B
    B --> o1(["output — scaled or unchanged vector"])
    B --> o2(["isLimiting"])
    B --> o3(["isEnabled"])

upperLimit is the maximum length of the whole vector, as a single number — not a bound on any one component. While the length is inside the limit the output is the input exactly. Beyond it, every component is multiplied by upperLimit ÷ the actual length.

Every component must share the same unit. The block computes one length across all of them, so a mixed vector — a pose with metres in some elements and radians in others — has a length with no physical meaning. Use one instance per unit group.

There is no lower limit, and there cannot usefully be one: a zero-length vector has no direction to grow in.

The block ships switched off. enable defaults to false.

Signals

Inputs

Path Unit Range Description
input signal unit unbounded The vector’s components, one element per channel. All of them must share a unit. The channel count is fixed by the machine configuration.
disable - - True bypasses the limiter: every component passes straight through. Use it for a runtime override from a supervisor; use enable for the configured intent.

Outputs

Path Unit Description
output signal unit The vector, scaled down uniformly if it was too long and unchanged otherwise. Its direction always matches input. Equals input exactly while bypassed.
isLimiting - True while the vector is being scaled. A single value for the whole vector, not one per channel — the vector is limited as a whole.
isEnabled - True when enable is true and disable is false.

Parameters

Path Unit Default Range Effect
enable - false - False bypasses the limiter. Set this, or the block does nothing.
upperLimit signal unit 1 0 upward The maximum vector length, as a single number for the whole vector. 0 collapses the vector to zero. Not checked — a negative value points the output the opposite way.

Both are persistent and survive a controller restart. No parameters exist below this block.

Setup

  1. Confirm every element of input carries the same unit. If they do not, this block cannot limit them together — split them into separate instances.

  2. Set upperLimit to the largest vector length the consumer can accept — for a Cartesian velocity, the maximum tool speed.

  3. Leave enable false and confirm output matches input element for element.

  4. Set enable true. Command a vector well inside the limit and confirm output still matches input exactly and isLimiting reads false.

  5. Command a vector longer than the limit. Confirm isLimiting goes true, and check the ratios between the output components are unchanged from the input’s.

    Step 5 is the check that direction is preserved. If the ratios change, something else in the chain is clamping components individually — that is exactly the behaviour this block exists to replace.

  6. Confirm the output’s length equals upperLimit while limiting.

Tuning

There is nothing to tune beyond the one bound.

  1. Set upperLimit from the consumer, not from the signal. For a tool velocity it is the machine’s rated speed; for a force it is what the structure can take.
  2. Watch isLimiting during normal operation. Persistent limiting means something upstream is commanding more than the machine can deliver, and that is usually the real problem.
  3. If individual components also need bounds — a per-axis speed limit as well as a tool speed limit — add a Limiter after this one. Order matters: this block first keeps the direction, and the per-component clamp afterwards catches anything still out of range.
  4. Nothing here needs re-checking after a task-rate change.

Length of the output against length of the input at three limits: each linefollows the input until it reaches its limit and is flatbeyond.

Read each limit off the height at which its line goes flat.

Symptom Cause Action
Nothing is limited and isLimiting stays false enable defaults to false Set enable true
The output points the opposite way from the input upperLimit is negative Set it positive
The output collapses to zero whenever the input moves upperLimit is 0 Set a positive limit
The direction changes when the limit bites Not possible in this block — something downstream is clamping components individually Check what follows this block
The limit bites at a length that makes no sense The vector mixes units, so its computed length is not physical Use one instance per unit group
The output stepped when the block was enabled Expected: the block is memoryless and clamps at once Enable while the vector is inside the limit
One component is still too large Expected: this block bounds the whole vector’s length, not any one component Add a per-component limiter after it
isLimiting is a single value, not one per channel Expected: the vector is limited as a whole Use a per-component limiter if you need per-channel flags
Limiting is persistent during ordinary motion The limit is too low, or something upstream is over-commanding Check the command before raising the limit
A non-numeric component passed straight through Expected: the length comparison fails and the block copies through Fix the source; the block holds no state and recovers at once
You need a minimum length as well Not available — a zero-length vector has no direction to grow in Handle it upstream

A starting point for bounding a three-axis Cartesian velocity to 0.25 m/s:

enable     = true
upperLimit = 0.25

Limits and errors

Limit Set by What happens Reported
upperLimit non-negative Nothing Not checked. A negative value scales every component by a negative factor, so the output points the opposite way at the limit’s magnitude Not reported
upperLimit = 0 Fixed Any non-zero vector is collapsed to zero isLimiting reads true
output length upperLimit while enabled Bounded exactly. Unbounded while enable is false isLimiting, one flag for the vector
Individual components Nothing Not bounded. A long vector along one axis is scaled, but nothing caps any single component on its own Not reported
Unit consistency Nothing Not checked, and cannot be. A vector mixing units has a length with no physical meaning Not reported
Lower limit Not available There is none, by design: a zero-length vector has no direction to scale toward Not applicable
Enabling Fixed The block is memoryless, so a vector already too long is scaled on the first enabled cycle — a step Not reported
Non-numeric input Nothing Passes through unchanged. The block is stateless and recovers immediately Not reported
Channel count Machine configuration Fixed once the controller starts Not reported

The block raises no errors or warnings and logs nothing. Every failure above shows as a value on a trace, not as a message.


Verified against motorcortex-control3 3.30.0 (bc348fd).