Skip to content

Commit 5dcaf3b

Browse files
authored
DM: fewer alerts during maneuvers (commaai#37751)
* 2in1 * clip * drop aodm lowspeed * cleanup * add lower bd * that was random
1 parent bf43c7e commit 5dcaf3b

File tree

2 files changed

+24
-13
lines changed

2 files changed

+24
-13
lines changed

selfdrive/monitoring/helpers.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from math import atan2
1+
from math import atan2, radians
22
import numpy as np
33

44
from cereal import car, log
@@ -43,6 +43,9 @@ def __init__(self, device_type):
4343
self._POSE_YAW_THRESHOLD = 0.4020
4444
self._POSE_YAW_THRESHOLD_SLACK = 0.5042
4545
self._POSE_YAW_THRESHOLD_STRICT = self._POSE_YAW_THRESHOLD
46+
self._POSE_YAW_MIN_STEER_DEG = 30
47+
self._POSE_YAW_STEER_FACTOR = 0.15
48+
self._POSE_YAW_STEER_MAX_OFFSET = 0.3927
4649
self._PITCH_NATURAL_OFFSET = 0.011 # initial value before offset is learned
4750
self._PITCH_NATURAL_THRESHOLD = 0.449
4851
self._YAW_NATURAL_OFFSET = 0.075 # initial value before offset is learned
@@ -59,7 +62,6 @@ def __init__(self, device_type):
5962
self._POSESTD_THRESHOLD = 0.3
6063
self._HI_STD_FALLBACK_TIME = int(10 / self._DT_DMON) # fall back to wheel touch if model is uncertain for 10s
6164
self._DISTRACTED_FILTER_TS = 0.25 # 0.6Hz
62-
self._ALWAYS_ON_ALERT_MIN_SPEED = 11
6365

6466
self._POSE_CALIB_MIN_SPEED = 13 # 30 mph
6567
self._POSE_OFFSET_MIN_COUNT = int(60 / self._DT_DMON) # valid data counts before calibration completes, 1min cumulative
@@ -101,6 +103,7 @@ def __init__(self, settings):
101103
self.low_std = True
102104
self.cfactor_pitch = 1.
103105
self.cfactor_yaw = 1.
106+
self.steer_yaw_offset = 0.
104107

105108
class DriverProb:
106109
def __init__(self, raw_priors, max_trackable):
@@ -238,7 +241,11 @@ def _get_distracted_types(self):
238241
yaw_error = self.pose.yaw - min(max(self.pose.yaw_offseter.filtered_stat.mean(),
239242
self.settings._YAW_MIN_OFFSET), self.settings._YAW_MAX_OFFSET)
240243
pitch_error = 0 if pitch_error > 0 else abs(pitch_error) # no positive pitch limit
241-
yaw_error = abs(yaw_error)
244+
245+
if yaw_error * self.pose.steer_yaw_offset > 0: # unidirectional
246+
yaw_error = max(abs(yaw_error) - min(abs(self.pose.steer_yaw_offset), self.settings._POSE_YAW_STEER_MAX_OFFSET), 0.)
247+
else:
248+
yaw_error = abs(yaw_error)
242249

243250
pitch_threshold = self.settings._POSE_PITCH_THRESHOLD * self.pose.cfactor_pitch if self.pose.calibrated else self.settings._PITCH_NATURAL_THRESHOLD
244251
yaw_threshold = self.settings._POSE_YAW_THRESHOLD * self.pose.cfactor_yaw
@@ -254,7 +261,7 @@ def _get_distracted_types(self):
254261

255262
return distracted_types
256263

257-
def _update_states(self, driver_state, cal_rpy, car_speed, op_engaged, standstill, demo_mode=False):
264+
def _update_states(self, driver_state, cal_rpy, car_speed, op_engaged, standstill, demo_mode=False, steering_angle_deg=0.):
258265
rhd_pred = driver_state.wheelOnRightProb
259266
# calibrates only when there's movement and either face detected
260267
if car_speed > self.settings._WHEELPOS_CALIB_MIN_SPEED and (driver_state.leftDriverData.faceProb > self.settings._FACE_THRESHOLD or
@@ -277,8 +284,11 @@ def _update_states(self, driver_state, cal_rpy, car_speed, op_engaged, standstil
277284

278285
self.face_detected = driver_data.faceProb > self.settings._FACE_THRESHOLD
279286
self.pose.roll, self.pose.pitch, self.pose.yaw = face_orientation_from_net(driver_data.faceOrientation, driver_data.facePosition, cal_rpy)
287+
steer_d = max(abs(steering_angle_deg) - self.settings._POSE_YAW_MIN_STEER_DEG, 0.)
288+
self.pose.steer_yaw_offset = radians(steer_d) * -np.sign(steering_angle_deg) * self.settings._POSE_YAW_STEER_FACTOR
280289
if self.wheel_on_right:
281290
self.pose.yaw *= -1
291+
self.pose.steer_yaw_offset *= -1
282292
self.wheel_on_right_last = self.wheel_on_right
283293
self.pose.pitch_std = driver_data.faceOrientationStd[0]
284294
self.pose.yaw_std = driver_data.faceOrientationStd[1]
@@ -360,19 +370,19 @@ def _update_events(self, driver_engaged, op_engaged, standstill, wrong_gear, car
360370
if self.awareness > self.threshold_prompt:
361371
return
362372

373+
_reaching_pre = self.awareness - self.step_change <= self.threshold_pre
363374
_reaching_audible = self.awareness - self.step_change <= self.threshold_prompt
364375
_reaching_terminal = self.awareness - self.step_change <= 0
365-
standstill_orange_exemption = standstill and _reaching_audible
376+
standstill_exemption = standstill and _reaching_pre
366377
always_on_red_exemption = always_on_valid and not op_engaged and _reaching_terminal
367-
always_on_lowspeed_exemption = always_on_valid and not op_engaged and car_speed < self.settings._ALWAYS_ON_ALERT_MIN_SPEED
368378

369379
certainly_distracted = self.driver_distraction_filter.x > 0.63 and self.driver_distracted and self.face_detected
370380
maybe_distracted = self.hi_stds > self.settings._HI_STD_FALLBACK_TIME or not self.face_detected
371381

372382
if certainly_distracted or maybe_distracted:
373-
# should always be counting if distracted unless at standstill (lowspeed for always-on) and reaching orange
383+
# should always be counting if distracted unless at standstill and reaching green
374384
# also will not be reaching 0 if DM is active when not engaged
375-
if not (standstill_orange_exemption or always_on_red_exemption or (always_on_lowspeed_exemption and _reaching_audible)):
385+
if not (standstill_exemption or always_on_red_exemption):
376386
self.awareness = max(self.awareness - self.step_change, -0.1)
377387

378388
alert = None
@@ -385,7 +395,7 @@ def _update_events(self, driver_engaged, op_engaged, standstill, wrong_gear, car
385395
elif self.awareness <= self.threshold_prompt:
386396
# prompt orange alert
387397
alert = EventName.promptDriverDistracted if self.active_monitoring_mode else EventName.promptDriverUnresponsive
388-
elif self.awareness <= self.threshold_pre and not always_on_lowspeed_exemption:
398+
elif self.awareness <= self.threshold_pre:
389399
# pre green alert
390400
alert = EventName.preDriverDistracted if self.active_monitoring_mode else EventName.preDriverUnresponsive
391401

@@ -451,6 +461,7 @@ def run_step(self, sm, demo=False):
451461
op_engaged=enabled,
452462
standstill=standstill,
453463
demo_mode=demo,
464+
steering_angle_deg=sm['carState'].steeringAngleDeg,
454465
)
455466

456467
# Update distraction events

selfdrive/monitoring/test_monitoring.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,10 @@ def test_long_traffic_light_victim(self):
186186
standstill_vector = always_true[:]
187187
standstill_vector[int(_redlight_time/DT_DMON):] = [False] * int((TEST_TIMESPAN-_redlight_time)/DT_DMON)
188188
events, d_status = self._run_seq(always_distracted, always_false, always_true, standstill_vector)
189-
assert events[int((d_status.settings._DISTRACTED_TIME-d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL+1)/DT_DMON)].names[0] == \
190-
EventName.preDriverDistracted
191-
assert events[int((_redlight_time-0.1)/DT_DMON)].names[0] == EventName.preDriverDistracted
192-
assert events[int((_redlight_time+0.5)/DT_DMON)].names[0] == EventName.promptDriverDistracted
189+
assert len(events[int((_redlight_time-0.1)/DT_DMON)]) == 0
190+
_pre_to_prompt = d_status.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL - d_status.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL
191+
assert events[int((_redlight_time+0.5)/DT_DMON)].names[0] == EventName.preDriverDistracted
192+
assert events[int((_redlight_time+_pre_to_prompt+0.5)/DT_DMON)].names[0] == EventName.promptDriverDistracted
193193

194194
# engaged, model is somehow uncertain and driver is distracted
195195
# - should fall back to wheel touch after uncertain alert

0 commit comments

Comments
 (0)