|  |  | @ -5,7 +5,6 @@ import numpy as np | 
			
		
	
		
		
			
				
					
					|  |  |  | from casadi import SX, vertcat, sin, cos |  |  |  | from casadi import SX, vertcat, sin, cos | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | from common.realtime import sec_since_boot |  |  |  | from common.realtime import sec_since_boot | 
			
		
	
		
		
			
				
					
					|  |  |  | from selfdrive.controls.lib.drive_helpers import LAT_MPC_N as N |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | from selfdrive.modeld.constants import T_IDXS |  |  |  | from selfdrive.modeld.constants import T_IDXS | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | if __name__ == '__main__':  # generating code |  |  |  | if __name__ == '__main__':  # generating code | 
			
		
	
	
		
		
			
				
					|  |  | @ -18,6 +17,9 @@ EXPORT_DIR = os.path.join(LAT_MPC_DIR, "c_generated_code") | 
			
		
	
		
		
			
				
					
					|  |  |  | JSON_FILE = os.path.join(LAT_MPC_DIR, "acados_ocp_lat.json") |  |  |  | JSON_FILE = os.path.join(LAT_MPC_DIR, "acados_ocp_lat.json") | 
			
		
	
		
		
			
				
					
					|  |  |  | X_DIM = 4 |  |  |  | X_DIM = 4 | 
			
		
	
		
		
			
				
					
					|  |  |  | P_DIM = 2 |  |  |  | P_DIM = 2 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | N = 16 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | COST_E_DIM = 3 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | COST_DIM = COST_E_DIM + 1 | 
			
		
	
		
		
			
				
					
					|  |  |  | MODEL_NAME = 'lat' |  |  |  | MODEL_NAME = 'lat' | 
			
		
	
		
		
			
				
					
					|  |  |  | ACADOS_SOLVER_TYPE = 'SQP_RTI' |  |  |  | ACADOS_SOLVER_TYPE = 'SQP_RTI' | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -29,8 +31,8 @@ def gen_lat_model(): | 
			
		
	
		
		
			
				
					
					|  |  |  |   x_ego = SX.sym('x_ego') |  |  |  |   x_ego = SX.sym('x_ego') | 
			
		
	
		
		
			
				
					
					|  |  |  |   y_ego = SX.sym('y_ego') |  |  |  |   y_ego = SX.sym('y_ego') | 
			
		
	
		
		
			
				
					
					|  |  |  |   psi_ego = SX.sym('psi_ego') |  |  |  |   psi_ego = SX.sym('psi_ego') | 
			
		
	
		
		
			
				
					
					|  |  |  |   curv_ego = SX.sym('curv_ego') |  |  |  |   psi_rate_ego = SX.sym('psi_rate_ego') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   model.x = vertcat(x_ego, y_ego, psi_ego, curv_ego) |  |  |  |   model.x = vertcat(x_ego, y_ego, psi_ego, psi_rate_ego) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   # parameters |  |  |  |   # parameters | 
			
		
	
		
		
			
				
					
					|  |  |  |   v_ego = SX.sym('v_ego') |  |  |  |   v_ego = SX.sym('v_ego') | 
			
		
	
	
		
		
			
				
					|  |  | @ -38,22 +40,22 @@ def gen_lat_model(): | 
			
		
	
		
		
			
				
					
					|  |  |  |   model.p = vertcat(v_ego, rotation_radius) |  |  |  |   model.p = vertcat(v_ego, rotation_radius) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   # controls |  |  |  |   # controls | 
			
		
	
		
		
			
				
					
					|  |  |  |   curv_rate = SX.sym('curv_rate') |  |  |  |   psi_accel_ego = SX.sym('psi_accel_ego') | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   model.u = vertcat(curv_rate) |  |  |  |   model.u = vertcat(psi_accel_ego) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   # xdot |  |  |  |   # xdot | 
			
		
	
		
		
			
				
					
					|  |  |  |   x_ego_dot = SX.sym('x_ego_dot') |  |  |  |   x_ego_dot = SX.sym('x_ego_dot') | 
			
		
	
		
		
			
				
					
					|  |  |  |   y_ego_dot = SX.sym('y_ego_dot') |  |  |  |   y_ego_dot = SX.sym('y_ego_dot') | 
			
		
	
		
		
			
				
					
					|  |  |  |   psi_ego_dot = SX.sym('psi_ego_dot') |  |  |  |   psi_ego_dot = SX.sym('psi_ego_dot') | 
			
		
	
		
		
			
				
					
					|  |  |  |   curv_ego_dot = SX.sym('curv_ego_dot') |  |  |  |   psi_rate_ego_dot = SX.sym('psi_rate_ego_dot') | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   model.xdot = vertcat(x_ego_dot, y_ego_dot, psi_ego_dot, curv_ego_dot) |  |  |  |   model.xdot = vertcat(x_ego_dot, y_ego_dot, psi_ego_dot, psi_rate_ego_dot) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   # dynamics model |  |  |  |   # dynamics model | 
			
		
	
		
		
			
				
					
					|  |  |  |   f_expl = vertcat(v_ego * cos(psi_ego) - rotation_radius * sin(psi_ego) * (v_ego * curv_ego), |  |  |  |   f_expl = vertcat(v_ego * cos(psi_ego) - rotation_radius * sin(psi_ego) * psi_rate_ego, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                    v_ego * sin(psi_ego) + rotation_radius * cos(psi_ego) * (v_ego * curv_ego), |  |  |  |                    v_ego * sin(psi_ego) + rotation_radius * cos(psi_ego) * psi_rate_ego, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                    v_ego * curv_ego, |  |  |  |                    psi_rate_ego, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                    curv_rate) |  |  |  |                    psi_accel_ego) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   model.f_impl_expr = model.xdot - f_expl |  |  |  |   model.f_impl_expr = model.xdot - f_expl | 
			
		
	
		
		
			
				
					
					|  |  |  |   model.f_expl_expr = f_expl |  |  |  |   model.f_expl_expr = f_expl | 
			
		
	
		
		
			
				
					
					|  |  |  |   return model |  |  |  |   return model | 
			
		
	
	
		
		
			
				
					|  |  | @ -72,26 +74,28 @@ def gen_lat_ocp(): | 
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.cost.cost_type = 'NONLINEAR_LS' |  |  |  |   ocp.cost.cost_type = 'NONLINEAR_LS' | 
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.cost.cost_type_e = 'NONLINEAR_LS' |  |  |  |   ocp.cost.cost_type_e = 'NONLINEAR_LS' | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   Q = np.diag([0.0, 0.0]) |  |  |  |   Q = np.diag(np.zeros(COST_E_DIM)) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   QR = np.diag([0.0, 0.0, 0.0]) |  |  |  |   QR = np.diag(np.zeros(COST_DIM)) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.cost.W = QR |  |  |  |   ocp.cost.W = QR | 
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.cost.W_e = Q |  |  |  |   ocp.cost.W_e = Q | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   y_ego, psi_ego = ocp.model.x[1], ocp.model.x[2] |  |  |  |   y_ego, psi_ego, psi_rate_ego = ocp.model.x[1], ocp.model.x[2], ocp.model.x[3] | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   curv_rate = ocp.model.u[0] |  |  |  |   psi_rate_ego_dot = ocp.model.u[0] | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   v_ego = ocp.model.p[0] |  |  |  |   v_ego = ocp.model.p[0] | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.parameter_values = np.zeros((P_DIM, )) |  |  |  |   ocp.parameter_values = np.zeros((P_DIM, )) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.cost.yref = np.zeros((3, )) |  |  |  |   ocp.cost.yref = np.zeros((COST_DIM, )) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.cost.yref_e = np.zeros((2, )) |  |  |  |   ocp.cost.yref_e = np.zeros((COST_E_DIM, )) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   # TODO hacky weights to keep behavior the same |  |  |  |   # TODO hacky weights to keep behavior the same | 
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.model.cost_y_expr = vertcat(y_ego, |  |  |  |   ocp.model.cost_y_expr = vertcat(y_ego, | 
			
		
	
		
		
			
				
					
					|  |  |  |                                   ((v_ego +5.0) * psi_ego), |  |  |  |                                   ((v_ego + 5.0) * psi_ego), | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                   ((v_ego + 5.0) * 4.0 * curv_rate)) |  |  |  |                                   ((v_ego + 5.0) * psi_rate_ego), | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                   ((v_ego + 5.0) * psi_rate_ego_dot)) | 
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.model.cost_y_expr_e = vertcat(y_ego, |  |  |  |   ocp.model.cost_y_expr_e = vertcat(y_ego, | 
			
		
	
		
		
			
				
					
					|  |  |  |                                     ((v_ego +5.0) * psi_ego)) |  |  |  |                                   ((v_ego + 5.0) * psi_ego), | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                   ((v_ego + 5.0) * psi_rate_ego)) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   # set constraints |  |  |  |   # set constraints | 
			
		
	
		
		
			
				
					
					|  |  |  |   ocp.constraints.constr_type = 'BGH' |  |  |  |   ocp.constraints.constr_type = 'BGH' | 
			
		
	
	
		
		
			
				
					|  |  | @ -124,10 +128,10 @@ class LateralMpc(): | 
			
		
	
		
		
			
				
					
					|  |  |  |   def reset(self, x0=np.zeros(X_DIM)): |  |  |  |   def reset(self, x0=np.zeros(X_DIM)): | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.x_sol = np.zeros((N+1, X_DIM)) |  |  |  |     self.x_sol = np.zeros((N+1, X_DIM)) | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.u_sol = np.zeros((N, 1)) |  |  |  |     self.u_sol = np.zeros((N, 1)) | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.yref = np.zeros((N+1, 3)) |  |  |  |     self.yref = np.zeros((N+1, COST_DIM)) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     for i in range(N): |  |  |  |     for i in range(N): | 
			
		
	
		
		
			
				
					
					|  |  |  |       self.solver.cost_set(i, "yref", self.yref[i]) |  |  |  |       self.solver.cost_set(i, "yref", self.yref[i]) | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.solver.cost_set(N, "yref", self.yref[N][:2]) |  |  |  |     self.solver.cost_set(N, "yref", self.yref[N][:COST_E_DIM]) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     # Somehow needed for stable init |  |  |  |     # Somehow needed for stable init | 
			
		
	
		
		
			
				
					
					|  |  |  |     for i in range(N+1): |  |  |  |     for i in range(N+1): | 
			
		
	
	
		
		
			
				
					|  |  | @ -140,14 +144,13 @@ class LateralMpc(): | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.solve_time = 0.0 |  |  |  |     self.solve_time = 0.0 | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.cost = 0 |  |  |  |     self.cost = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def set_weights(self, path_weight, heading_weight, steer_rate_weight): |  |  |  |   def set_weights(self, path_weight, heading_weight, yaw_rate_weight, yaw_accel_cost): | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     W = np.asfortranarray(np.diag([path_weight, heading_weight, steer_rate_weight])) |  |  |  |     W = np.asfortranarray(np.diag([path_weight, heading_weight, yaw_rate_weight, yaw_accel_cost])) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     for i in range(N): |  |  |  |     for i in range(N): | 
			
		
	
		
		
			
				
					
					|  |  |  |       self.solver.cost_set(i, 'W', W) |  |  |  |       self.solver.cost_set(i, 'W', W) | 
			
		
	
		
		
			
				
					
					|  |  |  |     #TODO hacky weights to keep behavior the same |  |  |  |     self.solver.cost_set(N, 'W', W[:COST_E_DIM,:COST_E_DIM]) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     self.solver.cost_set(N, 'W', (3/20.)*W[:2,:2]) |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def run(self, x0, p, y_pts, heading_pts, curv_rate_pts): |  |  |  |   def run(self, x0, p, y_pts, heading_pts, yaw_rate_pts): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     x0_cp = np.copy(x0) |  |  |  |     x0_cp = np.copy(x0) | 
			
		
	
		
		
			
				
					
					|  |  |  |     p_cp = np.copy(p) |  |  |  |     p_cp = np.copy(p) | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.solver.constraints_set(0, "lbx", x0_cp) |  |  |  |     self.solver.constraints_set(0, "lbx", x0_cp) | 
			
		
	
	
		
		
			
				
					|  |  | @ -155,13 +158,13 @@ class LateralMpc(): | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.yref[:,0] = y_pts |  |  |  |     self.yref[:,0] = y_pts | 
			
		
	
		
		
			
				
					
					|  |  |  |     v_ego = p_cp[0] |  |  |  |     v_ego = p_cp[0] | 
			
		
	
		
		
			
				
					
					|  |  |  |     # rotation_radius = p_cp[1] |  |  |  |     # rotation_radius = p_cp[1] | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.yref[:,1] = heading_pts*(v_ego+5.0) |  |  |  |     self.yref[:,1] = heading_pts * (v_ego+5.0) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     self.yref[:,2] = curv_rate_pts * (v_ego+5.0) * 4.0 |  |  |  |     self.yref[:,2] = yaw_rate_pts * (v_ego+5.0) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     for i in range(N): |  |  |  |     for i in range(N): | 
			
		
	
		
		
			
				
					
					|  |  |  |       self.solver.cost_set(i, "yref", self.yref[i]) |  |  |  |       self.solver.cost_set(i, "yref", self.yref[i]) | 
			
		
	
		
		
			
				
					
					|  |  |  |       self.solver.set(i, "p", p_cp) |  |  |  |       self.solver.set(i, "p", p_cp) | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.solver.set(N, "p", p_cp) |  |  |  |     self.solver.set(N, "p", p_cp) | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.solver.cost_set(N, "yref", self.yref[N][:2]) |  |  |  |     self.solver.cost_set(N, "yref", self.yref[N][:COST_E_DIM]) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     t = sec_since_boot() |  |  |  |     t = sec_since_boot() | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.solution_status = self.solver.solve() |  |  |  |     self.solution_status = self.solver.solve() | 
			
		
	
	
		
		
			
				
					|  |  | 
 |