import math
import numpy as np
from cereal import log
from common . filter_simple import FirstOrderFilter
from common . numpy_fast import clip , interp
from common . realtime import DT_CTRL
from selfdrive . controls . lib . latcontrol import LatControl , MIN_STEER_SPEED
class LatControlINDI ( LatControl ) :
def __init__ ( self , CP , CI ) :
super ( ) . __init__ ( CP , CI )
self . angle_steers_des = 0.
A = np . array ( [ [ 1.0 , DT_CTRL , 0.0 ] ,
[ 0.0 , 1.0 , DT_CTRL ] ,
[ 0.0 , 0.0 , 1.0 ] ] )
C = np . array ( [ [ 1.0 , 0.0 , 0.0 ] ,
[ 0.0 , 1.0 , 0.0 ] ] )
# Q = np.matrix([[1e-2, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 10.0]])
# R = np.matrix([[1e-2, 0.0], [0.0, 1e3]])
# (x, l, K) = control.dare(np.transpose(A), np.transpose(C), Q, R)
# K = np.transpose(K)
K = np . array ( [ [ 7.30262179e-01 , 2.07003658e-04 ] ,
[ 7.29394177e+00 , 1.39159419e-02 ] ,
[ 1.71022442e+01 , 3.38495381e-02 ] ] )
self . speed = 0.
self . K = K
self . A_K = A - np . dot ( K , C )
self . x = np . array ( [ [ 0. ] , [ 0. ] , [ 0. ] ] )
self . _RC = ( CP . lateralTuning . indi . timeConstantBP , CP . lateralTuning . indi . timeConstantV )
self . _G = ( CP . lateralTuning . indi . actuatorEffectivenessBP , CP . lateralTuning . indi . actuatorEffectivenessV )
self . _outer_loop_gain = ( CP . lateralTuning . indi . outerLoopGainBP , CP . lateralTuning . indi . outerLoopGainV )
self . _inner_loop_gain = ( CP . lateralTuning . indi . innerLoopGainBP , CP . lateralTuning . indi . innerLoopGainV )
self . steer_filter = FirstOrderFilter ( 0. , self . RC , DT_CTRL )
self . reset ( )
@property
def RC ( self ) :
return interp ( self . speed , self . _RC [ 0 ] , self . _RC [ 1 ] )
@property
def G ( self ) :
return interp ( self . speed , self . _G [ 0 ] , self . _G [ 1 ] )
@property
def outer_loop_gain ( self ) :
return interp ( self . speed , self . _outer_loop_gain [ 0 ] , self . _outer_loop_gain [ 1 ] )
@property
def inner_loop_gain ( self ) :
return interp ( self . speed , self . _inner_loop_gain [ 0 ] , self . _inner_loop_gain [ 1 ] )
def reset ( self ) :
super ( ) . reset ( )
self . steer_filter . x = 0.
self . speed = 0.
def update ( self , active , CS , VM , params , last_actuators , steer_limited , desired_curvature , desired_curvature_rate , llk ) :
self . speed = CS . vEgo
# Update Kalman filter
y = np . array ( [ [ math . radians ( CS . steeringAngleDeg ) ] , [ math . radians ( CS . steeringRateDeg ) ] ] )
self . x = np . dot ( self . A_K , self . x ) + np . dot ( self . K , y )
indi_log = log . ControlsState . LateralINDIState . new_message ( )
indi_log . steeringAngleDeg = math . degrees ( self . x [ 0 ] )
indi_log . steeringRateDeg = math . degrees ( self . x [ 1 ] )
indi_log . steeringAccelDeg = math . degrees ( self . x [ 2 ] )
steers_des = VM . get_steer_from_curvature ( - desired_curvature , CS . vEgo , params . roll )
steers_des + = math . radians ( params . angleOffsetDeg )
indi_log . steeringAngleDesiredDeg = math . degrees ( steers_des )
# desired rate is the desired rate of change in the setpoint, not the absolute desired curvature
rate_des = VM . get_steer_from_curvature ( - desired_curvature_rate , CS . vEgo , 0 )
indi_log . steeringRateDesiredDeg = math . degrees ( rate_des )
if CS . vEgo < MIN_STEER_SPEED or not active :
indi_log . active = False
self . steer_filter . x = 0.0
output_steer = 0
else :
# Expected actuator value
self . steer_filter . update_alpha ( self . RC )
self . steer_filter . update ( last_actuators . steer )
# Compute acceleration error
rate_sp = self . outer_loop_gain * ( steers_des - self . x [ 0 ] ) + rate_des
accel_sp = self . inner_loop_gain * ( rate_sp - self . x [ 1 ] )
accel_error = accel_sp - self . x [ 2 ]
# Compute change in actuator
g_inv = 1. / self . G
delta_u = g_inv * accel_error
# If steering pressed, only allow wind down
if CS . steeringPressed and ( delta_u * last_actuators . steer > 0 ) :
delta_u = 0
output_steer = self . steer_filter . x + delta_u
output_steer = clip ( output_steer , - self . steer_max , self . steer_max )
indi_log . active = True
indi_log . rateSetPoint = float ( rate_sp )
indi_log . accelSetPoint = float ( accel_sp )
indi_log . accelError = float ( accel_error )
indi_log . delayedOutput = float ( self . steer_filter . x )
indi_log . delta = float ( delta_u )
indi_log . output = float ( output_steer )
indi_log . saturated = self . _check_saturation ( self . steer_max - abs ( output_steer ) < 1e-3 , CS , steer_limited )
return float ( output_steer ) , float ( steers_des ) , indi_log