import pytest
import numpy as np
from openpilot . selfdrive . controls . lib . lateral_mpc_lib . lat_mpc import LateralMpc
from openpilot . selfdrive . controls . lib . drive_helpers import CAR_ROTATION_RADIUS
from openpilot . selfdrive . controls . lib . lateral_mpc_lib . lat_mpc import N as LAT_MPC_N
def run_mpc ( lat_mpc = None , v_ref = 30. , x_init = 0. , y_init = 0. , psi_init = 0. , curvature_init = 0. ,
lane_width = 3.6 , poly_shift = 0. ) :
if lat_mpc is None :
lat_mpc = LateralMpc ( )
lat_mpc . set_weights ( 1. , .1 , 0.0 , .05 , 800 )
y_pts = poly_shift * np . ones ( LAT_MPC_N + 1 )
heading_pts = np . zeros ( LAT_MPC_N + 1 )
curv_rate_pts = np . zeros ( LAT_MPC_N + 1 )
x0 = np . array ( [ x_init , y_init , psi_init , curvature_init ] )
p = np . column_stack ( [ v_ref * np . ones ( LAT_MPC_N + 1 ) ,
CAR_ROTATION_RADIUS * np . ones ( LAT_MPC_N + 1 ) ] )
# converge in no more than 10 iterations
for _ in range ( 10 ) :
lat_mpc . run ( x0 , p ,
y_pts , heading_pts , curv_rate_pts )
return lat_mpc . x_sol
class TestLateralMpc :
def _assert_null ( self , sol , curvature = 1e-6 ) :
for i in range ( len ( sol ) ) :
assert sol [ 0 , i , 1 ] == pytest . approx ( 0 , abs = curvature )
assert sol [ 0 , i , 2 ] == pytest . approx ( 0 , abs = curvature )
assert sol [ 0 , i , 3 ] == pytest . approx ( 0 , abs = curvature )
def _assert_simmetry ( self , sol , curvature = 1e-6 ) :
for i in range ( len ( sol ) ) :
assert sol [ 0 , i , 1 ] == pytest . approx ( - sol [ 1 , i , 1 ] , abs = curvature )
assert sol [ 0 , i , 2 ] == pytest . approx ( - sol [ 1 , i , 2 ] , abs = curvature )
assert sol [ 0 , i , 3 ] == pytest . approx ( - sol [ 1 , i , 3 ] , abs = curvature )
assert sol [ 0 , i , 0 ] == pytest . approx ( sol [ 1 , i , 0 ] , abs = curvature )
def test_straight ( self ) :
sol = run_mpc ( )
self . _assert_null ( np . array ( [ sol ] ) )
def test_y_symmetry ( self ) :
sol = [ ]
for y_init in [ - 0.5 , 0.5 ] :
sol . append ( run_mpc ( y_init = y_init ) )
self . _assert_simmetry ( np . array ( sol ) )
def test_poly_symmetry ( self ) :
sol = [ ]
for poly_shift in [ - 1. , 1. ] :
sol . append ( run_mpc ( poly_shift = poly_shift ) )
self . _assert_simmetry ( np . array ( sol ) )
def test_curvature_symmetry ( self ) :
sol = [ ]
for curvature_init in [ - 0.1 , 0.1 ] :
sol . append ( run_mpc ( curvature_init = curvature_init ) )
self . _assert_simmetry ( np . array ( sol ) )
def test_psi_symmetry ( self ) :
sol = [ ]
for psi_init in [ - 0.1 , 0.1 ] :
sol . append ( run_mpc ( psi_init = psi_init ) )
self . _assert_simmetry ( np . array ( sol ) )
def test_no_overshoot ( self ) :
y_init = 1.
sol = run_mpc ( y_init = y_init )
for y in list ( sol [ : , 1 ] ) :
assert y_init > = abs ( y )
def test_switch_convergence ( self ) :
lat_mpc = LateralMpc ( )
sol = run_mpc ( lat_mpc = lat_mpc , poly_shift = 3.0 , v_ref = 7.0 )
right_psi_deg = np . degrees ( sol [ : , 2 ] )
sol = run_mpc ( lat_mpc = lat_mpc , poly_shift = - 3.0 , v_ref = 7.0 )
left_psi_deg = np . degrees ( sol [ : , 2 ] )
np . testing . assert_almost_equal ( right_psi_deg , - left_psi_deg , decimal = 3 )