FILE:P-05 YEAR:2026 REV:1.0
§ RESEARCH PAPER · PHYSICS · CONTROL THEORY

Inverted Pendulum
Control Systems.

Control theory PID LQR State space Riccati Kalman filter

How do you keep something that wants to fall over standing perfectly upright? This paper works through it from first principles — starting with PID, then deriving the Linear Quadratic Regulator for a two-wheeled balancing robot: the state-space model, the A and B matrices, controllability, the algebraic Riccati equation, and a fully worked numerical example.

FIG.01 / FREE-BODY θ → 0 rad
balance loop
vertical θ friction F control force mg disturbance
SubjectControl
MethodsPID · LQR
Format16-pg paper
StatusComplete
§01 · Definition

01 What is an inverted pendulum?

An inverted pendulum is a pendulum in which its centre of mass is above the pivot point, making it unstable and prone to toppling without active control systems.

It can be controlled by moving the base. A basic example of this is balancing a ruler or a pencil on the tip of your finger by moving your finger so that the pencil’s centre of mass stays above the pivot. The schematic at the top of the page (Figure 1) displays the forces acting on the pendulum: gravity \(mg\) pulling the mass down, an external disturbance, ground friction, and the control force \(F\) applied through the base.

Original hand-drawn free-body diagram of an inverted pendulum on a cart, showing the disturbance force, gravity mg, the control force, friction and the tilt angle theta.
Figure 1 · original diagram (made by Giorgi)

My original diagram of the inverted pendulum and the forces acting on it — recreated as the live schematic at the top of the page.

Measurements

The diagram shown above (Figure 1) displays the forces acting on the pendulum. To control the pendulum, we need a way to calculate the force and acceleration required to move the base, given the angle, angular velocity, and mass, to ensure that the centre of mass is always above the base. To get these measurements in robotics, you need to use an IMU, which contains:

Inside the IMU
Accel.
An accelerometer — measures linear acceleration and gravity; it is used to determine the static tilt angle relative to the ground.
Gyro.
A gyroscope — measures the rate of rotation (angular velocity) around the axes, telling the controller how fast the pendulum is falling.
EKF
An Extended Kalman Filter — to estimate the tilt angle, providing a highly accurate, real-time estimation of the pendulum’s tilt angle, velocity, and position by fusing noisy sensor data.
§02 · How to control an inverted pendulum

02 PID control (Proportional–Integral–Derivative)

The error term is the difference between the pendulum being perfectly upright when it is directly above the pivot point \(0\) rads and the pendulum’s actual angle at that moment.

P Proportional

\[ K_{p}\, e(t) \]

The first part of PID control is the proportional term, known as the P value, and its equation is shown above. This applies a correcting force based on how far the pendulum is leaning away from the centre position (the error). A larger angle produces a greater corrective force, while a smaller angle produces a smaller one. Although this helps the pendulum respond quickly, proportional control alone can make the system unstable. This is because the pendulum may swing past the centre point at too high a speed, causing repeated side-to-side oscillations and making the robot unstable.

I Integral

\[ K_{i}\int e(t)\,dt \]

The next part is the integral term, or I value, shown with the equation above. In some situations, proportional control may not produce sufficient force to fully balance the pendulum when the angle error is very small. Small continuous forces, such as gravity or friction, can still cause the pendulum to drift away from the centre over time. To fix this, the integral term tracks the total error over a period of time and adds a small extra correction to remove any remaining offset. However, the integral effect is normally kept quite low, because if too much past error is accumulated the system can become unstable and the pendulum movement may become even more erratic.

D Derivative

\[ K_{d}\frac{de(t)}{dt} \]

To help control this erratic movement, the derivative term is added and it is the equation shown above. The D value looks at the rate of change of the error rather than just the size of the error itself, acting as a braking force to slow the pendulum as it approaches the upright position. When the pendulum is moving rapidly towards the target angle, the derivative term produces an opposing effect that reduces the speed of the correction, as the rate of the error will be decreasing, creating a negative value. This makes the overall movement smoother and reduces overshoot and excessive oscillation.

Combining all these terms gives us the following equation, which can be used to control an inverted pendulum smoothly. (\(u(t)\) in a two-wheeled robot would be the motor voltage.)

