LQR Controllers
What is LQR?
Linear Quadratic Regulator (LQR) is an optimal control algorithm that automatically computes controller gains to minimize a cost function balancing state error and control effort. Unlike manually-tuned PID controllers, LQR uses a mathematical model of your system to determine the optimal feedback gains.
Key Difference from PID: With PID, you manually tune kP, kI, and kD through trial and error. With LQR, you specify how much you care about position error vs velocity error vs control effort, and the algorithm computes the optimal gains for you.
Why Use LQR?
Advantages
Model-Based Tuning: LQR uses your mechanism's physical model (mass, gearing, motor characteristics) to compute gains, reducing trial-and-error tuning
Multi-State Control: Naturally handles both position and velocity simultaneously
Optimal Performance: Mathematically minimizes a cost function you define
Consistent Behavior: Gains are derived from physics, making them more predictable across different setpoints
When to Consider LQR
Complex mechanisms where PID tuning is difficult
High-performance requirements where optimal response matters
Educational settings where understanding control theory is valuable
Mechanisms with well-characterized models (accurate mass, inertia, motor constants)
When PID May Be Better
Simple mechanisms that tune easily with PID
Limited modeling data (unknown mass, inertia, etc.)
Quick prototyping where tuning time is limited
Mechanisms with significant nonlinearities that LQR's linear model can't capture
LQR Execution in YAMS
Important: LQR controllers are not natively supported by any motor controller hardware. When you configure an LQR controller in YAMS, the closed loop control always runs on the RoboRIO via SmartMotorController.iterateClosedLoop().
Why RoboRIO-Only?
Motor controller vendors (CTRE, REV, ThriftyBot) implement PID controllers on their hardware, but none support LQR natively. LQR requires:
Matrix operations (solving Riccati equations)
State-space model storage
Kalman filter state estimation
Multi-state feedback computation
These operations are beyond what current motor controller firmware supports.
Performance Implications
Update Rate
1kHz+ (on controller)
50Hz (robot loop) or custom period
Latency
Minimal (~1ms)
CAN bus round-trip (~5-20ms)
CPU Load
None on RoboRIO
Small increase on RoboRIO
Best For
Fast loops, simple control
Complex control, slower mechanisms
For most FRC mechanisms (arms, elevators), the 50Hz update rate is sufficient. LQR's optimal gains often compensate for the slower update rate compared to motor controller PID.
Configuring LQR in YAMS
In YAMS, you create an LQRConfig to specify your mechanism type and tuning parameters, then create an LQRController from that config, and finally pass it to SmartMotorControllerConfig.withClosedLoopController().
LQRConfig Overview
LQRConfig requires three core parameters:
DCMotor: The motor model (e.g.,
DCMotor.getKrakenX60(1))MechanismGearing: Your gear reduction
MomentOfInertia: The rotational inertia of your mechanism
Then you specify the mechanism type with one of:
.withFlyWheel()- For velocity-controlled flywheels.withArm()- For position-controlled arms.withElevator()- For position-controlled elevators
Flywheel LQR Configuration
Flywheels use a single-state model (velocity only):
Parameter Explanation:
qelms (velocity)
RadiansPerSecond
Velocity error tolerance. Decrease to penalize velocity errors more heavily (more aggressive).
modelTrust
RadiansPerSecond
Standard deviation of your model. Lower = trust the model more.
encoderTrust
RadiansPerSecond
Standard deviation of encoder readings. Lower = trust encoder more.
controlEffort
Volts
How much to penalize voltage usage. Increase for gentler control.
Arm LQR Configuration
Arms use a two-state model (position and velocity):
Parameter Explanation:
qelmsPosition
Radians
Position error tolerance. Decrease for faster position correction.
qelmsVelocity
RadiansPerSecond
Velocity error tolerance. Decrease for smoother velocity tracking.
modelPositionTrust
Radians
Model position uncertainty.
modelVelocityTrust
RadiansPerSecond
Model velocity uncertainty.
encoderPositionTrust
Radians
Encoder measurement uncertainty.
Elevator LQR Configuration
Elevators use a two-state linear model (position and velocity in meters):
Elevator-Specific Parameters:
mass
Kilograms
Total mass of the elevator carriage and load.
drumRadius
Meters/Inches
Radius of the spool or drum that the belt/rope wraps around.
Using LQRController with SmartMotorControllerConfig
Once you have an LQRController, pass it to withClosedLoopController():
Advanced LQR Options
Aggressiveness
Use withAggressiveness() to scale overall controller response:
Measurement Delay Compensation
If your sensors have significant latency, compensate with:
Custom Loop Period
By default, LQR uses a 20ms (50Hz) loop period. Override if using a faster loop:
Simulation-Only LQR
You can use different controllers for simulation and real robot:
This is useful for:
Validating LQR tuning in simulation before deploying
Comparing LQR vs PID performance
Using LQR's model-based approach to inform PID tuning
Complete Example: LQR Arm
Critical: LQR runs on the RoboRIO via SmartMotorController.iterateClosedLoop(). If you use the Arm, Elevator, or other mechanism classes, this is handled automatically. If you use SmartMotorController directly, you must call iterateClosedLoop() in your periodic method.
Tuning Strategy
Starting Point
Begin with conservative settings:
Position qelms:
Radians.of(0.1)orMeters.of(0.05)Velocity qelms:
RadiansPerSecond.of(1.0)orMetersPerSecond.of(0.5)Control effort:
Volts.of(12)(full battery = least aggressive)
Trust values (standard deviations):
Model trust: Start with small values (0.01) if your model is accurate
Encoder trust: Use values based on your encoder resolution and noise
Increasing Responsiveness
Decrease position qelms (e.g.,
Radians.of(0.1)→Radians.of(0.05))Decrease control effort (e.g.,
Volts.of(12)→Volts.of(8))
Reducing Oscillation
Increase control effort (e.g.,
Volts.of(8)→Volts.of(12))Decrease velocity qelms to penalize velocity errors more
Always Test in Simulation First
LQR can behave very differently with small parameter changes. Always validate in simulation before testing on the real robot.
Troubleshooting LQR
Oscillation
Symptoms: Mechanism oscillates around setpoint Solutions:
Increase control effort (R) to reduce aggressiveness
Decrease velocity qelms to penalize velocity errors
Add or increase feedforward kD term
Check for mechanical issues (backlash, friction)
Slow Response
Symptoms: Mechanism responds too slowly to setpoint changes Solutions:
Decrease control effort (R)
Decrease position qelms to penalize position errors more
Verify motion profile constraints aren't too conservative
Steady-State Error
Symptoms: Mechanism doesn't quite reach setpoint Solutions:
Verify feedforward is properly tuned (especially kG for arms/elevators)
Check that closed loop tolerance isn't too large
Ensure model parameters (mass, inertia, gearing) are accurate
Model Mismatch
Symptoms: Simulation works but real robot doesn't Solutions:
Re-measure mass and moment of inertia
Verify gearing ratio is correct
Run SysId to get accurate motor characterization
Account for friction and other losses in feedforward
LQR vs PID Quick Reference
Tuning Method
Trial and error
Model-based computation
Parameters
kP, kI, kD
Q matrix (qelms), R matrix (control effort)
States Controlled
Typically one (position or velocity)
Multiple (position AND velocity)
Model Required
No
Yes (motor, gearing, inertia)
Optimality
Not guaranteed
Mathematically optimal
Hardware Support
Motor controllers
RoboRIO only
Update Rate
1kHz+ (on controller)
50Hz (RoboRIO)
YAMS API
withClosedLoopController(kP, kI, kD)
withClosedLoopController(LQRController)
Last updated