blob: b7110fe2cf4cb956e2b59888e24087e855a264b8 [file] [log] [blame]
\documentclass[a4paper,12pt]{article}
\usepackage{amsmath}
\usepackage{graphicx}
\begin{document}
TODO(austin): Now that the python matches the original problem and solves, confirm the paper matches what got implemented.
osqp!
\section{Catapult MPC}
We want to phrase our problem as trying to solve for the set of control inputs
which get us closest to the destination, but minimizes acceleration.
Specifically, we want to minimize acceleration close to the end.
We also have a voltage limit.
Our model is
\begin{equation}
\label{cost}
\begin{bmatrix} x_1 \\ v_1 \end{bmatrix} =
\begin{bmatrix} a_{00} & a_{01} \\ 0 & a_{11} \end{bmatrix}
\begin{bmatrix} x_0 \\ v_0 \end{bmatrix} +
\begin{bmatrix} b_{0} \\ b_{1} \end{bmatrix} \begin{bmatrix} u_0 \end{bmatrix}
\end{equation}
Our acceleration can be measured as:
\begin{equation}
\label{accel}
\frac{ \left( \boldsymbol{X_1(1)} - \boldsymbol{X_1(0)} \right)}{\Delta t}
\end{equation}
This simplifies to:
\begin{equation}
\frac{a_{11} v_0 + b_1 u_0 - v_0}{\Delta t}
\end{equation}
and finally
\begin{equation}
\frac{(a_{11} - 1) v_0 + b_1 u_0}{\Delta t}
\end{equation}
We can also compute our state matrix as a function of inital state and the control inputs.
\begin{equation}
\label{all_x}
\begin{bmatrix} X_1 \\ X_2 \\ X_3 \\ \vdots \end{bmatrix} =
\begin{bmatrix} A \\
A^2 \\
A^3 \\
\vdots \end{bmatrix}
X_0 +
\begin{bmatrix} B & 0 & 0 & 0 \\
A B & B & 0 & 0 \\
A^2 B & A B & B & 0 \\
\vdots & \ddots & & \hdots \end{bmatrix}
\begin{bmatrix} U_0 \\ U_1 \\ U_2 \\ \vdots \end{bmatrix}
\end{equation}
\section{MPC problem formulation}
We want to penalize both final state and intermediate acceleration.
\begin{equation}
C = \sum_{n=0}^{39} \frac{\left(v(n + 1) - v(n)\right)^2}{\Delta t} \pi_n + (X_{40} - X_{final})^T Q_{final} (X_{40} - X_{final})
\end{equation}
where $\pi_n$ is a constant only dependent on $n$, and designed such that it depends on the distance to the end of the sequence, not the distance from the start.
In order to use OSQP, which has a code generator, we need to get this into the form of
\begin{tabular}{ l l }
minimize & $ \frac{1}{2} X^T P X + q^T X $ \\
subject to & $ l <= A X <= u $ \\
\end{tabular}
This is the simplest form of a constrained quadratic program that we can solve efficiently.
Luckily for us, the problem statement above fits that definition.
\section{Manipulating the formulation}
We need to separate constant factors from things dependent on U (or X in OSQP parlance) so we can create these matrices easier.
\subsection{Terminal cost}
Next step is to compute $X_{40}$ using equation \ref{all_x}.
We can do this by only computing the final row of the matrix.
\begin{equation}
\label{x40}
X_{40} = \begin{bmatrix} A^{39} B & A^{38} B & \hdots & B \end{bmatrix}
\begin{bmatrix} U_0 \\
\vdots \\
U_{39}
\end{bmatrix} + A^{40} X_0 = B_f \boldsymbol{U} + A^{40} X_0
\end{equation}
We can substitute equation \ref{x40} into equation \ref{cost}.
\begin{equation}
\label{final_cost}
\begin{aligned}[t]
C_f = & \boldsymbol{U}^T B_f^T Q_{final} B_f \boldsymbol{U} \\
& + 2 (A^{40} X_0 - X_{final})^T Q_{final} B_f \boldsymbol{U} \\
& + (A^{40} X_0 - X_{final})^T Q_{final} (A^{40} X_0 - X_{final})
\end{aligned}
\end{equation}
\subsection{Acceleration costs}
We can compute a velocity matrix for all the times by stripping out the positions from equation \ref{all_x} by using every other row.
We can use this to then compute the accelerations for each time slice and then penalize them.
\begin{equation}
\begin{bmatrix} v_1 \\ v_2 \\ \vdots \\ v_{40} \end{bmatrix} =
M \boldsymbol{U} + \begin{bmatrix} a_{11} \\ a^2_{11} \\ \vdots \\ a^{40}_{11} \end{bmatrix} v_0 =
M \boldsymbol{U} + m v_0
\end{equation}
We can then use equation \ref{accel} in matrix form to convert a velocity matrix to an acceleration matrix.
\begin{equation}
\begin{bmatrix} \alpha_1 \\ \alpha_2 \\ \alpha_3 \\ \vdots \\ \alpha_{40} \end{bmatrix} =
\frac{1}{\Delta t} \left(
\begin{bmatrix} 1 & 0 & 0 & \hdots & 0 \\
-1 & 1 & 0 & \hdots & 0 \\
0 & -1 & 1 & \hdots & 0 \\
\vdots & & & \ddots & \vdots \\
0 & 0 & \hdots & -1 & 1 \\
\end{bmatrix}
\begin{bmatrix} v_1 \\ v_2 \\ \vdots \\ v_{40} \end{bmatrix} - \begin{bmatrix} v_0 \\ 0 \\ \vdots \\ 0 \end{bmatrix}
\right)
\end{equation}
We can pull some of these terms out to make it easier to work with.
\begin{equation}
\boldsymbol{\alpha} = W V + w v_0
\end{equation}
Our acceleration cost function is then:
\begin{equation}
C_a = \boldsymbol{\alpha}^T
\begin{bmatrix} \pi_1 & & 0 \\
& \pi_2 & \\
0 & & \ddots \end{bmatrix} \boldsymbol{\alpha} =
\boldsymbol{\alpha}^T \Pi \boldsymbol{\alpha}
\end{equation}
We can substitute everything in to get something as a function of $U$.
\begin{equation}
C_a = \left(W \left(M \boldsymbol{U} + m v_0 \right) + w v_0 \right)^T \Pi \left(W \left(M \boldsymbol{U} + m v_0 \right) + w v_0 \right)
\end{equation}
And then simplify this down into the expected form.
\begin{equation}
C_a = \left(W M \boldsymbol{U} + (W m + w) v_0 \right)^T \Pi \left(W M \boldsymbol{U} + (W m + w) v_0 \right)
\end{equation}
\begin{equation}
\label{accel_cost}
\begin{aligned}[t]
C_a = & \boldsymbol{U}^T M^T W^T \Pi W M \boldsymbol{U} \\
& + 2 v_0 (W m + w)^T \Pi W M \boldsymbol{U} \\
& + v_0 (W m + w)^T \Pi \left(W m + w \right) v_0
\end{aligned}
\end{equation}
\subsection{Overall cost}
We can combine equations \ref{final_cost} and \ref{accel_cost} to get our overall cost in the correct form.
\begin{equation}
\begin{aligned}[t]
C &= \boldsymbol{U}^T \left( M^T W^T \Pi W M + B_f^T Q_{final} B_f \right) \boldsymbol{U} \\
&+ \left(2 v_0 (W m + w)^T \Pi W M
- 2 X_{final}^T Q_{final} B_f
\right) \boldsymbol{U} \\
& + X_{final}^T Q_{final} X_{final}
+ v_0 (W m + w)^T \Pi \left(W m + w \right) v_0
\end{aligned}
\end{equation}
\section{Response}
For a reasonable request (11 m/s after 90 degrees), we get the following response
\begin{figure}
\centering
\includegraphics[width=\linewidth]{response.png}
\end{figure}
This is well within 1\% error, and avoid saturation and keeps the acceleration down at the end.
\end{document}