Skip to content
2 min read
In progress

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.

Lesson
41 / 47
Reward
+10XP

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 (or, per WPILib's guidance for position loops, increase kD instead) until the oscillation stops — WPILib's tuning docs describe this qualitatively, not as a fixed percentage cut. 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 until it just starts to oscillate, then back it off (or add kD) until the oscillation stops — WPILib doesn't specify a fixed percentage.
Spot an error or something out of date?Log in to suggest an edit

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.

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

02.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?

03.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.

All 47 lessons in Mechanical, Build & Pneumatics