Torque-Current Control
Tuning with TorqueCurrentFOC requests (Phoenix Pro), and what torque control does and doesn't change.
Torque-current requests command the torque-producing stator current () directly, using Field Oriented Control. They need Phoenix Pro on the Kraken X60 or X44.
About the name. This section and §4 say "FOC" to mean torque-current control, as most teams do. Strictly, FOC is a way of commutating the motor, and Phoenix Pro also uses it for voltage and duty-cycle requests when EnableFOC = true (see §1.6). What sets this section apart is the output family: Amps instead of Volts.
3.0.1 Why Torque Control is Different
In voltage mode, the torque you get for a given voltage depends on speed, because back-EMF subtracts from it:
So the same kP produces less force at high speed than at low speed. (Battery sag is not the issue: voltage requests already compensate for it.) Torque-current mode commands the current directly:
A fast inner current loop in the firmware produces the requested current, so from the tuner's point of view you are commanding motor torque directly, and it no longer depends on speed.
It cannot create voltage the battery doesn't have. To push a current, the drive still has to overcome back-EMF: the most current it can get is . Near top speed, torque mode runs out of authority exactly like voltage mode. What changes is how error becomes output, not how much output is available.
3.0.2 Tuning Implications
With Amps as the output, every gain changes units. A rough conversion for kP:
A voltage-mode kP of 30 V/rotation on a Kraken X60 (FOC, Ω from §1.6.2) becomes about A/rotation. Treat this as a ballpark only. Modest errors will already hit the current limit, and once the output is clipped the loop stops behaving linearly. Tune from a lower starting point (see the procedures below).
3.0.3 Feedforward in Torque Mode
Which feedforwards act depends on the request, not only the mechanism. A term only contributes when the request supplies the reference it multiplies:
| Term | Active in VelocityTorqueCurrentFOC | Active in PositionTorqueCurrentFOC (no velocity arg) | Active in MotionMagic*TorqueCurrentFOC |
|---|---|---|---|
| kS | Yes | Yes (via StaticFeedforwardSign config — see §1.2.1) | Yes |
| kV | Yes — represents drag | No (no ) | Yes |
| kA | Yes (if profiled or with explicit acceleration) | No (no ) | Yes |
| kG | Always applied (set kG = 0 for a flywheel) | Yes | Yes |
(Rows marked "No" become "Yes" if you pass a Velocity or Acceleration to the request yourself.)
In particular, kA does nothing without a profile. On plain PositionTorqueCurrentFOC there is no commanded acceleration to multiply, so don't spend time on kA until you switch to Motion Magic.
What each term means in torque mode:
- kS (Amps): current to overcome stiction. Found by slowly raising current until the mechanism moves.
- kV on a flywheel: current to overcome drag and windage. It matters here: CTRE's flywheel example ends at kV ≈ 0.15 A/rps.
- kV on a position mechanism (turret, arm, elevator): 0 without a profile, small with one (gear-train drag).
- kA (Amps per mechanism rotation/s²): inertia. Two conversions are easy to miss: the rotor accelerates times faster than the mechanism, and a converts rotations to radians. With the slot in mechanism units (via
SensorToMechanismRatio):
where is the mechanism inertia reflected to the rotor. Check that whatever you compute comes out in A/(rotation/s²).
- kG (Amps): current to hold against gravity. for an arm at horizontal, and for an elevator with drum radius .
All torque-current requests use the same slot fields as voltage mode. The values are simply read as Amps.
Torque mode has no built-in damping
In voltage mode, back-EMF opposes motion in proportion to speed. It acts as free damping, which is why a voltage-mode position loop often works with kP alone.
Torque mode removes that damping. The current loop delivers the commanded torque whatever the speed, so nothing resists motion except friction. As a result:
- kD is effectively required for torque-mode position control, even on mechanisms that were stable with kP alone in voltage mode.
- Tune kP and kD together, stepping each in turn, rather than finishing kP and then adding kD.
- Expect a much larger kD/kP ratio: roughly 1/30 to 1/10, versus about 1/100 in voltage mode. CTRE's examples: 60/1650 ≈ 1/28 (turret), 300/3700 ≈ 1/12 (arm), 2000/16000 = 1/8 (profiled high-inertia mechanism).
See the difference. The sandbox simulates a 20:1 turret. Compare the voltage and torque presets with kP only, then add kD. Raising kD far past CTRE's value makes the loop chatter, which is the latency limit described in the turret procedure (§3.2.3).
Start with Voltage, kP only: back-EMF damps the move, so it settles without kD. Switch to Torque, kP only and the same kind of tune rings, because torque mode has no back-EMF damping. CTRE's gains add kD and settle cleanly. Push kD much higher and the loop starts to chatter: that is the latency limit from step 6 of the turret procedure.
A 20:1 turret on a Kraken X60 (FOC), 0.05 kg·m², with friction equal to kS = 1.25 A. Runs the loop at 1 kHz with an ideal current loop, a 12 V supply, and the chosen output delay. The current limit and the plotted current are stator (motor winding) current, set by StatorCurrentLimit. In torque mode PeakForwardTorqueCurrent caps it the same way. Supply (battery) current is not shown. Real mechanisms add backlash, compliance, and sensor noise, so use the results as intuition, not as gains to copy.
3.0.4 SysId and Torque-Current: What Actually Transfers
The model is not the obstacle. SysId fits a first-order linear system of the form
In torque-current mode, the mechanism behaves as
which has the same form, with in Amps instead of Volts. So the fitting math still works: drive the SysId routine with a torque-current request (the routine's "volts" are then really Amps) and the resulting kS/kV/kA/kG come out in Amps.
What gets awkward:
- kV is near zero and poorly determined. In voltage mode, kV is mostly back-EMF and is the largest, best-measured term in the fit. In torque mode the current loop has already removed back-EMF, leaving only mechanical drag. On a low-friction position mechanism that is close to the noise floor, and the fit may return a small negative or erratic value. Treat a torque-mode kV from SysId as zero unless it's a flywheel.
- kA absorbs the error. Because kV is poorly determined, fitting error tends to end up in kA. Compare SysId's kA with the physics value from §3.0.3 before using it.
- The tools say Volts. SysId labels its inputs and gains in volts no matter what you logged. Remember that the numbers are Amps.
This is why CTRE recommends tuning torque-current mechanisms by hand (their Manually Tune your PID Loops guide), which is often faster than a SysId run for a single mechanism. Each torque-mode section below gives:
- A physics calculation for kG (and kA for high-inertia mechanisms) from motor constants and mechanism geometry.
- A way to measure kS with a slow current ramp.
- A way to set kP and kD by watching the response.
The approaches combine well: compute kG and kA from physics, measure kS, and use SysId, if at all, as a check on kA. In torque mode the physics maps cleanly onto known quantities (, mass, gear ratio, geometry), so the hand calculation is usually the more trustworthy of the two.
3.0.5 Profiled Tuning (Motion Magic with TorqueCurrentFOC)
With a torque-current Motion Magic request (MotionMagicTorqueCurrentFOC, MotionMagicExpoTorqueCurrentFOC, MotionMagicVelocityTorqueCurrentFOC), the profile supplies and every loop, so kV and kA do real work:
When this is tuned well, feedforward does most of the work: kS handles stiction, kG gravity, kA the profile's acceleration, and kV drag at speed. PID only corrects modeling error and disturbances. From CTRE's guide:
"the introduction of a profile means much of the response can be calculated in advance with feed-forwards. This results in much of the work being done due to feed forward, with the feedback gains being used to account for any error in the system."
Recommended order for tuning a profiled torque-current controller
Order matters: tuned out of order, terms hide each other's errors.
-
Zero all gains (kP, kI, kD, kS, kV, kA). If gravity acts on the mechanism, first find kG and kS with the bracketing method (§3.3.3 for arms, §3.4.4 for elevators).
-
Tune kS by raising current slowly until the mechanism moves (skip if bracketing already gave you kS). Same as without a profile.
-
Tune kA on the acceleration phase. Run a profiled move and compare the measured velocity slope at the start with the profile's. Raise kA until they match. If you can plot acceleration (Tuner X, AdvantageScope), match measured to commanded acceleration directly.
- kA does most of the work in profiled torque mode. Start from the physics value (§3.0.3). The tuned value usually lands within ~30% of it.
- CTRE's profiled example ends at kA = 65 A/(rotation/s²) for a 1:1 high-inertia mechanism.
-
Tune kV on the cruise phase. Once acceleration matches, look at constant-velocity cruise. Raise kV until measured velocity stays on the profile throughout, without slowly falling behind or pulling ahead.
- Many position mechanisms have almost no drag and can keep kV = 0. Only add kV if you see drift during cruise.
- CTRE's example ends at kV = 0.15 A/(rotation/s). That is drag, not back-EMF, which the current loop has already removed.
-
Tune kP and kD together, as without a profile: raise kP until it overshoots, raise kD until the overshoot stops, and repeat until you reach the limit (§3.2.3). Because good feedforward keeps the tracking error small, the loop tolerates much higher kP and kD than it would without a profile. Gains that would be unstable on a large step are fine when the error never gets large.
Worked example from CTRE. A 1:1 high-inertia profiled mechanism ended at kS = 1.25 A, kV = 0.15 A/(rotation/s), kA = 65 A/(rotation/s²), kP = 16000 A/rotation, kD = 2000 A/(rotation/s). Those very high kP and kD values only work because kA is doing most of the work. Without it, the tracking error would grow and the same gains would be unstable.
3.1 Flywheel (Velocity)
Torque-current works very well for flywheels:
- The loop behaves the same at every speed. The current loop cancels back-EMF, so a given error produces the same corrective torque at 20 rps as at 80 rps (given enough voltage headroom, see §3.1.4).
- Recovery is sharper. The controller commands torque directly instead of working through the voltage/back-EMF relationship.
- The recovery current is bounded.
PeakForwardTorqueCurrentand the stator limit cap how hard it pulls when a game piece slows the wheel. (To protect the battery from brownouts you still need the supply current limit.)
3.1.1 Control Output Equation
For VelocityTorqueCurrentFOC:
The output is in Amps. The inner current loop then produces that current in the motor.
3.1.2 Parameter Effects
| Gain | Effect on Output (Torque Mode) |
|---|---|
| kS | Current to overcome stiction. Typically 1–4 A for FRC flywheels. |
| kV | Current per rps to overcome drag. Small but not zero, since air drag grows with speed. |
| kA | Current per rps² of acceleration: in mechanism units (§3.0.3). Supplies spin-up current ahead of time. |
| kP | Disturbance rejection, and very effective here. Values are numerically larger than in voltage mode (it takes many Amps to match one Volt), and you can usually push it further before oscillation. |
| kI | Steady-state error correction. Often 0. |
3.1.3 Tuning Procedure
CTRE's method (from their Manually Tune your PID Loops guide) alternates between a low and a high setpoint. kS dominates at low speed, where kV·v is small, and kV dominates at high speed, so tuning each where it dominates and alternating separates them cleanly. A small kP (not zero) during this makes it easy to see whether the flywheel reaches the setpoint, without hiding feedforward errors.
-
Set current limits.
TorqueCurrentConfigs.PeakForwardTorqueCurrent/PeakReverseTorqueCurrent: the most current a torque request can ask for. The default is 800 A, so always lower it (e.g., ±80 A for one Kraken on a flywheel).StatorCurrentLimit(default 120 A, on): applies on top of the peak torque current.- Supply limits, to protect the battery: e.g.,
SupplyCurrentLimit = 80A, dropping toSupplyCurrentLowerLimit = 60A afterSupplyCurrentLowerTime = 1s.
-
Zero all gains (kP, kI, kD, kS, kV, kA).
-
Tune kS at a low setpoint, about 1/10 of top speed (e.g., 10 rps on a 100 rps flywheel). Raise kS until the flywheel spins up to the setpoint without overshooting. Doubling is quick (1, 2, 4, 8 A). Narrow down once you've bracketed it.
-
Set a small kP:
kP = 1 * RotorToSensorRatio * SensorToMechanismRatio, which is 1 A per rotor rps of error in mechanism units. A 1:1 flywheel gets kP = 1, and a 20:1 mechanism gets kP = 20. It is deliberately small, just enough to show undershoot clearly while you tune kV. -
Tune kV at a high setpoint, about 8/10 of top speed (e.g., 80 rps). Raise kV until the flywheel reaches it. If it overshoots badly, halve kV. If it undershoots, raise it. Narrow down from there.
-
Alternate. Back at the low setpoint it will probably overshoot now, because of the added kV. Lower kS until it lands cleanly, then return to the high setpoint and adjust kV. Stop when neither changes over two consecutive rounds, usually 2–3 rounds.
-
Raise kP for disturbance rejection. Keep doubling it (1, 2, 4, 8, 16…) while watching time-to-setpoint and overshoot. When it oscillates or overshoots too much, go back to the last good value. CTRE's example ends at kP = 16 A/rps. Yours depends on inertia and current limit.
-
Test with real game pieces (or another realistic disturbance) and watch the closed-loop error. Recovery too slow → room for more kP. Oscillation → back off. If normal shots hit the current limit, kP is asking for more than the limit allows, so back off.
-
kA only matters with a profiled velocity request (
MotionMagicVelocityTorqueCurrentFOC). If you use one to control spin-up, start from (§3.0.3) and refine on the robot.
Worked example from CTRE. A 1:1 flywheel with a 100 rps top speed ended at kS = 2.6 A, kV = 0.15 A/rps, kP = 16 A/rps. The kV here is air drag, not back-EMF, which the current loop has already removed.
3.1.4 Torque vs. Voltage for Flywheels
It's tempting to say torque mode has "full current available at any speed". It doesn't. Both modes hit the same physical ceiling:
At 80 rps on a Kraken X60 (FOC), back-EMF is V. That leaves about 2 V, or roughly 2 / 0.0248 ≈ 80 A, for either mode. Closer to free speed, both run out.
Move the operating speed in the chart to see how quickly the ceiling drops as a shooter approaches free speed. It starts at 80 rps (4800 RPM) with an 80 A stator current limit.
At 4800 RPM, back-EMF uses 9.93 V of the 12.0 V supply, so at most 80 A of stator current is available for torque. This ceiling is the same in voltage and torque-current mode. Torque mode changes how the loop uses the current, not how much there is.
Which limit is this? The slider is the stator current limit (StatorCurrentLimit, default 120 A), which caps current in the motor windings and so caps torque. In torque-current mode, PeakForwardTorqueCurrent / PeakReverseTorqueCurrent cap it the same way. The supply limit (SupplyCurrentLimit) caps battery current instead. At low speed the motor needs only a fraction of the supply voltage, so supply current is much lower than stator current. That is why the supply limit protects the battery but does little to limit torque at low speed.
Uses the effective constants from the Motor Constants page. Ignores free current, friction, and temperature. The effective resistance rises about 25% when the motor is hot, which lowers every current in this chart.
What torque mode actually improves:
- Error-to-torque stays constant. In voltage mode, the correction voltage has to fight back-EMF before it becomes current, so the same kP behaves differently at different speeds. In torque mode, a given error always commands the same current.
- Recovery is sharper. In voltage mode, back-EMF acts as damping that softens every correction. Torque mode has none (§3.0.3), so the same error gets a stronger response.
- Peak current is set explicitly with
PeakForwardTorqueCurrent, instead of depending on kP and the size of the error.
On a high-speed shooter this usually shows up as noticeably faster, more consistent recovery between shots, as long as the setpoint leaves some voltage headroom.
3.2 Turret (Position)
Turrets gain from torque control mainly in smoothness: smoother slow motion and better small corrections, because the current loop removes the speed dependence that back-EMF adds. (It does nothing about friction, which kS still has to handle.)
3.2.1 Control Output Equation
For PositionTorqueCurrentFOC:
with set by StaticFeedforwardSign (§1.2.1). Use UseClosedLoopSign here so kS acts on small corrections. With the default, and kS does nothing.
For MotionMagicExpoTorqueCurrentFOC:
3.2.2 Parameter Effects
| Gain | Effect (Torque Mode) |
|---|---|
| kS | Current to overcome static friction. Direct-drive and low-ratio turrets need more than highly geared ones. |
| kV | Current per rps, from gear-train drag only. Often ~0.5 A/rps or less. |
| kA | Current per rps², proportional to inertia. Significant on heavy turrets. |
| kP | Position correction. |
| kD | Damping. |
3.2.3 Tuning Procedure
CTRE's method for plain position control in torque mode (from Manually Tune your PID Loops): tune kS to overcome friction, then raise kP and kD together until you reach the system's limit. kV and kA do nothing here, because there is no commanded velocity or acceleration to multiply.
-
Set soft limits, current limits, and the sensor. Lower
PeakForwardTorqueCurrent/PeakReverseTorqueCurrentfrom the 800 A default and setStatorCurrentLimit. For a turret, 40–60 A is typical. -
Set
StaticFeedforwardSign:UseClosedLoopSignfor plainPositionTorqueCurrentFOC, the default for Motion Magic. -
Zero all gains.
-
Command a small move, e.g., 0.1 mechanism rotations. That is 36° of turret travel whatever the gear ratio (2 rotor rotations on a 20:1 turret).
-
Tune kS. Raise kS until the turret just starts to move toward the setpoint, then back off until it just doesn't. That largest non-moving value is kS.
-
Raise kP and kD together. With no back-EMF damping, kP alone always overshoots or oscillates, so they have to be tuned as a pair. You can try this on a simulated turret in the tuning sandbox:
- Raise kP until it clearly overshoots. Big jumps (1, 10, 50, 100, 200…) find the range fast. Then narrow down.
- Raise kD until the overshoot stops (1, 10, 20, 40…).
- Repeat, kP then kD, until either (a) more kD makes oscillation worse, or (b) the turret oscillates on its way to the setpoint, not just at it.
- Either sign means you've reached the system's latency limit. Lower kD until the on-the-way oscillation stops, then lower kP until any overshoot is gone.
-
Test several move sizes: small, medium, and large. Gains tuned on small moves often overshoot on large ones, because large errors saturate the current limit and the move becomes a step response. Lower kP until large moves behave, accepting slightly slower small moves.
-
Optional: gain scheduling. If small and large moves both matter and one set of gains can't serve both, set
ClosedLoopGeneralConfigs.GainSchedErrorThresholdand the slot'sGainSchedBehavior. The firmware then switches gains automatically when falls inside the threshold. CTRE's example 20:1 turret ended at kS = 1.25 A, kP = 1650 A/rotation, kD = 60 A/(rotation/s), after walking kP back down (2200 → 2000 → 1800 → 1650) once larger moves started overshooting. -
For Motion Magic Expo, follow §3.0.5: kS first, then kA on the acceleration, kV on the cruise, then kP and kD as above.
A safe first kP: A per mechanism rotation, i.e., 1 A per rotor rotation of error. On a 20:1 turret that is 20 A/rotation. The tuned value will be far higher (CTRE's turret ended at 1650), but this gives a safe non-zero starting point.
3.3 Arm (Position)
kG is especially easy to calculate in torque mode: gravity torque converts straight to motor torque, and motor torque straight to current. That's one fewer step than in voltage mode, and it doesn't depend on .
3.3.1 Control Output Equation
For PositionTorqueCurrentFOC with GravityType = Arm_Cosine:
with set by StaticFeedforwardSign (§1.2.1). Use UseClosedLoopSign without a profile: kG supplies the holding current, and kS only needs to act on small corrections, in whichever direction the error points.
For MotionMagicExpoTorqueCurrentFOC:
3.3.2 First-Principles kG in Torque Mode
The current required to hold an arm at horizontal is:
Example: 5 kg arm with CG at 0.4 m from pivot, gear ratio 100:1, Kraken X60 in FOC mode ( N·m/A from §1.6.2):
So kG ≈ 10 A. The same arm on a Kraken X44 (FOC, ) needs ~12.9 A. The whole calculation uses only the mechanism's geometry and one number from the motor table.
3.3.3 Tuning Procedure
CTRE uses a bracketing method that finds kG and kS in one pass. At horizontal, where gravity torque is largest, friction first helps hold the arm up and then resists pushing it up, so the two thresholds straddle kG by ±kS:
-
Set the zero (horizontal = 0), as in voltage mode.
-
Set
StaticFeedforwardSign:UseClosedLoopSignfor plainPositionTorqueCurrentFOC, the default for Motion Magic. -
Zero all gains: kP, kI, kD, kS, kV, kA.
-
Find the lower bound (
kG_low). Hold the arm at horizontal and raise kG to the smallest value at which the arm doesn't fall when you let go. This is , because friction is helping.- Doubling finds it fast (1, 2, 4, 8, 16 A). Then narrow down.
-
Find the upper bound (
kG_high). Keep raising kG to the largest value at which the arm still doesn't start moving up. This is . -
Compute kG and kS:
Splitting the bracket this way is more accurate than measuring kG and kS separately. Compare kG with the physics value from §3.3.2. They should agree within 10–15%.
-
Command a small move, typically 0.1 mechanism rotations from where the arm is.
-
Raise kP and kD together as for the turret (§3.2.3, step 6), until more kD makes things worse or the arm oscillates on its way to the setpoint. Then back off kD, then kP.
-
Test several moves across the range. A move from near vertical toward horizontal takes gravity torque from almost nothing to its maximum, which can expose a kP that works on small moves but overshoots on long ones. CTRE's example arm did exactly this: kP had to come back from 4000 to 3700.
-
For Motion Magic, follow §3.0.5. kA and kV only matter once there is a profile.
Worked example from CTRE. A 35:1 arm ended at kG = 21 A and kS = 3.5 A (brackets at 17.5 A and 24.5 A), kP = 3700 A/rotation, kD = 300 A/(rotation/s).
Practice the bracketing test. The simulated arm below has hidden kG and kS. Find the smallest kG that holds it and the largest that doesn't lift it, record both, then reveal the true values to check your answer.
You are holding the arm at horizontal.
A 35:1 arm on a Kraken X60 (FOC), started at horizontal each time. Motor output follows kG·cos(θ), as with GravityType = Arm_Cosine. Friction is modeled as a static threshold (kS) with slightly lower sliding friction. The first arm uses CTRE's worked example.
3.3.4 Compound Arms (Multi-Joint)
On a two-joint arm (shoulder plus elbow), gravity torque on the shoulder depends on the elbow angle too:
where is the length of the first link (shoulder to elbow), and are the distances from each joint to its link's center of gravity, and is measured relative to the first link. Add the elbow motor and any payload as point masses if they are significant.
Arm_Cosine only handles a single cosine. For two joints, compute the gravity current in code, pass it through the request's FeedForward argument (Amps in torque mode), and set slot kG to 0:
private final MotionMagicExpoTorqueCurrentFOC control = new MotionMagicExpoTorqueCurrentFOC(0);
...
double gravityFF = computeShoulderGravityCurrent(shoulderAngle, elbowAngle);
shoulderMotor.setControl(control.withPosition(targetAngle).withFeedForward(gravityFF));This is where torque mode really shines: gravity torque from physics becomes a current command with one division by .
3.4 Elevator (Position)
Elevators are easy in torque mode: the dynamics are linear and gravity is a constant.
3.4.1 Control Output Equation
For MotionMagicExpoTorqueCurrentFOC with GravityType = Elevator_Static:
3.4.2 First-Principles Gains
For an elevator with output mass , drum radius , and gear ratio :
Use the kA form that matches your units. kG is a plain current, the same whatever your units. kA is not: it depends on what SensorToMechanismRatio makes one "mechanism unit". Meters of carriage travel → left form. Drum rotations → right form. The two differ by , the travel per drum turn, which is a handy check.
Start tuning from these values and confirm them with the measurements below.
The calculator does the arithmetic for both kA forms. Switch it to Arm for the calculation in §3.3.2.
| Gain | Voltage mode | Torque-current mode |
|---|---|---|
| kG | 0.201 V | 8.09 A |
| kA per m/s² of carriage | 0.0205 V | 0.825 A |
| kA per drum rot/s² | 0.00257 V | 0.104 A |
kG = m·g·r / (G·kt) in Amps, the same at every height. Pick the kA row that matches your SensorToMechanismRatio units. The two differ by 2πr, the travel per drum turn.
Starting estimates only. Ignores friction, cables, and the motor's own rotor inertia. Measured voltage-mode values usually come out higher, because a warm motor and the wiring add resistance. Cross-check against SysId or the bracketing test.
3.4.3 Why Torque Mode Suits Elevators
- Predictable acceleration. : a given current gives a known acceleration at any speed, within the voltage headroom of §3.0.1.
- Current is bounded explicitly.
PeakForwardTorqueCurrent/PeakReverseTorqueCurrentcap the output directly, so you can size them for the hardest acceleration and know they won't be exceeded. (Voltage mode relies on the stator and supply limits for the same job.) - The same force up and down. Current-to-force is identical in both directions. In voltage mode, back-EMF eats into headroom on fast up-moves while gravity helps on down-moves, so the loop feels different each way. Torque mode removes that difference (again within the voltage headroom). The friction difference of §2.4.6 is mechanical and stays.
3.4.4 Tuning Procedure
- Set soft limits, current limits, and homing, as for the voltage-mode elevator. Not optional.
- Set
StaticFeedforwardSign:UseClosedLoopSignfor plainPositionTorqueCurrentFOC, the default for Motion Magic. - Zero all gains.
- Find kG and kS by bracketing, as for the arm (§3.3.3):
- Raise kG to the smallest value at which the elevator stops sliding down: that is .
- Keep raising it to the largest value at which it still doesn't start rising: that is .
- kG is the midpoint and kS is half the difference. Compare kG with the physics value from §3.4.2. They should agree within 10–15%.
- Command a small move, e.g., 0.1 mechanism units from where it is.
- Raise kP and kD together as in §3.2.3. Elevators are rigid and tolerate aggressive kP. Expect a higher kP than on a similar-sized arm.
- Test several moves, including full-travel moves up and down. Friction that differs by direction often shows up here as different overshoot each way. If it's significant, use one slot for up-moves and another for down-moves.
- For Motion Magic, follow §3.0.5 to add kA and kV, starting kA from the physics value in §3.4.2.
3.5 Linear Deployment (Position)
Most short deployments don't need torque mode. Voltage mode is simpler to set up, and moves this short are mostly acceleration and deceleration anyway. The exception is any deployment that needs force control rather than position control.
3.5.1 Force-Limited Deployment
A typical case is a climber hook that extends until it touches the chain or bar and then pulls with a controlled force. With torque-current control:
- Drive to position with
PositionTorqueCurrentFOC(or Motion Magic) and a tight current limit. - Once there, switch to
TorqueCurrentFOC(open-loop torque) with the holding current you want.
TorqueCurrentFOC simply outputs the commanded current:
No PID, no feedforward: just "produce this much torque." That is exactly what "pull with this much force" needs. A 30 A hold gives a known motor torque, and so a known force on the hook, wherever the mechanism is.
3.5.2 Hybrid Position+Force Control
private final TorqueCurrentFOC holdRequest = new TorqueCurrentFOC(0);
private final MotionMagicExpoTorqueCurrentFOC moveRequest = new MotionMagicExpoTorqueCurrentFOC(0);
...
if (deploymentExtended && readyToApplyForce) {
motor.setControl(holdRequest.withOutput(holdingAmps));
} else {
motor.setControl(moveRequest.withPosition(targetPosition));
}(Create control requests once and update them each loop, rather than allocating new ones.)
The state machine follows a position while extending and applies a set force while holding. Voltage mode can't do this cleanly. At a stall, current is , and changes by around 25% as the motor warms up (§1.6.4), so a fixed voltage doesn't give a fixed force.
3.5.3 Tuning Procedure
Position phase: use the normal torque-mode workflow. Calculate kG and kA from physics, measure kS, and tune kP and kD by watching the response (§3.4.4 if gravity acts on it, §3.2.3 if it slides horizontally).
Force phase: nothing to tune, since current maps directly to force. You only need to:
- Convert the force you want to current: , with the drum radius (or moment arm).
- Keep long holds within what the motor can sustain thermally. Check the motor's published thermal data, and watch motor temperature during long holds.
- Set
StatorCurrentLimitandPeakForwardTorqueCurrent/PeakReverseTorqueCurrenta little above the hold current as a safety cap.