CLAUDE.md: added a "Logging" rule — never use cloudlog (upstream cloud
pipeline, effectively a black hole for us), always use
print(..., file=sys.stderr, flush=True). Manager redirects each process's
stderr to /data/log2/current/{proc}.log. Prefix our lines with "CLP ".
Diagnostic logging — when a publisher sets its own msg.valid=False, log
which specific subscriber tripped the check. Only fires on transition
(True→False) so we don't spam. Covers the services whose cascades we've
been chasing:
- frogpilot_planner (frogpilotPlan)
- longitudinal_planner (longitudinalPlan)
- paramsd (liveParameters)
- calibrationd (liveCalibration)
- torqued (liveTorqueParameters)
- dmonitoringd (driverMonitoringState)
gpsd.is_daylight: fixed a day-boundary bug where the function would flip
to "night" at UTC midnight regardless of actual local sunset. At 85W
sunset is ~00:20 UTC next day, so between local 8pm and actual sunset
the function used *tomorrow's* sunrise/sunset and said night. Now checks
yesterday/today/tomorrow windows with UTC-day offsets.
ui/onroad.cc: nightrider tire-path outline is now light blue (#99CCFF)
at 3px (was white/status-tinted at 6px); lane lines 5% thinner (float
pen width).
thermald/power_monitoring: auto-shutdown timer 10min → 30min.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
100 lines
4.1 KiB
Python
Executable File
100 lines
4.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import gc
|
|
|
|
import cereal.messaging as messaging
|
|
from cereal import car
|
|
from openpilot.common.params import Params
|
|
from openpilot.common.realtime import set_realtime_priority
|
|
from openpilot.selfdrive.controls.lib.events import Events
|
|
from openpilot.selfdrive.monitoring.driver_monitor import DriverStatus
|
|
|
|
|
|
def dmonitoringd_thread():
|
|
gc.disable()
|
|
set_realtime_priority(2)
|
|
|
|
params = Params()
|
|
pm = messaging.PubMaster(['driverMonitoringState'])
|
|
sm = messaging.SubMaster(['driverStateV2', 'liveCalibration', 'carState', 'controlsState', 'modelV2'], poll='driverStateV2')
|
|
|
|
driver_status = DriverStatus(rhd_saved=params.get_bool("IsRhdDetected"))
|
|
|
|
v_cruise_last = 0
|
|
driver_engaged = False
|
|
dbg_prev_valid = True # CLEARPILOT: track valid transitions
|
|
|
|
# 10Hz <- dmonitoringmodeld
|
|
while True:
|
|
sm.update()
|
|
if not sm.updated['driverStateV2']:
|
|
continue
|
|
|
|
# Get interaction
|
|
if sm.updated['carState']:
|
|
v_cruise = sm['carState'].cruiseState.speed
|
|
driver_engaged = len(sm['carState'].buttonEvents) > 0 or \
|
|
v_cruise != v_cruise_last or \
|
|
sm['carState'].steeringPressed or \
|
|
sm['carState'].gasPressed
|
|
v_cruise_last = v_cruise
|
|
|
|
if sm.updated['modelV2']:
|
|
driver_status.set_policy(sm['modelV2'], sm['carState'].vEgo)
|
|
|
|
# Get data from dmonitoringmodeld
|
|
events = Events()
|
|
|
|
if sm.all_checks() and len(sm['liveCalibration'].rpyCalib):
|
|
driver_status.update_states(sm['driverStateV2'], sm['liveCalibration'].rpyCalib, sm['carState'].vEgo, sm['controlsState'].enabled)
|
|
|
|
# Block engaging after max number of distrations
|
|
if driver_status.terminal_alert_cnt >= driver_status.settings._MAX_TERMINAL_ALERTS or \
|
|
driver_status.terminal_time >= driver_status.settings._MAX_TERMINAL_DURATION:
|
|
events.add(car.CarEvent.EventName.tooDistracted)
|
|
|
|
# Update events from driver state
|
|
driver_status.update_events(events, driver_engaged, sm['controlsState'].enabled, sm['carState'].standstill)
|
|
|
|
# CLEARPILOT: log on transition to invalid so we can see which sub caused the cascade
|
|
dm_valid = sm.all_checks()
|
|
if dm_valid != dbg_prev_valid and not dm_valid:
|
|
import sys
|
|
bad = [s for s in sm.alive if not (sm.alive[s] and sm.valid[s] and sm.freq_ok.get(s, True))]
|
|
details = [f"{s}(a={sm.alive[s]},v={sm.valid[s]},f={sm.freq_ok[s]})" for s in bad]
|
|
print(f"CLP driverMonitoringState valid=False: {' '.join(details)}", file=sys.stderr, flush=True)
|
|
dbg_prev_valid = dm_valid
|
|
# build driverMonitoringState packet
|
|
dat = messaging.new_message('driverMonitoringState', valid=dm_valid)
|
|
dat.driverMonitoringState = {
|
|
"events": events.to_msg(),
|
|
"faceDetected": driver_status.face_detected,
|
|
"isDistracted": driver_status.driver_distracted,
|
|
"distractedType": sum(driver_status.distracted_types),
|
|
"awarenessStatus": driver_status.awareness,
|
|
"posePitchOffset": driver_status.pose.pitch_offseter.filtered_stat.mean(),
|
|
"posePitchValidCount": driver_status.pose.pitch_offseter.filtered_stat.n,
|
|
"poseYawOffset": driver_status.pose.yaw_offseter.filtered_stat.mean(),
|
|
"poseYawValidCount": driver_status.pose.yaw_offseter.filtered_stat.n,
|
|
"stepChange": driver_status.step_change,
|
|
"awarenessActive": driver_status.awareness_active,
|
|
"awarenessPassive": driver_status.awareness_passive,
|
|
"isLowStd": driver_status.pose.low_std,
|
|
"hiStdCount": driver_status.hi_stds,
|
|
"isActiveMode": driver_status.active_monitoring_mode,
|
|
"isRHD": driver_status.wheel_on_right,
|
|
}
|
|
pm.send('driverMonitoringState', dat)
|
|
|
|
# save rhd virtual toggle every 5 mins
|
|
if (sm['driverStateV2'].frameId % 6000 == 0 and
|
|
driver_status.wheelpos_learner.filtered_stat.n > driver_status.settings._WHEELPOS_FILTER_MIN_COUNT and
|
|
driver_status.wheel_on_right == (driver_status.wheelpos_learner.filtered_stat.M > driver_status.settings._WHEELPOS_THRESHOLD)):
|
|
params.put_bool_nonblocking("IsRhdDetected", driver_status.wheel_on_right)
|
|
|
|
def main():
|
|
dmonitoringd_thread()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|