@ -7,6 +7,7 @@ import cereal.messaging as messaging
from cereal import car , log
from msgq . visionipc import VisionIpcClient , VisionStreamType
from opendbc . car . interfaces import ACCEL_MIN , ACCEL_MAX
from openpilot . common . params import Params
@ -15,6 +16,7 @@ from openpilot.common.swaglog import cloudlog
from openpilot . common . gps import get_gps_location_service
from openpilot . selfdrive . car . car_specific import CarSpecificEvents
from openpilot . selfdrive . locationd . helpers import PoseCalibrator , Pose
from openpilot . selfdrive . selfdrived . events import Events , ET
from openpilot . selfdrive . selfdrived . state import StateMachine
from openpilot . selfdrive . selfdrived . alertmanager import AlertManager , set_offroad_alert
@ -25,7 +27,9 @@ from openpilot.system.version import get_build_metadata
REPLAY = " REPLAY " in os . environ
SIMULATION = " SIMULATION " in os . environ
TESTING_CLOSET = " TESTING_CLOSET " in os . environ
LONGITUDINAL_PERSONALITY_MAP = { v : k for k , v in log . LongitudinalPersonality . schema . enumerants . items ( ) }
MIN_EXCESSIVE_ACTUATION_COUNT = int ( 0.25 / DT_CTRL )
ThermalStatus = log . DeviceState . ThermalStatus
State = log . SelfdriveState . OpenpilotState
@ -39,6 +43,21 @@ SafetyModel = car.CarParams.SafetyModel
IGNORED_SAFETY_MODES = ( SafetyModel . silent , SafetyModel . noOutput )
def check_excessive_actuation ( sm : messaging . SubMaster , CS : car . CarState , calibrator : PoseCalibrator , counter : int ) - > tuple [ int , bool ] :
# CS.aEgo can be noisy to bumps in the road, transitioning from standstill, losing traction, etc.
device_pose = Pose . from_live_pose ( sm [ ' livePose ' ] )
calibrated_pose = calibrator . build_calibrated_pose ( device_pose )
accel_calibrated = calibrated_pose . acceleration . x
# livePose acceleration can be noisy due to bad mounting or aliased livePose measurements
accel_valid = abs ( CS . aEgo - accel_calibrated ) < 2
excessive_actuation = accel_calibrated > ACCEL_MAX * 2 or accel_calibrated < ACCEL_MIN * 2
counter = counter + 1 if sm [ ' carControl ' ] . longActive and excessive_actuation and accel_valid else 0
return counter , counter > MIN_EXCESSIVE_ACTUATION_COUNT
class SelfdriveD :
def __init__ ( self , CP = None ) :
self . params = Params ( )
@ -54,6 +73,7 @@ class SelfdriveD:
self . CP = CP
self . car_events = CarSpecificEvents ( self . CP )
self . calibrator = PoseCalibrator ( )
# Setup sockets
self . pm = messaging . PubMaster ( [ ' selfdriveState ' , ' onroadEvents ' ] )
@ -111,6 +131,8 @@ class SelfdriveD:
self . experimental_mode = False
self . personality = self . params . get ( " LongitudinalPersonality " , return_default = True )
self . recalibrating_seen = False
self . excessive_actuation = self . params . get ( " Offroad_ExcessiveActuation " ) is not None
self . excessive_actuation_counter = 0
self . state_machine = StateMachine ( )
self . rk = Ratekeeper ( 100 , print_delay_threshold = None )
@ -227,6 +249,18 @@ class SelfdriveD:
if self . sm [ ' driverAssistance ' ] . leftLaneDeparture or self . sm [ ' driverAssistance ' ] . rightLaneDeparture :
self . events . add ( EventName . ldw )
# Check for excessive (longitudinal) actuation
if self . sm . updated [ ' liveCalibration ' ] :
self . calibrator . feed_live_calib ( self . sm [ ' liveCalibration ' ] )
self . excessive_actuation_counter , excessive_actuation = check_excessive_actuation ( self . sm , CS , self . calibrator , self . excessive_actuation_counter )
if not self . excessive_actuation and excessive_actuation :
set_offroad_alert ( " Offroad_ExcessiveActuation " , True , extra_text = " longitudinal " )
self . excessive_actuation = True
if self . excessive_actuation :
self . events . add ( EventName . excessiveActuation )
# Handle lane change
if self . sm [ ' modelV2 ' ] . meta . laneChangeState == LaneChangeState . preLaneChange :
direction = self . sm [ ' modelV2 ' ] . meta . laneChangeDirection