import math
from cereal import car
from common . conversions import Conversions as CV
from common . numpy_fast import clip , interp
from common . realtime import DT_MDL
from selfdrive . modeld . constants import T_IDXS
# WARNING: this value was determined based on the model's training distribution,
# model predictions above this speed can be unpredictable
V_CRUISE_MAX = 145 # kph
V_CRUISE_MIN = 8 # kph
V_CRUISE_ENABLE_MIN = 40 # kph
LAT_MPC_N = 16
LON_MPC_N = 32
CONTROL_N = 17
CAR_ROTATION_RADIUS = 0.0
# EU guidelines
MAX_LATERAL_JERK = 5.0
ButtonType = car . CarState . ButtonEvent . Type
CRUISE_LONG_PRESS = 50
CRUISE_NEAREST_FUNC = {
ButtonType . accelCruise : math . ceil ,
ButtonType . decelCruise : math . floor ,
}
CRUISE_INTERVAL_SIGN = {
ButtonType . accelCruise : + 1 ,
ButtonType . decelCruise : - 1 ,
}
class MPC_COST_LAT :
PATH = 1.0
HEADING = 1.0
STEER_RATE = 1.0
def rate_limit ( new_value , last_value , dw_step , up_step ) :
return clip ( new_value , last_value + dw_step , last_value + up_step )
def update_v_cruise ( v_cruise_kph , v_ego , gas_pressed , buttonEvents , button_timers , enabled , metric ) :
# handle button presses. TODO: this should be in state_control, but a decelCruise press
# would have the effect of both enabling and changing speed is checked after the state transition
if not enabled :
return v_cruise_kph
long_press = False
button_type = None
# should be CV.MPH_TO_KPH, but this causes rounding errors
v_cruise_delta = 1. if metric else 1.6
for b in buttonEvents :
if b . type . raw in button_timers and not b . pressed :
if button_timers [ b . type . raw ] > CRUISE_LONG_PRESS :
return v_cruise_kph # end long press
button_type = b . type . raw
break
else :
for k in button_timers . keys ( ) :
if button_timers [ k ] and button_timers [ k ] % CRUISE_LONG_PRESS == 0 :
button_type = k
long_press = True
break
if button_type :
v_cruise_delta = v_cruise_delta * ( 5 if long_press else 1 )
if long_press and v_cruise_kph % v_cruise_delta != 0 : # partial interval
v_cruise_kph = CRUISE_NEAREST_FUNC [ button_type ] ( v_cruise_kph / v_cruise_delta ) * v_cruise_delta
else :
v_cruise_kph + = v_cruise_delta * CRUISE_INTERVAL_SIGN [ button_type ]
# If set is pressed while overriding, clip cruise speed to minimum of vEgo
if gas_pressed and button_type in ( ButtonType . decelCruise , ButtonType . setCruise ) :
v_cruise_kph = max ( v_cruise_kph , v_ego * CV . MS_TO_KPH )
v_cruise_kph = clip ( round ( v_cruise_kph , 1 ) , V_CRUISE_MIN , V_CRUISE_MAX )
return v_cruise_kph
def initialize_v_cruise ( v_ego , buttonEvents , v_cruise_last ) :
for b in buttonEvents :
# 250kph or above probably means we never had a set speed
if b . type in ( ButtonType . accelCruise , ButtonType . resumeCruise ) and v_cruise_last < 250 :
return v_cruise_last
return int ( round ( clip ( v_ego * CV . MS_TO_KPH , V_CRUISE_ENABLE_MIN , V_CRUISE_MAX ) ) )
def get_lag_adjusted_curvature ( CP , v_ego , psis , curvatures , curvature_rates ) :
if len ( psis ) != CONTROL_N :
psis = [ 0.0 ] * CONTROL_N
curvatures = [ 0.0 ] * CONTROL_N
curvature_rates = [ 0.0 ] * CONTROL_N
# TODO this needs more thought, use .2s extra for now to estimate other delays
delay = CP . steerActuatorDelay + .2
current_curvature = curvatures [ 0 ]
psi = interp ( delay , T_IDXS [ : CONTROL_N ] , psis )
desired_curvature_rate = curvature_rates [ 0 ]
# MPC can plan to turn the wheel and turn back before t_delay. This means
# in high delay cases some corrections never even get commanded. So just use
# psi to calculate a simple linearization of desired curvature
curvature_diff_from_psi = psi / ( max ( v_ego , 1e-1 ) * delay ) - current_curvature
desired_curvature = current_curvature + 2 * curvature_diff_from_psi
v_ego = max ( v_ego , 0.1 )
max_curvature_rate = MAX_LATERAL_JERK / ( v_ego * * 2 )
safe_desired_curvature_rate = clip ( desired_curvature_rate ,
- max_curvature_rate ,
max_curvature_rate )
safe_desired_curvature = clip ( desired_curvature ,
current_curvature - max_curvature_rate * DT_MDL ,
current_curvature + max_curvature_rate * DT_MDL )
return safe_desired_curvature , safe_desired_curvature_rate