Tripping at a 0.350 Nm limit and running clean at 0.104 Nm comes down to one division: the mechanical-power threshold divided by commanded torque. The detector fires when filtered mechanical power falls below its negative threshold while filtered electrical power stays above its positive threshold, so a fixed −10 W limit is a 4.5 rev/s reverse-velocity window at 0.350 Nm and a 15 rev/s window at 0.104 Nm. Grass hands the rotor those reverse excursions every time a tire loads against a clump and unloads. Ramp the velocity command and widen the thresholds — the magnet is not slipping.
Symptom Split: Which Limit Trips and Which Stalls
Two operating points, two different physical failures. At 0.350 Nm the drive detects a fault that is not there. At 0.104 Nm the drive is honest and the vehicle simply cannot break out of grass. Convert both to current before anything else, because the detector and the thermal limits both live in amps.
| Quantity | Value | Where to read / how derived |
|---|---|---|
| Torque constant | 6.49 mNm/A | 8.27 / 1275 KV (ODrive convention); confirm against torque_constant
|
| Torque at the 80 A limit | 0.519 Nm | 0.00649 × 80 |
| q-axis current at 0.350 Nm | 54 A | 0.350 / 0.00649 |
| q-axis current at 0.104 Nm | 16 A (20% of max) | 0.104 / 0.00649 |
| Electrical frequency at 170 rev/s | 340 Hz | 170 rev/s × 2 pole pairs |
| Encoder output rate | 10.2–12.4 kHz (11.25 kHz typ) | AS5048A datasheet |
| Encoder pipeline latency | ~100 µs | AS5048A |
| Commutation lag at 170 rev/s | 12.2° electrical | 170 × 100 µs × 360° × 2 pole pairs |
| Observer bandwidth | 1000 (≈159 Hz if rad/s) |
encoder_bandwidth; confirm units in the parameter reference |
| Spinout thresholds | ±10 W default → ±50 W |
spinout_electrical_power_threshold, spinout_mechanical_power_threshold
|
The 20% figure is a commissioning default, not an operating limit. At 16 A of q-axis current the shaft cannot supply break-out torque against turf, which is why momentum rescues the low-torque case and a standing start does not.
Mechanism: A Sign Flip in the Power Balance
Spinout detection measures nothing about traction. It compares two power estimates that must agree when the encoder angle and the rotor angle are the same angle: electrical power into the phases, and mechanical power computed as Kt·Iq·ω from the encoder-derived velocity. Decouple the sensor from the rotor — a magnet that spins on its shaft, a through-bore hub that slips its friction fit — and commutation walks off the true angle: the drive keeps pouring in electrical power while the mechanical estimate collapses or inverts. Both conditions must hold simultaneously for the trip.
Put a number on the mechanical side. Pmech = τ·ω, so the reverse velocity that reaches −10 W is ω = 10 / τ. At 0.350 Nm that is 28.6 rad/s, or 4.55 rev/s backward. At 0.104 Nm it is 96 rad/s, or 15.3 rev/s. Raising the torque limit shrinks the trip window in inverse proportion — a 3.4× torque increase makes the detector 3.4× more sensitive to any momentary rotor reversal.
The electrical side is satisfied trivially at either torque. Copper loss alone is 1.5·Iq²·Rphase for peak-referenced dq; at 54 A with an example 10 mΩ phase resistance that is 44 W, and none of it appears as mechanical power at zero speed. Read phase_resistance from your own motor calibration and redo the multiplication. So the electrical condition latches almost immediately on a hard torque step, and the trip then waits only for a 4.5 rev/s backward blip. Tire sidewall and driveline compliance produce exactly that: 0.350 Nm lands on a stationary wheel, the tread digs into turf, the stored wind-up releases, and a light rotor bounces backward through zero.
Encoder Bandwidth Is an Observer Pole, Not a Sample Rate
11.25 kHz is how often the AS5048A produces a new 14-bit angle. encoder_bandwidth places the pole of the tracking observer that turns those samples into position and velocity for commutation and for the power estimate. The two connect only through a ceiling, and the ceiling is set by the sensor's ~100 µs pipeline latency, which is pure transport delay — phase lag with no attenuation. At 1000 rad/s (159 Hz), that delay contributes 5.7° of phase; at 5000 rad/s it contributes 29°, before the discrete update adds its own. Two decades below the sample rate is where the pole belongs.
Quantization is not the problem here. One count of a 14-bit sensor is 0.0219° mechanical, and at a 1000 rad/s observer pole a few counts of jitter buy roughly 1–2 rad/s of velocity noise — an order of magnitude short of the 28.6 rad/s needed to trip at 0.350 Nm. That arithmetic is the reason widening bandwidth does not fix the symptom: a faster observer tracks the real reverse excursion more faithfully and trips sooner. Bandwidth earns its keep elsewhere, in the 12.2° of electrical commutation lag at 170 rev/s, which costs 2.3% of torque and dumps 21% of the current onto the d-axis.
Procedure: Ramp First, Then Widen the Window
- Confirm the magnet is mechanically captive on the shaft end — bonded or seated in a machined pocket, on-axis, not a friction fit. Every step below widens a fault window; do not widen it over a magnet that can slip, because a masked decoupling becomes an uncontrolled runaway.
- Set the axis
input_modeto so the controller integrates toward the target instead of presenting a step. - Restore the torque limit to 0.350 Nm now, not before the ramp is in place.
- Raise
spinout_electrical_power_thresholdto +50 W andspinout_mechanical_power_thresholdto −50 W, up from the ±10 W defaults. - Leave
encoder_bandwidthat 1000 unless a step-response log shows the velocity estimate lagging the command. - Save configuration, reboot, and clear the axis error before the first armed run.
Verification: The Three Traces That Close the Loop
Log electrical_power, mechanical_power, Iq_setpoint against Iq_measured, vel_estimate against input_vel, and pos_estimate at the highest rate the interface sustains, then run the maneuver that failed — standing start on grass to 170 rev/s.
Good looks like this. Mechanical power dips negative on load transients but the worst excursion sits at half the threshold or better; if the worst dip is −25 W, ±50 W is the right setting and ±30 W is not. Iq measured tracks setpoint and pins at the limit for no more than a few tens of milliseconds. Position estimate is continuous across the whole run — a step discontinuity is the signature of a genuine slip and nothing in the tuning will make it acceptable. Repeat the run with the wheels lifted: a trip that appears only under load is mechanical wind-up, a trip that appears unloaded is in the sensing chain. A paint witness line across the magnet hub and shaft, checked after a session, settles the slip question permanently.
Recurring Pitfalls on Small High-KV Traction Drives
Widened thresholds are a real trade. At ±50 W and 0.350 Nm, a genuine decoupling has to produce a 22.7 rev/s discrepancy before the drive intervenes. That is fine behind a bonded on-axis magnet, and unacceptable behind a through-bore encoder relying on a friction fit — that hub is the classic slipper, and it is the only configuration where the detector is protecting you from something.
VEL_RAMP shapes the command; it does not create torque. Push the ramp past what the tires transmit into turf and the axis saturates, actual velocity falls behind the profile, and error accumulates until the vehicle lurches when traction returns. The 80 A current limit is thermal, not logical: 54 A held into a bogged wheel puts tens of watts into the windings and heats rotor magnets, so cap the time at limit and watch motor temperature rather than trusting the current ceiling alone. Route the SPI run away from phase leads — a single corrupted angle frame at 340 Hz electrical becomes a velocity spike straight into the mechanical-power estimate, and the AS5048A parity and error flags are the place to catch it.
Stop widening thresholds if the trip still appears with vel_ramp_rate at or below 10 rev/s² and the wheels off the ground, or if pos_estimate shows a step discontinuity across the fault. Both point at the sensing chain or a physically loose magnet, and more threshold is the wrong answer to either. Capture a full configuration dump plus a high-rate log spanning the trip and take it to ODrive's official support channel.
FAQ
How do I tell a false SPINOUT_DETECTED from a real encoder slip?
Check pos_estimate across the trip: a false trip shows continuous position with a brief negative excursion in mechanical_power, while a real slip shows a step discontinuity in angle and a persistent power mismatch. Confirm mechanically with a paint witness line across the magnet hub and shaft.
How do I set vel_ramp_rate for a 0 to 170 rev/s command?
Start at 10 rev/s² and raise it until Iq_measured pins at the torque limit and vel_estimate falls behind input_velThe analytical ceiling is (τlimit − τload) / (2π·Jtotal).
How do I calculate the torque my ODrive current limit allows?
Use Kt = 8.27 / KV, so a 1275 KV motor gives 6.49 mNm/A and an 80 A limit gives 0.519 Nm peak. A 0.350 Nm limit therefore commands 54 A of q-axis current, and the 20% commissioning default of 0.104 Nm commands 16 A.
How do I pick spinout power thresholds without masking a real fault?
Log mechanical_power through the worst maneuver, take the largest negative transient, and set the threshold to roughly twice it — ±50 W against a −25 W worst case. Keep the default ±10 W if the encoder magnet is held by friction fit, because that is the configuration that actually slips.
How do I use encoder_bandwidth if the AS5048A samples at 11.25 kHz?
Bandwidth sets the tracking observer pole, not the sample rate, and the sensor's ~100 µs latency caps it: 1000 rad/s costs 5.7° of phase, 5000 rad/s costs 29°. Leave it at 1000 unless a step-response log shows the velocity estimate lagging the command, since a faster observer tracks real reverse excursions better and trips the detector sooner.