PID\[ u(t) = K_{p}\, e(t) + K_{i}\int e(t)\,dt + K_{d}\frac{de(t)}{dt} \]
Fig.02 · PID control loopCLOSED LOOP
θref = 0 + e(t) PID controller P · Kp e I · Ki ∫e dt D · Kd de/dt u(t) motor V Pendulum (the plant) θ IMU + Kalman

Fig.02 — the setpoint and the measured angle meet at the summing junction; the error drives the PID controller, whose output moves the plant; the IMU and Kalman filter close the loop.

§03 · Potential issues with PID and how to fix them

03 Potential issues with PID

Windup

One potential problem with using PID control is an integral windup. This is because in a real-world scenario, motors have a physical limit where they can reach a maximum RPM, and if the system experiences a constant error, such as the pendulum being knocked over, this error will build up through the integral, causing it to request a higher RPM than is physically possible by the motor. However, the main issue is that when the robot returns to its correct position, the controller has to unwind all the accumulated excess error, causing the pendulum to overshoot significantly and fall over.

Fix · clamping (anti-windup)

To fix this, an anti-windup method is used, with the most popular being clamping. Clamping is where it conditionally turns off the integrator by setting its error input to zero when two things happen: the controller outputs its saturation limit, and the error is trying to push the controller even further into that saturation limit. The integral is then turned back on when the error sign changes from + to − or − to +.

Noise

Another huge issue is noise, which can be caused by motor vibration, sensor inaccuracies, external factors, etc. One of the biggest issues is high-frequency noise, as even when the amplitude is low, it can create a very high derivative value in the PID control, causing inaccuracies. This can be fixed through a filter.

Fix · the extended Kalman filter

One of the best filters you can use is the extended Kalman filter. A Kalman filter removes noise by continuously comparing a mathematical prediction of a system’s state, such as the precise tilt angle, against the actual, jittery sensor measurements it receives. It mathematically blends these two values using a dynamic weight called the Kalman gain, trusting whichever source currently has less uncertainty to calculate a smooth, accurate estimate of the true state.

§04 · A more capable controller

04 LQR control system

An LQR system, compared to a PID control system, is a lot more complex. Developed 38 years after PID, in the 1960s, an LQR system model offers much better performance in terms of stability and control. However, it requires more computation and, in robots — unlike PID — requires encoders on the motors.

What follows

The rest of this paper is the maths behind LQR: the state vector, the equation \(\dot{X} = AX + Bu\), deriving the A and B matrices, full-state feedback, why a naive approach falls short, the Riccati equation, and finally a fully worked example with real numbers.

§05 · Maths behind LQR

05 The state vector

To begin with, you have a state vector \(X\), and for a self-balancing robot it would be represented with 4 variables — a \(4\times1\) vector:

\[ X = \begin{bmatrix} x \\[2pt] \dot{x} \\[2pt] \theta \\[2pt] \dot{\theta} \end{bmatrix} \]

The state vector is useful because it encapsulates the system’s exact physical state, allowing the Linear Quadratic Regulator (LQR) to compute the single, mathematically optimal motor torque required to keep the robot upright. These are the definitions for the terms shown:

The four states
\(x\)
Position — the displacement from the robot’s wheels to the designated reference origin point, telling the robot where it is relative to its starting point, which is recorded using the robot’s encoder. This value is used by the robot so it doesn’t drift, and tries to move back to its original starting position.
\(\dot{x}\)
Velocity — represents the first time derivative of the position and is used by the LQR for momentum, as the system has to know the instantaneous speed of the robot to calculate the counter-torque required to apply without the system falling over.
\(\theta\)
Tilt angle — the angle deviation from the robot’s perfect vertical position, used by the LQR to ensure stability, as any deviation creates a gravitational torque pulling the robot down. The LQR heavily penalises this variable in its cost function (the \(Q\) matrix) to keep the tilt as small as possible.
\(\dot{\theta}\)
Angular velocity — the first time derivative of the angle deviation, representing how fast the robot is falling or recovering. This is used much like the derivative function in PID, ensuring the robot doesn’t overshoot: if it has a large tilt angle but is already rotating back, it knows it is recovering and will not overshoot with excessive motor power.

Eigenvalues: how the robot knows if it is stable

In terms of how the robot knows if it is stabilised or falling, it uses eigenvalues — a scalar value, \(\lambda\). It is used to see if a robot is stabilised due to this equation:

\[ \dot{x} = \lambda x \]

