SimpleActuatorControlLoop
SimpleActuatorControlLoop is the reduced control loop for a single axis.8 minute read
SimpleActuatorControlLoop is the reduced control loop for a single axis. It
converts sensor readings into engineering units, switches between tracking the
measurement and following a command, converts the result back into drive units,
and watches four quantities for faults.
Use it for an axis whose drive closes its own position loop and which needs no torque handling.
This loop does not limit anything. There is no position limiter and no velocity limiter — whatever you write to
inputPositiongoes to the drive, converted. Whatever feeds this block is entirely responsible for keeping the commanded motion within what the machine can take. The fullActuatorControlLoopdoes clamp its setpoints.
Compared with the full loop it also has no torque path, no feedback
controllers, no feedforward, no impedance mode and no jogging. If you need
any of those, use ActuatorControlLoop.
flowchart LR
i1(["inputPosition, inputVelocity, inputAcceleration"]) --> B["SimpleActuatorControlLoop"]
i2(["motorPositionActual, motorVelocityActual"]) --> B
i3(["gotoEngaged, doInstantSwitchToggle"]) --> B
i4(["driveMode, disable"]) --> B
B --> o1(["motorPositionTarget, motorVelocityTarget"])
B --> o2(["actuatorPositionTarget, actuatorVelocityTarget, actuatorAccelerationTarget"])
B --> o3(["actuatorPositionActual, actuatorVelocityActual"])
B --> o4(["actuatorPositionError, actuatorVelocityError"])
B --> o5(["…ActualFiltered outputs, gearboxGain, isEnabled"])
B --> s1(["positionTransformation, velocityTransformation"])
B --> s2(["engagedSwitch, actualVelocityFilter, motorBacklashCompensation"])
B --> s3(["four window detectors"])
gotoEngageddecides whether the axis follows you or follows itself. While false, the target tracks the measured position so nothing jumps when the drive powers on. While true, it followsinputPosition. The transition is faded.
During that fade,
actuatorVelocityTargetandactuatorAccelerationTargetdo not matchactuatorPositionTarget. They are correct before and after, and wrong in between, by an amount that grows with the gap between where the axis is and where you are commanding it. Match them before engaging.
Signals
Inputs
| Path | Unit | Range | Description |
|---|---|---|---|
inputPosition |
actuator unit | unbounded | The commanded position. Followed only while engaged. Not limited by this block. |
inputVelocity |
actuator unit per second | unbounded | The commanded velocity. |
inputAcceleration |
actuator unit per second² | unbounded | The commanded acceleration. |
motorPositionActual |
ticks | unbounded | From the drive. |
motorVelocityActual |
ticks per second | unbounded | From the drive. |
gotoEngaged |
- | true or false | Follow the input, or track the measured position. |
doInstantSwitchToggle |
- | true or false | Make that transition a step instead of a fade. |
driveMode |
- | drive enumeration | Which mode the drive is in. Recorded, but this loop has no torque routing to gate on it. |
disable |
- | true or false | Disables the loop. |
Outputs
| Path | Unit | Description |
|---|---|---|
motorPositionTarget |
ticks | To the drive. |
motorVelocityTarget |
ticks per second | To the drive. |
actuatorPositionTarget |
actuator unit | What the loop decided, before conversion. Trace this first. |
actuatorVelocityTarget |
actuator unit per second | Wrong during an engage fade — see the callout above. |
actuatorAccelerationTarget |
actuator unit per second² | Same. |
actuatorPositionActual |
actuator unit | Where the axis is. |
actuatorVelocityActual |
actuator unit per second | From the drive, or derived from the position — see usePositionActualFilteredForVelocity. |
actuatorPositionError |
actuator unit | Target minus actual. The main health signal. Its exact definition depends on useAngleDiffForPositionError. |
actuatorVelocityError |
actuator unit per second | |
actuatorPositionActualFiltered |
actuator unit | The filtered measurements. These are what the loop tracks while idle, and what three of the four detectors watch. |
actuatorVelocityActualFiltered |
actuator unit per second | |
actuatorAccelerationActualFiltered |
actuator unit per second² | |
gearboxGain |
- | gearboxLoadSide ÷ gearboxMotorSide. Read it back to check the ratio. |
isEnabled |
- | The loop is running. |
Parameters
| Path | Unit | Default | Range | Effect |
|---|---|---|---|---|
enable |
- | — | - | Enables the loop. |
gearboxLoadSide |
teeth | — | non-zero | Load-side tooth count. Not checked for zero. |
gearboxMotorSide |
teeth | — | non-zero | Motor-side tooth count. Not checked for zero. |
windowDetectorsEnable |
- | — | - | Turns all four fault detectors on. Leave this on in service. |
usePositionActualFilteredForVelocity |
- | — | - | Derive the velocity from the position instead of taking the drive’s own velocity. Useful when the drive’s velocity is noisy or absent. |
useAngleDiffForPositionError |
- | — | - | For a rotary axis: compute the position error by the shortest angular path, so an axis near the wrap-around point does not report a full-turn error. It also switches the error to use the filtered position, which changes its noise and lag. |
usePvaActualForCompensation |
- | — | - | Has no effect in this loop. It selects a feedforward input, and this loop has no feedforward. |
Everything else is in the sub-trees — the two transformations, the engage switch, the velocity filter, the backlash compensation, and the four window detectors. All parameters are persistent and survive a controller restart.
Setup
-
Configure the transformations first, under
positionTransformationandvelocityTransformation. Nothing else can be checked until the axis reports its position correctly. -
Set
gearboxLoadSideandgearboxMotorSide, and readgearboxGainback. -
With the drive disabled, move the axis by hand and confirm
actuatorPositionActualreads correctly over a long move. -
Confirm whatever feeds
inputPositionhas its own limits. This block has none. -
Set the four window detectors' levels from a trace of normal operation, and set
windowDetectorsEnabletrue. -
For a rotary axis that wraps, set
useAngleDiffForPositionErrortrue. -
Leave
gotoEngagedfalse and enable the drive. ConfirmactuatorPositionTargettracksactuatorPositionActualand the axis does not move. -
Feed
inputPositionthe axis’s current measured position, then setgotoEngagedtrue.Step 8 hands the axis to your setpoint source, with nothing between them but a unit conversion. If
inputPositiondoes not match where the axis is, the loop will move it there over the fade, at whatever rate the fade implies. -
Move slowly and watch
actuatorPositionError.
Tuning
- There are no gains here — the drive closes the loop. The tuning is in the measurement chain and the fault levels.
- Set the measurement filtering under
positionTransformation/actualLP1Filterfrom the noise you see. Lower cut-off is smoother and laggier. - Choose the velocity source. If the drive reports velocity cleanly, use it;
if not, set
usePositionActualFilteredForVelocityand take the derivative of the filtered position instead. - Set the engage fade time under
engagedSwitch/fadeInTimefrom how abruptly you are willing to take control. Longer is gentler, and longer also means the velocity and acceleration targets are wrong for longer. - Set the backlash compensation only if the drivetrain has measurable backlash, and only after the position reads correctly.
- Set the four detector levels from the error you actually see, with margin.
- Watch
actuatorPositionErrorthrough a full working cycle before declaring the axis commissioned.
The step is what you get with doInstantSwitchToggle true. Use it only when
the two values already match.
| Symptom | Cause | Action |
|---|---|---|
| The axis jumped when engaging | inputPosition did not match the measured position, and nothing limits the difference |
Match them before engaging |
| The axis stepped rather than faded | doInstantSwitchToggle is true |
Set it false |
| The axis moved further or faster than intended | This block has no limiters | Limit the source that feeds inputPosition |
| Nothing moves when engaged | enable is false or disable is true |
Check isEnabled |
| The velocity target looks wrong during engaging | Expected in this version: it does not match the position target during the fade | Match the values before engaging, or shorten the fade |
| A rotary axis reports a full-turn error | The position error is not using the shortest angular path | Set useAngleDiffForPositionError |
| The position error got smoother when I set that flag | Expected: it also switches to the filtered position | Nothing, but be aware the signal changed |
| The velocity is noisy | The drive’s velocity is noisy | Set usePositionActualFilteredForVelocity and tune the filter |
| A fault will not clear | The window detectors latch. The reset is not on this block | Assert resetErrors on the parent’s state input — it clears every axis at once |
usePvaActualForCompensation does nothing |
Expected: there is no feedforward in this loop | Use the full loop if you need feedforward |
| Everything is scaled wrongly | The gearbox ratio, or the transformations | Read gearboxGain back; check the transformations first |
| The loop misbehaves after writing a gearbox value | A zero tooth count is not refused | Read both back |
| I need torque control, feedforward, or jogging | Not in this loop | Use ActuatorControlLoop |
| I need the setpoints limited here | Not in this loop | Use ActuatorControlLoop, or limit upstream |
A starting point once the transformations are correct:
gearboxLoadSide = <from the drivetrain>
gearboxMotorSide = <from the drivetrain>
windowDetectorsEnable = true
usePositionActualFilteredForVelocity = false
useAngleDiffForPositionError = false (true for a rotary axis)
Limits and errors
| Limit | Set by | What happens | Reported |
|---|---|---|---|
| Setpoint limiting | None | Nothing in this block clamps position, velocity or acceleration. The commanded value reaches the drive converted | Not reported |
| Fault detection | The four window detector sub-trees | Latching warning and error flags on the position error, position, velocity and acceleration | Each detector’s noError |
| Fault reset | The parent’s state input | This block has no reset path of its own. Inside AxesControl the reset arrives through its state channel and clears every actuator at once |
Not reported |
| Engage transition | The engage switch sub-tree | Faded, unless doInstantSwitchToggle. The velocity and acceleration targets do not match the position target during the fade |
Not reported |
| Position error definition | useAngleDiffForPositionError |
Plain subtraction, or the shortest angular path — and the second also switches to the filtered measurement | Not reported |
| Gearbox ratio | Nothing | A zero tooth count is not refused and makes the conversion invalid | gearboxGain |
| Values that are not numbers | Nothing | Not checked anywhere in this block | Not reported |
usePvaActualForCompensation |
Fixed | Inert. There is no feedforward here for it to select | Not reported |
driveMode |
Fixed | Recorded but not acted on — there is no torque path to route | Not reported |
| Feature set | Fixed | No torque, no controllers, no feedforward, no impedance, no jogging, no limiters | Not applicable |
| Axis count | Fixed | One axis per instance, always | Not reported |
This block logs nothing itself. The transducers below it log during referencing. Every other condition above shows as a value on a trace, or not at all.
Verified against motorcortex-control3 3.30.0 (bc348fd).