Skip to content
Mechanical, Build & Pneumatics·Lesson 41 of 47

Closed-Loop Mechanisms That Oscillate, Sag, or Stall

Fix arms/elevators that buzz, droop, or slam: wrong tuning order, missing gravity term, encoder phase/conversion errors, and bad motion constraints.

Sign in to track progress, earn XP, and save lessons.

Symptom A: It oscillates / buzzes at the setpoint

Usually too much kP or kD, or a feedback delay. Fix: back kP off by ~20% from the point where overshoot starts (WPILib's rule). Confirm your loop reads a fresh sensor each iteration and that you're not double-applying feedforward and integral windup. Lower the velocity/acceleration constraints to see if the mechanism is being asked to move impossibly fast.

Symptom B: It sags or drifts under gravity

Missing or wrong gravity feedforward. For an arm, kG must be multiplied by cos(angle) (use ArmFeedforward, which does this); a constant kG on an arm will hold at one angle and sag at others. For an elevator, kG is constant (use ElevatorFeedforward). Tune kG first, raise it until the mechanism just holds against gravity without drifting.

Symptom C: It runs away or fights itself

Classic encoder phase / sign error or wrong conversion factor. The controller sees the mechanism move the 'wrong' way and commands harder, accelerating the runaway. Diagnose: disable the motor, move the mechanism by hand, and confirm the reported position increases in the commanded-positive direction. Fix the encoder inversion or conversion factor (counts-to-radians/meters) before touching gains.

Symptom D: It slams into the setpoint

No motion profile, or profile constraints set too aggressively. Use a ProfiledPIDController / TrapezoidProfile so the controller chases a physically realistic position+velocity+acceleration trajectory instead of an instantaneous step. WPILib recommends starting with modest constraints and increasing.

The correct tuning order (don't improvise)

For gravity-loaded mechanisms, WPILib's sequence is: kG -> kV -> kA -> kP, then add kD only if needed, and find kS via SysId. Tuning kP before kG is the most common reason a mechanism 'won't tune', the feedback is fighting uncompensated gravity.

Use SysId, then refine

Run a SysId quasistatic + dynamic routine to get kS/kV/kA/(kG) empirically. These get you most of the way; only then hand-tune kP/kD for the last bit of tracking.

Workflow

  1. Verify sensor direction/scale by hand.
  2. Add/verify the correct gravity feedforward (arm = cosine, elevator = constant).
  3. Set conservative profile constraints.
  4. Characterize with SysId; apply kS/kV/kA/kG.
  5. Raise kP to slight overshoot, back off 20%; add kD only if it still oscillates.

Key takeaways

  • Tune in the order kG -> kV -> kA -> kP; tuning kP first while gravity is uncompensated is why mechanisms 'won't tune'.
  • Sag means missing gravity FF: arms need cosine-scaled kG (ArmFeedforward), elevators need a constant kG (ElevatorFeedforward).
  • Runaway is almost always an encoder sign/conversion error, verify by hand before changing gains, and use a motion profile to stop slamming.

Lesson quiz

Required

Answer all 3 questions correctly to complete this lesson.

1.A position-controlled arm oscillates around its setpoint, overshooting back and forth. In a PID loop, which gain is most appropriate to add/increase to damp this oscillation?

2.An arm sags below its commanded angle and the PID has to constantly fight gravity to hold position. What is the correct WPILib-style fix?

3.In WPILib's ArmFeedforward, the gravity gain kG is multiplied by which quantity, and what does that imply about where gravity load is greatest?

Answer every question to submit.