This is important because the rate of change of \(x\) with respect to time equals \(\lambda x\), which says that the rate at which \(x\) changes is proportional to \(x\). This is an exponential function and can be represented as:

\[ x(t) = x(0)\,e^{\lambda t} \]

This shows that if \(\lambda > 0\) the robot will be unstable, as \(e^{\lambda t}\) will increase exponentially as time passes. If \(\lambda = 0\) or \(\lambda < 0\), it will be stable or stabilising respectively, as it would be decreasing to 0. The matrix \(A\) will have 4 distinct eigenvectors \((v_1,v_2,v_3,v_4)\) and also 4 distinct eigenvalues \((\lambda_1,\lambda_2,\lambda_3,\lambda_4)\). And to show the robot’s stability, we can sum each mode:

\[ x(t) = C_{1}e^{\lambda_{1}t}v_{1} + C_{2}e^{\lambda_{2}t}v_{2} + C_{3}e^{\lambda_{3}t}v_{3} + C_{4}e^{\lambda_{4}t}v_{4} \]

where \(C\) is the coefficient of the term when \(t = 0\).

Fig.03 · the sign of λ decides everythinge^λt
time t x(t) equilibrium x(0) λ > 0 topples λ < 0 · settles

Fig.03 — both start from the same small tilt. A stable controller forces every eigenvalue into the “settles” regime.

Putting everything together: \(\dot{X} = AX + Bu\).

\[ \dot{X} = AX + Bu \]
Where
\(X\)
is the state vector \((4\times1)\).
\(u\)
is the control input, which is just one number, and is the force that the motor pushes at the ground.
\(A\)
is the system matrix \((4\times4)\), which captures the robot’s own dynamics: what the robot will do naturally by itself.
\(B\)
is the input matrix \((4\times1)\), which shows that if the robot is pushed with force \(u\), what states it affects and by how much.
In words

So, to put the equation into words: the rate of change = the physics of the robot alone \((AX)\) + what you are commanding the robot to do \((Bu)\).

§06 · The A matrix & the B vector

06 Deriving A and B

The first row of the matrix \(A\) takes out the robot’s rate of change of position \((\dot{x})\) from the state vector. As the first term in the \(\dot{X}\) vector in the equation \(\dot{X} = AX + Bu\) is \(\dot{x}\), we simply take \(\dot{x}\) from the state vector \(X\):

\[ \text{row 1 of } A = \begin{bmatrix} 0 & 1 & 0 & 0 \end{bmatrix} \;\Rightarrow\; \dot{x} = 0\!\cdot\! x + 1\!\cdot\!\dot{x} + 0\!\cdot\!\theta + 0\!\cdot\!\dot{\theta} \]

Row 3 will just be \(\begin{bmatrix} 0 & 0 & 0 & 1 \end{bmatrix}\), as we need \(\dot{\theta}\) from the state vector, which is just its 4th variable, since the 3rd variable in the \(\dot{X}\) vector is \(\dot{\theta}\).

For row 2, we are looking to obtain \(\ddot{x}\) in terms of \(\theta\) (the angle deviation from the perfect vertical position). And for row 4, we are looking to get \(\ddot{\theta}\) from \(\theta\). In order to find these, we begin applying Newton’s laws: one for the horizontal motion of the whole thing, one for the rotation of the body about its centre of mass. These are all the new terms in the following equations:

New terms
\(M\)
The total mass of the wheels and base.
\(m\)
The body mass.
\(l\)
The distance from the wheel axle up to the body’s centre of mass.
\(I\)
The moment of inertia of the body about its own centre of mass.
\(g\)
The acceleration due to gravity (equal to 9.81).
\(F\)
The horizontal drive force generated at the ground by the wheel motors (interchangeable with the control input \(u\)).
1\[ (M+m)\,\ddot{x} - m\,l\,\ddot{\theta}\cos\theta + m\,l\,\dot{\theta}^{2}\sin\theta = F \]
2\[ (I+m\,l^{2})\,\ddot{\theta} - m\,l\,\ddot{x}\cos\theta - m\,g\,l\sin\theta = 0 \]

Equation (1) is total horizontal force = mass × acceleration for the system. Equation (2) is the rotational law for the body. The crucial term is \(-m\,g\,l\sin\theta\), which is gravity and is what topples the robot.

