@ -31,6 +31,7 @@ INPUTS_NEEDED = 5 # Minimum blocks needed for valid calibration
INPUTS_WANTED = 50 # We want a little bit more than we need for stability
INPUTS_WANTED = 50 # We want a little bit more than we need for stability
MAX_ALLOWED_SPREAD = np . radians ( 2 )
MAX_ALLOWED_SPREAD = np . radians ( 2 )
RPY_INIT = np . array ( [ 0.0 , 0.0 , 0.0 ] )
RPY_INIT = np . array ( [ 0.0 , 0.0 , 0.0 ] )
WIDE_FROM_DEVICE_EULER_INIT = np . array ( [ 0.0 , 0.0 , 0.0 ] )
# These values are needed to accommodate biggest modelframe
# These values are needed to accommodate biggest modelframe
PITCH_LIMITS = np . array ( [ - 0.09074112085129739 , 0.14907572052989657 ] )
PITCH_LIMITS = np . array ( [ - 0.09074112085129739 , 0.14907572052989657 ] )
@ -67,6 +68,7 @@ class Calibrator:
calibration_params = params . get ( " CalibrationParams " )
calibration_params = params . get ( " CalibrationParams " )
self . wide_camera = params . get_bool ( ' WideCameraOnly ' )
self . wide_camera = params . get_bool ( ' WideCameraOnly ' )
rpy_init = RPY_INIT
rpy_init = RPY_INIT
wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT
valid_blocks = 0
valid_blocks = 0
if param_put and calibration_params :
if param_put and calibration_params :
@ -74,24 +76,34 @@ class Calibrator:
msg = log . Event . from_bytes ( calibration_params )
msg = log . Event . from_bytes ( calibration_params )
rpy_init = np . array ( msg . liveCalibration . rpyCalib )
rpy_init = np . array ( msg . liveCalibration . rpyCalib )
valid_blocks = msg . liveCalibration . validBlocks
valid_blocks = msg . liveCalibration . validBlocks
wide_from_device_euler = np . array ( msg . liveCalibration . wideFromDeviceEuler )
except Exception :
except Exception :
cloudlog . exception ( " Error reading cached CalibrationParams " )
cloudlog . exception ( " Error reading cached CalibrationParams " )
self . reset ( rpy_init , valid_blocks )
self . reset ( rpy_init , valid_blocks , wide_from_device_euler )
self . update_status ( )
self . update_status ( )
def reset ( self , rpy_init : np . ndarray = RPY_INIT , valid_blocks : int = 0 , smooth_from : Optional [ np . ndarray ] = None ) - > None :
def reset ( self , rpy_init : np . ndarray = RPY_INIT ,
valid_blocks : int = 0 ,
wide_from_device_euler : np . ndarray = WIDE_FROM_DEVICE_EULER_INIT ,
smooth_from : Optional [ np . ndarray ] = None ) - > None :
if not np . isfinite ( rpy_init ) . all ( ) :
if not np . isfinite ( rpy_init ) . all ( ) :
self . rpy = RPY_INIT . copy ( )
self . rpy = RPY_INIT . copy ( )
else :
else :
self . rpy = rpy_init . copy ( )
self . rpy = rpy_init . copy ( )
if not np . isfinite ( wide_from_device_euler ) . all ( ) :
self . wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT . copy ( )
else :
self . wide_from_device_euler = wide_from_device_euler . copy ( )
if not np . isfinite ( valid_blocks ) or valid_blocks < 0 :
if not np . isfinite ( valid_blocks ) or valid_blocks < 0 :
self . valid_blocks = 0
self . valid_blocks = 0
else :
else :
self . valid_blocks = valid_blocks
self . valid_blocks = valid_blocks
self . rpys = np . tile ( self . rpy , ( INPUTS_WANTED , 1 ) )
self . rpys = np . tile ( self . rpy , ( INPUTS_WANTED , 1 ) )
self . wide_from_device_eulers = np . tile ( wide_from_device_euler , ( INPUTS_WANTED , 1 ) )
self . idx = 0
self . idx = 0
self . block_idx = 0
self . block_idx = 0
@ -115,6 +127,8 @@ class Calibrator:
if valid_idxs :
if valid_idxs :
rpys = self . rpys [ valid_idxs ]
rpys = self . rpys [ valid_idxs ]
self . rpy = np . mean ( rpys , axis = 0 )
self . rpy = np . mean ( rpys , axis = 0 )
wide_from_device_eulers = self . wide_from_device_eulers [ valid_idxs ]
self . wide_from_device_euler = np . mean ( wide_from_device_eulers , axis = 0 )
max_rpy_calib = np . array ( np . max ( rpys , axis = 0 ) )
max_rpy_calib = np . array ( np . max ( rpys , axis = 0 ) )
min_rpy_calib = np . array ( np . min ( rpys , axis = 0 ) )
min_rpy_calib = np . array ( np . min ( rpys , axis = 0 ) )
self . calib_spread = np . abs ( max_rpy_calib - min_rpy_calib )
self . calib_spread = np . abs ( max_rpy_calib - min_rpy_calib )
@ -146,7 +160,10 @@ class Calibrator:
else :
else :
return self . rpy
return self . rpy
def handle_cam_odom ( self , trans : List [ float ] , rot : List [ float ] , trans_std : List [ float ] ) - > Optional [ np . ndarray ] :
def handle_cam_odom ( self , trans : List [ float ] ,
rot : List [ float ] ,
wide_from_device_euler : List [ float ] ,
trans_std : List [ float ] ) - > Optional [ np . ndarray ] :
self . old_rpy_weight = min ( 0.0 , self . old_rpy_weight - 1 / SMOOTH_CYCLES )
self . old_rpy_weight = min ( 0.0 , self . old_rpy_weight - 1 / SMOOTH_CYCLES )
straight_and_fast = ( ( self . v_ego > MIN_SPEED_FILTER ) and ( trans [ 0 ] > MIN_SPEED_FILTER ) and ( abs ( rot [ 2 ] ) < MAX_YAW_RATE_FILTER ) )
straight_and_fast = ( ( self . v_ego > MIN_SPEED_FILTER ) and ( trans [ 0 ] > MIN_SPEED_FILTER ) and ( abs ( rot [ 2 ] ) < MAX_YAW_RATE_FILTER ) )
@ -165,7 +182,15 @@ class Calibrator:
new_rpy = euler_from_rot ( rot_from_euler ( self . get_smooth_rpy ( ) ) . dot ( rot_from_euler ( observed_rpy ) ) )
new_rpy = euler_from_rot ( rot_from_euler ( self . get_smooth_rpy ( ) ) . dot ( rot_from_euler ( observed_rpy ) ) )
new_rpy = sanity_clip ( new_rpy )
new_rpy = sanity_clip ( new_rpy )
self . rpys [ self . block_idx ] = ( self . idx * self . rpys [ self . block_idx ] + ( BLOCK_SIZE - self . idx ) * new_rpy ) / float ( BLOCK_SIZE )
if len ( wide_from_device_euler ) :
new_wide_from_device_euler = np . array ( wide_from_device_euler )
else :
new_wide_from_device_euler = WIDE_FROM_DEVICE_EULER_INIT
self . rpys [ self . block_idx ] = ( self . idx * self . rpys [ self . block_idx ] +
( BLOCK_SIZE - self . idx ) * new_rpy ) / float ( BLOCK_SIZE )
self . wide_from_device_eulers [ self . block_idx ] = ( self . idx * self . wide_from_device_eulers [ self . block_idx ] +
( BLOCK_SIZE - self . idx ) * new_wide_from_device_euler ) / float ( BLOCK_SIZE )
self . idx = ( self . idx + 1 ) % BLOCK_SIZE
self . idx = ( self . idx + 1 ) % BLOCK_SIZE
if self . idx == 0 :
if self . idx == 0 :
self . block_idx + = 1
self . block_idx + = 1
@ -187,6 +212,7 @@ class Calibrator:
liveCalibration . calPerc = min ( 100 * ( self . valid_blocks * BLOCK_SIZE + self . idx ) / / ( INPUTS_NEEDED * BLOCK_SIZE ) , 100 )
liveCalibration . calPerc = min ( 100 * ( self . valid_blocks * BLOCK_SIZE + self . idx ) / / ( INPUTS_NEEDED * BLOCK_SIZE ) , 100 )
liveCalibration . rpyCalib = smooth_rpy . tolist ( )
liveCalibration . rpyCalib = smooth_rpy . tolist ( )
liveCalibration . rpyCalibSpread = self . calib_spread . tolist ( )
liveCalibration . rpyCalibSpread = self . calib_spread . tolist ( )
liveCalibration . wideFromDeviceEuler = self . wide_from_device_euler . tolist ( )
if self . not_car :
if self . not_car :
liveCalibration . validBlocks = INPUTS_NEEDED
liveCalibration . validBlocks = INPUTS_NEEDED
@ -223,6 +249,7 @@ def calibrationd_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[m
calibrator . handle_v_ego ( sm [ ' carState ' ] . vEgo )
calibrator . handle_v_ego ( sm [ ' carState ' ] . vEgo )
new_rpy = calibrator . handle_cam_odom ( sm [ ' cameraOdometry ' ] . trans ,
new_rpy = calibrator . handle_cam_odom ( sm [ ' cameraOdometry ' ] . trans ,
sm [ ' cameraOdometry ' ] . rot ,
sm [ ' cameraOdometry ' ] . rot ,
sm [ ' cameraOdometry ' ] . wideFromDeviceEuler ,
sm [ ' cameraOdometry ' ] . transStd )
sm [ ' cameraOdometry ' ] . transStd )
if DEBUG and new_rpy is not None :
if DEBUG and new_rpy is not None :