The AutoLQR library for Arduino provides an intuitive and efficient implementation of the Linear Quadratic Regulator (LQR), a powerful control technique for dynamic systems. With AutoLQR, you can create optimized controllers for single-input, single-output (SISO) systems, or even multi-input, multi-output (MIMO) systems, directly on your Arduino-compatible hardware.
Linear Quadratic Regulator (LQR) is a method used to compute optimal feedback gains for controlling a linear dynamic system. It balances minimizing:
- State deviations from a desired target (e.g., position, velocity, angle).
- Control effort required to achieve that goal (e.g., motor torque, current).
LQR achieves this balance by solving a mathematical optimization problem, generating control gains that lead to:
- Stability: The system converges to the desired state.
- Efficiency: The control effort is minimized.
LQR is widely used in robotics, aerospace, and industrial automation due to its ability to handle dynamic systems robustly.
- Flexible System Dimensions: Supports arbitrary state and control dimensions.
- Dynamic Gains Computation: Automatically computes the optimal feedback gain matrix ( K ).
- Customizable Costs: Allows tuning of state and control penalties through ( Q ) and ( R ) matrices.
- Lightweight Implementation: Optimized for Arduino's limited memory and computational power.
AutoLQR assumes your system is modeled as a discrete-time linear state-space system:
[ \mathbf{x}[k+1] = \mathbf{A}\mathbf{x}[k] + \mathbf{B}\mathbf{u}[k] \ \mathbf{u}[k] = -\mathbf{K}\mathbf{x}[k] ]
Where:
- ( \mathbf{x}[k] ): System state vector at time step ( k ) (e.g., position, velocity).
- ( \mathbf{u}[k] ): Control input vector at time step ( k ) (e.g., motor command).
- ( \mathbf{A} ): State matrix defining the system's dynamics.
- ( \mathbf{B} ): Input matrix defining how control inputs affect the system.
- ( \mathbf{K} ): Optimal feedback gain matrix computed by LQR.
The LQR algorithm calculates ( \mathbf{K} ) by minimizing the cost function:
[ J = \sum_{k=0}^{\infty} \left( \mathbf{x}^T[k]\mathbf{Q}\mathbf{x}[k] + \mathbf{u}^T[k]\mathbf{R}\mathbf{u}[k] \right) ]
Where:
- ( \mathbf{Q} ): State cost matrix (penalizes deviation from the desired state).
- ( \mathbf{R} ): Input cost matrix (penalizes control effort).
The AutoLQR library consists of two main files:
AutoLQR.h
AutoLQR.cpp
Additionally, there is a library.properties
file for Arduino IDE compatibility.
Initializes the LQR controller.
stateSize
: Number of states in the system (size of ( \mathbf{x} )).controlSize
: Number of control inputs (size of ( \mathbf{u} )).
Sets the state matrix ( \mathbf{A} ).
- Input: Pointer to a row-major array representing the ( \mathbf{A} ) matrix.
Sets the input matrix ( \mathbf{B} ).
- Input: Pointer to a row-major array representing the ( \mathbf{B} ) matrix.
Sets the cost matrices ( \mathbf{Q} ) and ( \mathbf{R} ).
- Inputs:
Q
: Pointer to a row-major array representing the ( \mathbf{Q} ) matrix.R
: Pointer to a row-major array representing the ( \mathbf{R} ) matrix.
Computes the optimal feedback gain matrix ( \mathbf{K} ) by solving the discrete-time algebraic Riccati equation (DARE).
- Returns:
true
if computation succeeds;false
otherwise.
Updates the current state vector ( \mathbf{x} ).
- Input: Pointer to the current state vector.
Calculates the control vector ( \mathbf{u} ) based on the current state and gain matrix ( \mathbf{K} ).
- Output: Pointer to the calculated control vector.
Prints the computed ( \mathbf{K} ) matrix to the serial monitor for debugging.
The ( \mathbf{Q} ) and ( \mathbf{R} ) matrices allow you to adjust the balance between state accuracy and control effort:
-
( \mathbf{Q} ): State Cost Matrix
- Larger values penalize deviations in specific states (e.g., position or angle).
- Example: To prioritize accurate position tracking, increase the corresponding diagonal element of ( \mathbf{Q} ).
-
( \mathbf{R} ): Input Cost Matrix
- Larger values penalize high control efforts (e.g., motor torque or speed).
- Example: For limited power systems, increase ( \mathbf{R} ) values to reduce excessive control commands.
- Stability: Ensure your system is controllable and the ( \mathbf{Q} ) and ( \mathbf{R} ) matrices are positive definite.
- Discretization: The library assumes a discrete-time system. If you start with continuous-time matrices, discretize them using the sampling time.
- Computational Limits: Arduino's computational power is limited. For large systems, precompute the ( \mathbf{K} ) matrix offline and load it directly.
- Define your system's ( \mathbf{A} ) and ( \mathbf{B} ) matrices.
- Define the cost matrices ( \mathbf{Q} ) and ( \mathbf{R} ) based on your priorities.
- Use the library to compute the optimal ( \mathbf{K} ) matrix.
- Continuously update the system state and calculate the control inputs using the library's functions.
- Single-state control (e.g., position control of a motor).
- Two-state systems (e.g., position and velocity of a robot arm).
- Multi-state systems like balancing an inverted pendulum.
For complete code examples, refer to the provided files.
- Tested on Arduino Uno, Mega, and ESP32.
- Requires Arduino IDE version 1.8.13 or higher.
This library is open-source and licensed under the MIT License. Feel free to modify and adapt it to your specific needs.