However, the problem with these equations is that they are not linear due to the \(\sin\theta\), \(\cos\theta\) and \(\dot{\theta}^{2}\) terms, and eigenvalues and \(AX + Bu\) are built for a linear system. To make the equations linear, we can use the small-angle approximation, since a balancing robot only needs to deal with small values of \(\theta\), and a good control system will keep \(\theta\) within a few degrees:

\[ \sin\theta \approx \theta, \qquad \cos\theta = 1, \qquad \dot{\theta}^{2} \approx 0 \]
Fig.04 · small-angle approximationsinθ ≈ θ
θ y = θ y = sinθ θ ≈ sinθ small-angle

Fig.04 — inside the shaded band the straight line and the sine curve are indistinguishable, so the linear model is faithful while the robot stays near upright.

Now, by substituting the small-angle approximations into equations (1) and (2), we get these 2 linear equations:

\[ (M+m)\,\ddot{x} - m\,l\,\ddot{\theta} = F \]
\[ (I+m\,l^{2})\,\ddot{\theta} - m\,l\,\ddot{x} = m\,g\,l\,\theta \]

Now we need to remove the two unknowns with one equation — that is, \(\ddot{x} = \,\ldots\) without having another \(\ddot{x}\) or \(\ddot{\theta}\) inside the equation. To do this, we solve it simultaneously and get a common denominator \(p\), and get the following equations:

4\[ p \equiv I(M+m) + M\,m\,l^{2} \]

And the results are:

5\[ \ddot{x} = \frac{m^{2}g\,l^{2}}{p}\,\theta + \frac{I+m\,l^{2}}{p}\,F \]
6\[ \ddot{\theta} = \frac{m\,g\,l(M+m)}{p}\,\theta + \frac{m\,l}{p}\,F \]

Therefore, for row 2 it will be \(\begin{bmatrix} 0 & 0 & \frac{m^{2}gl^{2}}{p} & 0 \end{bmatrix}\), and for row 4 it will be \(\begin{bmatrix} 0 & 0 & \frac{mgl(M+m)}{p} & 0 \end{bmatrix}\), giving the final matrix:

System matrix A \[ A = \begin{bmatrix} 0 & 1 & 0 & 0 \\ 0 & 0 & \dfrac{m^{2}gl^{2}}{p} & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & \dfrac{mgl(M+m)}{p} & 0 \end{bmatrix} \]
Input vector B \[ B = \begin{bmatrix} 0 \\[4pt] \dfrac{I+ml^{2}}{p} \\[6pt] 0 \\[4pt] \dfrac{ml}{p} \end{bmatrix} \]

For vector \(B\), the first row is 0, as we already get the \(\dot{x}\) value from the \(AX\) part of the equation. Row 3 is also 0, as once again we get \(\dot{\theta}\) from the \(AX\) part in \(\dot{X} = AX + Bu\). And for rows 2 and 4, we can use the values on the right-hand side of equations (5) and (6) (\(F\) can be interchanged with \(u\)).

Showing that the system with matrix A will be unstable

By looking at just the angle and switching the motor off, so therefore \(F = 0\), we get the equation:

\[ \ddot{\theta} = \frac{mgl(M+m)}{p}\,\theta = \omega^{2}\theta, \qquad \omega^{2} \equiv \frac{mgl(M+m)}{p} > 0 \]

Unstable: \(\ddot{\theta} = \omega^{2}\theta\).  Stable: \(\ddot{\theta} = -\omega^{2}\theta\). It is unstable because, when the growth-rate coefficient is positive, it leads to exponential growth. So the angle doesn’t swing back and forth; it just blows up instantly until the robot hits the floor.

§07 · Steering λ to be negative

07 Feedback control

We know that the control system is naturally unstable, and we now need to make it stable through feedback, where it measures the state and feeds back to determine the control input.

Full-state feedback: u = −KX

One of the best ways to create a simple, powerful feedback rule is to make the control flow through a weighted combination of all the values in the state vector, and is shown as:

\[ u = -KX, \qquad K = \begin{bmatrix} k_{1} & k_{2} & k_{3} & k_{4} \end{bmatrix} \]

In addition, we use a negative \(K\) to counter the robot’s movement by pushing it in the opposite direction. The \(k\) values inside the \(K\) vector are referred to as gains. Now, by substituting \(u = -KX\) into the original equation, we get:

\[ \dot{X} = (A - BK)\,X \]

