cvxgrp / cvxpygen

Code generation with CVXPY

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to implement the LTV MPC in the CVXPYGEN

brilianputraa opened this issue · comments

Hi, first of all, sorry for creating this on the issue section, I think rather than an issue this should be a discussion.

I implemented the LTV-MPC with CVXPY, and I have the intention to generate the code using CVXPYGEN for deploying the program to the real hardware.

In the CVXPY we can do for loop to assign the constraints of the LTV system for each horizon

# My program with CVXPY
for t in range(self.N - 1):
      cost += cp.quad_form(self.u[:, t], R)
  
      if t != 0:
          cost += cp.quad_form(xref[:, t] - self.x[:, t], Q)
  
      self.A, self.B, self.C = self.get_linear_model(
          xbar[2, t], xbar[3, t], dref[0, t])
      constraints += [self.x[:, t + 1] == self.A @ self.x[:, t] + self.B @ self.u[:, t] + self.C]
  
      if t < (self.N - 2):
          cost += cp.quad_form(self.u[:, t + 1] - self.u[:, t], Rd)
          constraints += [cp.abs(self.u[1, t + 1] - self.u[1, t]) <=
                          self.MAX_ACT * self.DT]

Nevertheless, I encounter a problem in which I am having difficulties converting my optimization problem to DDP Compliant.

Let's say we have an objective function like this

image

I have tried to look into the example of MPC with CVXPYGEN but it is only for the LTI MPC, I am wondering how to change the for loop like my code above to assign each constraint to match the DDP Compliant in the CVXPYGEN

Thanks!

The two issues I see are the quad_forms and possibly self.MAX_ACT * self.DT if these are both parameters.

Take a look at this for more info: https://www.cvxpy.org/tutorial/advanced/index.html#the-dpp-ruleset

Okay thanks, now I get it after reading the tutorial you provided

By the way sorry again for replying to my closed issue, when I take a look into the MPC examples of CVXPYGEN, I think I found an indexing issue in the objective function. The DDP objective function of the MPC is such as this:

$$\begin{equation} \begin{array}{ll} \text{minimize} \quad & \Vert P^{1/2} X_{:,H} \Vert_2^2 + \Vert Q^{1/2} X_{:,0:H-1} \Vert_F^2 + \Vert R^{1/2} U \Vert_F^2\\ \text{subject to} \quad &X_{:,1:H} = A X_{:,0:H-1} + B U \\ & | U | \leq \mathbb{1} \\ & X_{:,0} = x_\mathrm{init}, \\ \end{array} \end{equation}$$

In the example, it is written as:
objective = cp.Minimize(cp.sum_squares(Psqrt@X[:,H-1]) + cp.sum_squares(Qsqrt@X[:,:H]) + cp.sum_squares(Rsqrt@U))

To the best of my knowledge, Psqrt is the weight for a terminal cost which should be at the H index instead of H-1, because Python index starts from 0, so the H-1 index implies that it is located at the previous index before the final index (H) with the assumption that the prediction horizon length is H+1. For the stage cost it is already correct because it starts from index 0...H-1. So I believe the final/terminal cost should be written as below:

objective = cp.Minimize(cp.sum_squares(Psqrt@X[:,H]) + cp.sum_squares(Qsqrt@X[:,:H]) + cp.sum_squares(Rsqrt@U))

Thanks!

Well spotted! I just updated MPC.ipynb