import unittest
import numpy as np
from cereal import log
import cereal . messaging as messaging
from selfdrive . config import Conversions as CV
from selfdrive . controls . lib . planner import calc_cruise_accel_limits
from selfdrive . controls . lib . speed_smoother import speed_smoother
from selfdrive . controls . lib . long_mpc import LongitudinalMpc
def RW ( v_ego , v_l ) :
TR = 1.8
G = 9.81
return ( v_ego * TR - ( v_l - v_ego ) * TR + v_ego * v_ego / ( 2 * G ) - v_l * v_l / ( 2 * G ) )
class FakePubMaster ( ) :
def send ( self , s , data ) :
assert data
def run_following_distance_simulation ( v_lead , t_end = 200.0 ) :
dt = 0.2
t = 0.
x_lead = 200.0
x_ego = 0.0
v_ego = v_lead
a_ego = 0.0
v_cruise_setpoint = v_lead + 10.
pm = FakePubMaster ( )
mpc = LongitudinalMpc ( 1 )
first = True
while t < t_end :
# Run cruise control
accel_limits = [ float ( x ) for x in calc_cruise_accel_limits ( v_ego , False ) ]
jerk_limits = [ min ( - 0.1 , accel_limits [ 0 ] ) , max ( 0.1 , accel_limits [ 1 ] ) ]
v_cruise , a_cruise = speed_smoother ( v_ego , a_ego , v_cruise_setpoint ,
accel_limits [ 1 ] , accel_limits [ 0 ] ,
jerk_limits [ 1 ] , jerk_limits [ 0 ] ,
dt )
# Setup CarState
CS = messaging . new_message ( )
CS . init ( ' carState ' )
CS . carState . vEgo = v_ego
CS . carState . aEgo = a_ego
# Setup lead packet
lead = log . RadarState . LeadData . new_message ( )
lead . status = True
lead . dRel = x_lead - x_ego
lead . vLead = v_lead
lead . aLeadK = 0.0
# Run MPC
mpc . set_cur_state ( v_ego , a_ego )
if first : # Make sure MPC is converged on first timestep
for _ in range ( 20 ) :
mpc . update ( pm , CS . carState , lead , v_cruise_setpoint )
mpc . update ( pm , CS . carState , lead , v_cruise_setpoint )
# Choose slowest of two solutions
if v_cruise < mpc . v_mpc :
v_ego , a_ego = v_cruise , a_cruise
else :
v_ego , a_ego = mpc . v_mpc , mpc . a_mpc
# Update state
x_lead + = v_lead * dt
x_ego + = v_ego * dt
t + = dt
first = False
return x_lead - x_ego
class TestFollowingDistance ( unittest . TestCase ) :
def test_following_distanc ( self ) :
for speed_mph in np . linspace ( 10 , 100 , num = 10 ) :
v_lead = float ( speed_mph * CV . MPH_TO_MS )
simulation_steady_state = run_following_distance_simulation ( v_lead )
correct_steady_state = RW ( v_lead , v_lead ) + 4.0
self . assertAlmostEqual ( simulation_steady_state , correct_steady_state , delta = 0.1 )