So, in order for the robot to be stable, the eigenvalues of \((A - BK)\) need to be negative, using the same logic shown in the \(\dot{X} = AX + Bu\) section, so the control system needs to use the \(BK\) value to steer the eigenvalues to be negative.

Is the robot controllable?

To see if the robot is controllable, we use the controllability matrix, which is the following:

\[ \mathcal{C} = \begin{bmatrix} B & AB & A^{2}B & A^{3}B \end{bmatrix} \]

Here, \(B\) is the direction your input pushes immediately, \(AB\) is where the push is a moment later, then \(A^{2}B\) is a moment after that, and so on. Then, using MATLAB, we can calculate the rank, which shows how many dimensions of the state equation can be controlled. So if the rank is equal to 4, the system is controllable, and if it is less than 4, it is not controllable. We will assume our robot is controllable.

§08 · The catch

08 Why this isn’t the end

Firstly, an aggressive controller commands forces larger than the motor can output. As soon as the motor reaches its saturation limit, the linear design — which assumes the motor can output unlimited force — no longer describes what the LQR system wants.

In addition to this, the gains can be calculated through pole placement, where you first decide what you want your 4 eigenvalues to be (all negative, to ensure the robot is stable) and write them as a polynomial’s solutions:

\[ (\lambda-\lambda_{1})(\lambda-\lambda_{2})(\lambda-\lambda_{3})(\lambda-\lambda_{4}) \]

and through this you get a quartic. Then you take the quartic from the equation \(\det(A - BK - \lambda I) = 0\), whose coefficients contain the unknown gains \(k_{1},k_{2},k_{3},k_{4}\), and you set the coefficients to equal each other, creating four different equations with four unknowns. By solving them simultaneously, you can find the \(k\) values.

\[ \det(A - BK - \lambda I) = 0 \]
Problem 1 · the gains are coupled

When you set the two quartics to equal each other, you see that multiple \(k_{1},k_{2},k_{3},k_{4}\) values sit in one coefficient, so changing only one of the four gains shifts the other coefficients, which shifts all four eigenvalues at once. Therefore the four gains cannot be treated as 4 independent dials — there is no single gain that will control a single eigenvalue, and so you cannot tune the controller by changing one gain and watching just one eigenvalue respond.

Problem 2 · it never says where to place them

The pole-placement method does not tell you where the four eigenvalues should be placed to make the robot behave well, as many different sets of negative eigenvalues all keep the robot stable. The behaviours you actually care about — how quickly the angle settles, how far the robot drifts along the floor, and how sensitive it is to sensor noise — don’t correspond neatly to individual eigenvalues either.

So designing a good controller this way becomes a process of trial and error: you guess a set of target eigenvalues, solve for the \(k\) values, simulate the result, and adjust. This gives no principled way of knowing whether the gains you finally settle on are the best ones possible, and also makes the process very time-intensive.

§09 · The Linear Quadratic Regulator

09 The Linear Quadratic Regulator

To fix the issues, we need to find another way to compute which stabilising gain \(k_{1},k_{2},k_{3},k_{4}\) is the best out of all the stabilising gains.

1 Scoring a controller with a cost function

So here we essentially try to compute a value that tells us how good the controller is — basically saying how good the \(k\) values are — where the lower the number, the better it is. There are two things that negatively impact the run:

  • The state being away from zero, as we want \(\theta\) and \(x\) to be as close to zero as possible — we want it to be upright, still, and in place.
  • Using a lot of control effort, because large motor forces drain the robot’s battery, can cause overheating, and the motors sometimes hit their physical limit, leading to harsh movements.

In order to create this scoring system, we need to be able to turn a vector into a single number value, and to do this we use the quadratic form. Given a vector \(X\) and a square matrix \(Q\), by calculating \(Qx\) and then \(x^{\mathsf{T}}(Qx)\) we get the following, which gives us a single value:

\[ X^{\mathsf{T}}QX = q_{1}x_{1}^{2} + q_{2}x_{2}^{2} + \cdots + q_{n}x_{n}^{2} \]

as a \(1 \times n\) row times an \(n \times n\) matrix times an \(n \times 1\) column gives a \(1 \times 1\) result. Now we can look at the LQR cost function, which is the following:

J\[ J = \int \left(x^{\mathsf{T}}Qx + u^{\mathsf{T}}Ru\right)dt \]

