|  |  | @ -1,12 +1,10 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | import unittest |  |  |  | import unittest | 
			
		
	
		
		
			
				
					
					|  |  |  | import numpy as np |  |  |  | import numpy as np | 
			
		
	
		
		
			
				
					
					|  |  |  | from selfdrive.car.honda.interface import CarInterface |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | from selfdrive.controls.lib.lateral_mpc import libmpc_py |  |  |  | from selfdrive.controls.lib.lateral_mpc import libmpc_py | 
			
		
	
		
		
			
				
					
					|  |  |  | from selfdrive.controls.lib.vehicle_model import VehicleModel |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | from selfdrive.controls.lib.drive_helpers import MPC_N, CAR_ROTATION_RADIUS |  |  |  | from selfdrive.controls.lib.drive_helpers import MPC_N, CAR_ROTATION_RADIUS | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | def run_mpc(v_ref=30., x_init=0., y_init=0., psi_init=0., tire_angle_init=0., |  |  |  | def run_mpc(v_ref=30., x_init=0., y_init=0., psi_init=0., curvature_init=0., | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             lane_width=3.6, poly_shift=0.): |  |  |  |             lane_width=3.6, poly_shift=0.): | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   libmpc = libmpc_py.libmpc |  |  |  |   libmpc = libmpc_py.libmpc | 
			
		
	
	
		
		
			
				
					|  |  | @ -17,21 +15,17 @@ def run_mpc(v_ref=30., x_init=0., y_init=0., psi_init=0., tire_angle_init=0., | 
			
		
	
		
		
			
				
					
					|  |  |  |   y_pts = poly_shift * np.ones(MPC_N + 1) |  |  |  |   y_pts = poly_shift * np.ones(MPC_N + 1) | 
			
		
	
		
		
			
				
					
					|  |  |  |   heading_pts = np.zeros(MPC_N + 1) |  |  |  |   heading_pts = np.zeros(MPC_N + 1) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   CP = CarInterface.get_params("HONDA CIVIC 2016 TOURING") |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   VM = VehicleModel(CP) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   curvature_factor = VM.curvature_factor(v_ref) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   cur_state = libmpc_py.ffi.new("state_t *") |  |  |  |   cur_state = libmpc_py.ffi.new("state_t *") | 
			
		
	
		
		
			
				
					
					|  |  |  |   cur_state.x = x_init |  |  |  |   cur_state.x = x_init | 
			
		
	
		
		
			
				
					
					|  |  |  |   cur_state.y = y_init |  |  |  |   cur_state.y = y_init | 
			
		
	
		
		
			
				
					
					|  |  |  |   cur_state.psi = psi_init |  |  |  |   cur_state.psi = psi_init | 
			
		
	
		
		
			
				
					
					|  |  |  |   cur_state.tire_angle = tire_angle_init |  |  |  |   cur_state.curvature = curvature_init | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   # converge in no more than 20 iterations |  |  |  |   # converge in no more than 20 iterations | 
			
		
	
		
		
			
				
					
					|  |  |  |   for _ in range(20): |  |  |  |   for _ in range(20): | 
			
		
	
		
		
			
				
					
					|  |  |  |     libmpc.run_mpc(cur_state, mpc_solution, v_ref, |  |  |  |     libmpc.run_mpc(cur_state, mpc_solution, v_ref, | 
			
		
	
		
		
			
				
					
					|  |  |  |                    curvature_factor, CAR_ROTATION_RADIUS, |  |  |  |                    CAR_ROTATION_RADIUS, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                    list(y_pts), list(heading_pts)) |  |  |  |                    list(y_pts), list(heading_pts)) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   return mpc_solution |  |  |  |   return mpc_solution | 
			
		
	
	
		
		
			
				
					|  |  | @ -39,26 +33,26 @@ def run_mpc(v_ref=30., x_init=0., y_init=0., psi_init=0., tire_angle_init=0., | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | class TestLateralMpc(unittest.TestCase): |  |  |  | class TestLateralMpc(unittest.TestCase): | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def _assert_null(self, sol, tire_angle=1e-6): |  |  |  |   def _assert_null(self, sol, curvature=1e-6): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     for i in range(len(sol[0].y)): |  |  |  |     for i in range(len(sol[0].y)): | 
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0].y[i], 0., delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0].y[i], 0., delta=curvature) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0].psi[i], 0., delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0].psi[i], 0., delta=curvature) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0].tire_angle[i], 0., delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0].curvature[i], 0., delta=curvature) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def _assert_simmetry(self, sol, tire_angle=1e-6): |  |  |  |   def _assert_simmetry(self, sol, curvature=1e-6): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     for i in range(len(sol[0][0].y)): |  |  |  |     for i in range(len(sol[0][0].y)): | 
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0][0].y[i], -sol[1][0].y[i], delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0][0].y[i], -sol[1][0].y[i], delta=curvature) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0][0].psi[i], -sol[1][0].psi[i], delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0][0].psi[i], -sol[1][0].psi[i], delta=curvature) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0][0].tire_angle[i], -sol[1][0].tire_angle[i], delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0][0].curvature[i], -sol[1][0].curvature[i], delta=curvature) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0][0].x[i], sol[1][0].x[i], delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0][0].x[i], sol[1][0].x[i], delta=curvature) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def _assert_identity(self, sol, ignore_y=False, tire_angle=1e-6): |  |  |  |   def _assert_identity(self, sol, ignore_y=False, curvature=1e-6): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     for i in range(len(sol[0][0].y)): |  |  |  |     for i in range(len(sol[0][0].y)): | 
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0][0].psi[i], sol[1][0].psi[i], delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0][0].psi[i], sol[1][0].psi[i], delta=curvature) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0][0].tire_angle[i], sol[1][0].tire_angle[i], delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0][0].curvature[i], sol[1][0].curvature[i], delta=curvature) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       self.assertAlmostEqual(sol[0][0].x[i], sol[1][0].x[i], delta=tire_angle) |  |  |  |       self.assertAlmostEqual(sol[0][0].x[i], sol[1][0].x[i], delta=curvature) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       if not ignore_y: |  |  |  |       if not ignore_y: | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.assertAlmostEqual(sol[0][0].y[i], sol[1][0].y[i], delta=tire_angle) |  |  |  |         self.assertAlmostEqual(sol[0][0].y[i], sol[1][0].y[i], delta=curvature) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def test_straight(self): |  |  |  |   def test_straight(self): | 
			
		
	
		
		
			
				
					
					|  |  |  |     sol = run_mpc() |  |  |  |     sol = run_mpc() | 
			
		
	
	
		
		
			
				
					|  |  | @ -76,10 +70,10 @@ class TestLateralMpc(unittest.TestCase): | 
			
		
	
		
		
			
				
					
					|  |  |  |       sol.append(run_mpc(poly_shift=poly_shift)) |  |  |  |       sol.append(run_mpc(poly_shift=poly_shift)) | 
			
		
	
		
		
			
				
					
					|  |  |  |     self._assert_simmetry(sol) |  |  |  |     self._assert_simmetry(sol) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def test_tire_angle_symmetry(self): |  |  |  |   def test_curvature_symmetry(self): | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     sol = [] |  |  |  |     sol = [] | 
			
		
	
		
		
			
				
					
					|  |  |  |     for tire_angle_init in [-0.1, 0.1]: |  |  |  |     for curvature_init in [-0.1, 0.1]: | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       sol.append(run_mpc(tire_angle_init=tire_angle_init)) |  |  |  |       sol.append(run_mpc(curvature_init=curvature_init)) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     self._assert_simmetry(sol) |  |  |  |     self._assert_simmetry(sol) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def test_psi_symmetry(self): |  |  |  |   def test_psi_symmetry(self): | 
			
		
	
	
		
		
			
				
					|  |  | @ -93,9 +87,9 @@ class TestLateralMpc(unittest.TestCase): | 
			
		
	
		
		
			
				
					
					|  |  |  |     sol = [] |  |  |  |     sol = [] | 
			
		
	
		
		
			
				
					
					|  |  |  |     sol.append(run_mpc(y_init=shift)) |  |  |  |     sol.append(run_mpc(y_init=shift)) | 
			
		
	
		
		
			
				
					
					|  |  |  |     sol.append(run_mpc(poly_shift=-shift)) |  |  |  |     sol.append(run_mpc(poly_shift=-shift)) | 
			
		
	
		
		
			
				
					
					|  |  |  |     # need larger tire_angle than standard, otherwise it false triggers. |  |  |  |     # need larger curvature than standard, otherwise it false triggers. | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     # this is acceptable because the 2 cases are very different from the optimizer standpoint |  |  |  |     # this is acceptable because the 2 cases are very different from the optimizer standpoint | 
			
		
	
		
		
			
				
					
					|  |  |  |     self._assert_identity(sol, ignore_y=True, tire_angle=1e-5) |  |  |  |     self._assert_identity(sol, ignore_y=True, curvature=1e-5) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   def test_no_overshoot(self): |  |  |  |   def test_no_overshoot(self): | 
			
		
	
		
		
			
				
					
					|  |  |  |     y_init = 1. |  |  |  |     y_init = 1. | 
			
		
	
	
		
		
			
				
					|  |  | 
 |