|
16 | 16 | import casadi as cs
|
17 | 17 | import cvxpy as cp
|
18 | 18 | import numpy as np
|
| 19 | +from acados_template import AcadosOcp, AcadosOcpSolver |
| 20 | +from acados_template.acados_model import AcadosModel |
19 | 21 | from pytope import Polytope
|
20 |
| -from scipy.linalg import solve_discrete_are, sqrtm |
| 22 | +from scipy.linalg import block_diag, solve_discrete_are, sqrtm |
21 | 23 |
|
22 | 24 | from safe_control_gym.controllers.mpc.mpc_utils import discretize_linear_system, rk_discrete
|
23 | 25 | from safe_control_gym.envs.benchmark_env import Environment, Task
|
@@ -821,7 +823,7 @@ def save(self, path):
|
821 | 823 | with open(path, 'wb') as f:
|
822 | 824 | pickle.dump(parameters, f)
|
823 | 825 |
|
824 |
| - def setup_optimizer(self): |
| 826 | + def setup_casadi_optimizer(self): |
825 | 827 | '''Setup the certifying MPC problem.'''
|
826 | 828 |
|
827 | 829 | # Horizon parameter.
|
@@ -935,3 +937,127 @@ def setup_optimizer(self):
|
935 | 937 | cost = cost + self.slack_cost * slack_term
|
936 | 938 | opti.minimize(cost)
|
937 | 939 | self.opti_dict['cost'] = cost
|
| 940 | + |
| 941 | + def setup_acados_optimizer(self): |
| 942 | + '''setup_optimizer_acados''' |
| 943 | + # create ocp object to formulate the OCP |
| 944 | + ocp = AcadosOcp() |
| 945 | + |
| 946 | + # Setup model |
| 947 | + model = AcadosModel() |
| 948 | + model.x = self.model.x_sym |
| 949 | + model.u = self.model.u_sym |
| 950 | + model.f_expl_expr = self.model.x_dot |
| 951 | + |
| 952 | + if self.env.NAME == Environment.CARTPOLE: |
| 953 | + x1_dot = cs.MX.sym('x1_dot') |
| 954 | + v_dot = cs.MX.sym('v_dot') |
| 955 | + theta1_dot = cs.MX.sym('theta1_dot') |
| 956 | + dtheta_dot = cs.MX.sym('dtheta_dot') |
| 957 | + xdot = cs.vertcat(x1_dot, v_dot, theta1_dot, dtheta_dot) |
| 958 | + elif self.env.NAME == Environment.QUADROTOR and self.env.QUAD_TYPE == 2: |
| 959 | + x1_dot = cs.MX.sym('x1_dot') |
| 960 | + vx_dot = cs.MX.sym('vx_dot') |
| 961 | + z1_dot = cs.MX.sym('z1_dot') |
| 962 | + vz_dot = cs.MX.sym('vz_dot') |
| 963 | + theta1_dot = cs.MX.sym('theta1_dot') |
| 964 | + dtheta_dot = cs.MX.sym('dtheta_dot') |
| 965 | + xdot = cs.vertcat(x1_dot, vx_dot, z1_dot, vz_dot, theta1_dot, dtheta_dot) |
| 966 | + else: |
| 967 | + x1_dot = cs.MX.sym('x1_dot') |
| 968 | + vx_dot = cs.MX.sym('vx_dot') |
| 969 | + y1_dot = cs.MX.sym('y1_dot') |
| 970 | + vy_dot = cs.MX.sym('vy_dot') |
| 971 | + z1_dot = cs.MX.sym('z1_dot') |
| 972 | + vz_dot = cs.MX.sym('vz_dot') |
| 973 | + phi1_dot = cs.MX.sym('phi1_dot') # Roll |
| 974 | + theta1_dot = cs.MX.sym('theta1_dot') # Pitch |
| 975 | + psi1_dot = cs.MX.sym('psi1_dot') # Yaw |
| 976 | + p1_body_dot = cs.MX.sym('p1_body_dot') # Body frame roll rate |
| 977 | + q1_body_dot = cs.MX.sym('q1_body_dot') # body frame pith rate |
| 978 | + r1_body_dot = cs.MX.sym('r1_body_dot') # body frame yaw rate |
| 979 | + xdot = cs.vertcat(x1_dot, vx_dot, y1_dot, vy_dot, z1_dot, vz_dot, phi1_dot, theta1_dot, psi1_dot, p1_body_dot, q1_body_dot, r1_body_dot) |
| 980 | + |
| 981 | + model.xdot = xdot |
| 982 | + model.f_impl_expr = model.xdot - model.f_expl_expr |
| 983 | + model.name = 'mpsf' |
| 984 | + ocp.model = model |
| 985 | + |
| 986 | + nx, nu = self.model.nx, self.model.nu |
| 987 | + ny = nx + nu |
| 988 | + |
| 989 | + ocp.dims.N = self.horizon |
| 990 | + |
| 991 | + # set cost module |
| 992 | + ocp.cost.cost_type = 'LINEAR_LS' |
| 993 | + ocp.cost.cost_type_e = 'LINEAR_LS' |
| 994 | + |
| 995 | + Q_mat = np.diag([0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1]) * 0 # .0001 |
| 996 | + ocp.cost.W_e = np.diag([0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1]) * 0.0001 |
| 997 | + R_mat = np.eye(nu) |
| 998 | + ocp.cost.W = block_diag(Q_mat, R_mat) |
| 999 | + |
| 1000 | + ocp.cost.Vx = np.zeros((ny, nx)) |
| 1001 | + ocp.cost.Vx[:nx, :] = np.eye(nx) |
| 1002 | + ocp.cost.Vu = np.zeros((ny, nu)) |
| 1003 | + ocp.cost.Vu[nx:nx + nu, :] = np.eye(nu) |
| 1004 | + ocp.cost.Vx_e = np.eye(nx) |
| 1005 | + |
| 1006 | + ocp.model.cost_y_expr = cs.vertcat(model.x, model.u) |
| 1007 | + ocp.model.cost_y_expr_e = model.x |
| 1008 | + |
| 1009 | + # Updated on each iteration |
| 1010 | + ocp.cost.yref = np.concatenate((self.model.X_EQ, self.model.U_EQ)) |
| 1011 | + ocp.cost.yref_e = self.model.X_EQ |
| 1012 | + |
| 1013 | + # set constraints |
| 1014 | + ocp.constraints.constr_type = 'BGH' |
| 1015 | + ocp.constraints.constr_type_e = 'BGH' |
| 1016 | + |
| 1017 | + ocp.constraints.x0 = self.model.X_EQ |
| 1018 | + ocp.constraints.C = self.L_x |
| 1019 | + ocp.constraints.D = self.L_u |
| 1020 | + ocp.constraints.lg = -1000 * np.ones((self.p)) |
| 1021 | + ocp.constraints.ug = np.zeros((self.p)) |
| 1022 | + |
| 1023 | + # Slack |
| 1024 | + ocp.constraints.Jsg = np.eye(self.p) |
| 1025 | + ocp.cost.Zu = 0.1 * np.array([self.slack_cost] * self.p) / self.p |
| 1026 | + ocp.cost.Zl = 0.1 * np.array([self.slack_cost] * self.p) / self.p |
| 1027 | + ocp.cost.zu = 0.1 * np.array([self.slack_cost] * self.p) / self.p |
| 1028 | + ocp.cost.zl = 0.1 * np.array([self.slack_cost] * self.p) / self.p |
| 1029 | + |
| 1030 | + # Options |
| 1031 | + ocp.solver_options.qp_solver = 'FULL_CONDENSING_HPIPM' |
| 1032 | + ocp.solver_options.hessian_approx = 'GAUSS_NEWTON' |
| 1033 | + ocp.solver_options.hpipm_mode = 'BALANCE' |
| 1034 | + ocp.solver_options.integrator_type = 'ERK' |
| 1035 | + # ocp.solver_options.sim_method_newton_iter = 3 |
| 1036 | + ocp.solver_options.nlp_solver_type = 'SQP_RTI' |
| 1037 | + ocp.solver_options.nlp_solver_max_iter = 10 |
| 1038 | + # ocp.solver_options.nlp_solver_step_length = 1.0 |
| 1039 | + |
| 1040 | + # set prediction horizon |
| 1041 | + ocp.solver_options.tf = self.dt * self.horizon |
| 1042 | + |
| 1043 | + solver_json = 'acados_ocp_cartpole.json' |
| 1044 | + ocp_solver = AcadosOcpSolver(ocp, json_file=solver_json) |
| 1045 | + |
| 1046 | + for stage in range(self.mpsc_cost_horizon): |
| 1047 | + ocp_solver.cost_set(stage, 'W', (self.cost_function.decay_factor**stage) * ocp.cost.W) |
| 1048 | + |
| 1049 | + for stage in range(self.mpsc_cost_horizon, self.horizon): |
| 1050 | + ocp_solver.cost_set(stage, 'W', 0.1 * ocp.cost.W) |
| 1051 | + |
| 1052 | + s_var = np.zeros((self.horizon + 1)) |
| 1053 | + g = np.zeros((self.horizon, self.p)) |
| 1054 | + |
| 1055 | + for i in range(self.horizon): |
| 1056 | + s_var[i + 1] = self.rho * s_var[i] + self.max_w |
| 1057 | + for j in range(self.p): |
| 1058 | + tighten_by = self.c_js[j] * s_var[i + 1] |
| 1059 | + g[i, j] = (self.l_xu[j] - tighten_by) |
| 1060 | + g[i, :] += (self.L_x @ self.X_mid) + (self.L_u @ self.U_mid) |
| 1061 | + ocp_solver.constraints_set(i, 'ug', g[i, :]) |
| 1062 | + |
| 1063 | + self.ocp_solver = ocp_solver |
0 commit comments