where the \(x^{\mathsf{T}}Qx\) is the state deviation and \(u^{\mathsf{T}}Ru\) is the control effort. Also, integration is used to sum up how bad the controller is over time. If the robot leans and moves for a long time, it will add up the badness from \(t=0\) to the infinite future.

2 What are Q and R?

We chose the matrices \(Q\) and \(R\), which are the only factors within the LQR control system that we choose, and everything else is done automatically.

  • For \(Q\), each diagonal entry \(q_{1},q_{2},q_{3},q_{4}\) is how much we care about each state being zero. For example, setting \(q_{3}\) as a large number means that you prioritise the tilt angle being zero and hate any tilt.
  • For \(R\), it is how much you care about saving control effort; the higher you set the value of \(R\), the more you are going easier on the robot’s motors.
  • Overall, only the ratio matters, as it is the balance between \(Q\) and \(R\) and is what determines how the control system works. A large \((Q/R)\) ratio means the control system will be fast, aggressive and effortful; a small \((Q/R)\) ratio means it will be gentle and slow.

3 The answer

Now, by minimising \(J\), we use the following equation to find what the optimal value of \(K\) is:

K\[ K = R^{-1}B^{\mathsf{T}}P \]

where the matrix \(P\) is the (symmetric, positive semi-definite) solution of the Continuous Algebraic Riccati Equation (CARE):

CARE\[ A^{\mathsf{T}}P + PA - PBR^{-1}B^{\mathsf{T}}P + Q = 0 \]

where all of \(A,B,R,Q\) are known, and you use the equation to solve for \(P\). There is a long derivation for this formula, and also a way to solve for \(P\); however, in our case:

  solve_care.py
import numpy as np
from scipy.linalg import solve_continuous_are

P = solve_continuous_are(A, B, Q, R)
§10 · How it works

10 How it works

Overall, to show how it works, I will lay out the processes the robot goes through for the LQR system.

Choose the physical parameters

The physical parameters are chosen, for example:

QuantitySymbolValue
Wheel & base mass\(M\)\(0.5\ \text{kg}\)
Body mass\(m\)\(0.5\ \text{kg}\)
Height of body centre of mass above the axle\(l\)\(0.15\ \text{m}\)
Body moment of inertia \(=\tfrac{1}{3}ml^{2}\)\(I\)\(0.00375\ \mathrm{kg\,m^2}\)
Gravity\(g\)\(9.81\ \mathrm{m/s^2}\)

And we also compute the value \(p\):

\[ p = I(M+m) + Mml^{2} = 0.00375(1.0) + (0.5)(0.5)(0.15)^{2} = 0.009375 \]

Compute the A and B matrices

Here we compute the A and B matrices:

\[ \frac{m^{2}gl^{2}}{p}=5.886, \quad \frac{mgl(M+m)}{p}=78.48, \quad \frac{I+ml^{2}}{p}=1.6, \quad \frac{ml}{p}=8.0 \]

So with these calculations, the A and B matrix is:

A \[ A = \begin{bmatrix} 0 & 1 & 0 & 0 \\ 0 & 0 & 5.886 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 78.48 & 0 \end{bmatrix} \]
B \[ B = \begin{bmatrix} 0 \\ 1.6 \\ 0 \\ 8.0 \end{bmatrix} \]

Check if it is unstable and controllable

In this step, we check if the robot is unstable and controllable, and to do this, we calculate the eigenvalues and use the controllability matrix. First, to check whether the robot is unstable, we compute the eigenvalues of \(A\) and ignore \(B\), since we are only looking at the robot’s state with no input. In order to find the eigenvalues of \(A\), we do \(\det(A - \lambda I) = 0\), which returns \(\lambda\) as:

\[ \lambda = 0, \quad +8.86, \quad -8.86 \]

The positive real part of the eigenvalue \(+8.86\) shows that the robot is naturally unstable. Then we use the controllability matrix \(\mathcal{C} = \begin{bmatrix} B & AB & A^{2}B & A^{3}B \end{bmatrix}\) and compute its rank, which returns a rank of 4, showing that the robot is able to steer all 4 states, so an LQR solution is guaranteed to exist.

Choose Q and R

Here we choose the values placed in the matrices \(Q\) and \(R\). For \(Q\), we care most about the tilt angle, as the robot falling is the main failure that we want to avoid, and we don’t care as much about the position and the rates. For \(R\), we set it to reflect that we are willing to expend a normal amount of motor effort.

Q \[ Q = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 10 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \]
R \[ R = 1 \]

So, essentially, we are saying we care 10 times more about the tilt angle than about all the other variables in the state vector.

Compute the optimal K values

Now compute the optimal \(K\) values. First, we use the Riccati solver to compute the matrix \(P\), and then \(K = R^{-1}B^{\mathsf{T}}P\) to return the \(K\) value, and in our case it will equal:

\[ K = \begin{bmatrix} -1.00 & -2.00 & 24.60 & 3.07 \end{bmatrix} \]

So, therefore, the motor command for each instant is:

\[ u = -Kx = -\big(-1.00\,x - 2.00\,\dot{x} + 24.60\,\theta + 3.07\,\dot{\theta}\big) \]

And by looking at the values, we can see that \(k_{3}\) is by far the largest, as expected, indicating that a small deviation in the robot’s tilt angle will produce the largest corrective force. \(k_{4}\) reacts to how quickly the robot is tipping, catching a fall early rather than waiting for the tilt angle to increase; without it, the robot would overshoot and oscillate. Finally, \(k_{1}\) and \(k_{2}\) are smaller and gently keep the robot from drifting away while it balances.

Check whether it is actually stable

This is the final step, where we check whether the robot is actually stable by computing the eigenvalues of \(A - BK\), which return:

\[ \lambda = -13.63, \quad -6.07, \quad -0.84 + 0.50\,i, \quad -0.84 - 0.50\,i \]

Since all the real parts of the eigenvalues are negative, the system is stable. This is because the real part of the eigenvalue represents the decay of the \(e^{\lambda t}\) term, and the imaginary part represents the oscillations. For example, looking at the eigenvalue \(-0.84 \pm 0.50\,i\): the real part is negative, so it will decay, but its magnitude is small, so it will decay slowly at around \(1/0.84 \approx 1.2\ \text{s}\); and the imaginary part means it oscillates at \(0.5\ \text{rad/s}\). Crucially, the decay time is much shorter than one oscillation period, so the motion dies away before the robot can complete one full swing, showing that it is well-damped: you will get roughly a single small overshoot which is then gone, rather than a sustained wobble.

Overall, putting the four eigenvalues together, the two fast eigenvalues \((-13.6\) and \(-6.1)\) snap the angle back quickly and handle most of the initial error, while the slow complex pair \((-0.84 \pm 0.50\,i)\) is what is left over and produces a gentle overshoot, followed by the slow final approach to rest.

Fig.05 · feedback drags the poles into the stable half-planes-PLANE
Re Im STABLE · Re < 0 UNSTABLE · Re > 0 feedback −BK +8.86 open loop −13.63 −6.07 −0.84 ± 0.5i

Fig.05 — the lone unstable pole at \(+8.86\) is the problem; choosing \(K\) relocates the closed-loop eigenvalues to \(-13.63,\,-6.07,\,-0.84\pm0.50i\), all safely in the stable half-plane.

Optimal gains
K
[−1, −2, 24.6, 3.07]
Dominant gain
24.6 k₃
tilt-angle term
Closed-loop λ
−13.6 max
all Re(λ) < 0
Result
Stable
well-damped
§11 · From maths to motion

11 Putting it into a robot

While the maths will compute \(K\) for us, the robot still needs to measure its 4 states many times per second, compute \(u = -Kx\), and convert it into a motor command. A balancing robot runs the same short loop, typically 100–500 times every second, forever:

\[ \text{sense} \;\rightarrow\; \text{estimate the state } x \;\rightarrow\; \text{compute } u=-Kx \;\rightarrow\; \text{drive motors} \;\rightarrow\; \text{repeat} \]
Fig.06 · the real-time control loop100–500 Hz
1 · Sense IMU + encoders 2 · Estimate state Kalman filter 3 · Compute u u = −Kx 4 · Drive motors force → PWM ↻ loop 100–500× / sec

Fig.06 — and the \(u\) value is the force. Then we convert the force into PWM, allowing us to control the motors and stabilise it.

That tight loop is what turns a page of linear algebra into a robot that refuses to fall over — which is the project this paper was written alongside.

See it in hardware Self-Balancing Desk Robot Coming soon
← back to index
SYSONLINE
SECTION
SCROLL000%
BUILDPORTFOLIO / 2026
LOCAL