modeld standby on lat inactive, dashcamd always-on, alert suppression
- modeld: enter standby when latActive=false (not just standstill), exception for lane changes (no_lat_lane_change). Fix Python capnp property access (.latActive not getLatActive()) - controlsd: move model_suppress computation early, suppress radarFault, posenetInvalid, locationdTemporaryError, paramsdTemporaryError during model standby + 2s grace period. All cascade from modeld not publishing - dashcamd: always_run (manages own trip lifecycle), wait for valid frame dimensions before encoding (fix SIGSEGV on early start) - Fan: driving range 15-100% (was 30-100%) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
@@ -130,18 +130,28 @@ int main(int argc, char *argv[]) {
|
|||||||
if (do_exit) return 0;
|
if (do_exit) return 0;
|
||||||
LOGW("dashcamd: system time valid");
|
LOGW("dashcamd: system time valid");
|
||||||
|
|
||||||
LOGW("dashcamd: connecting to camerad road stream");
|
LOGW("dashcamd: started, connecting to camerad road stream");
|
||||||
VisionIpcClient vipc("camerad", VISION_STREAM_ROAD, false);
|
VisionIpcClient vipc("camerad", VISION_STREAM_ROAD, false);
|
||||||
while (!do_exit && !vipc.connect(false)) {
|
while (!do_exit && !vipc.connect(false)) {
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
}
|
}
|
||||||
if (do_exit) return 0;
|
if (do_exit) return 0;
|
||||||
|
LOGW("dashcamd: vipc connected, waiting for valid frame");
|
||||||
|
|
||||||
int width = vipc.buffers[0].width;
|
// Wait for a frame with valid dimensions (camerad may still be initializing)
|
||||||
int height = vipc.buffers[0].height;
|
VisionBuf *init_buf = nullptr;
|
||||||
int y_stride = vipc.buffers[0].stride;
|
while (!do_exit) {
|
||||||
|
init_buf = vipc.recv();
|
||||||
|
if (init_buf != nullptr && init_buf->width > 0 && init_buf->height > 0) break;
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
if (do_exit) return 0;
|
||||||
|
|
||||||
|
int width = init_buf->width;
|
||||||
|
int height = init_buf->height;
|
||||||
|
int y_stride = init_buf->stride;
|
||||||
int uv_stride = y_stride;
|
int uv_stride = y_stride;
|
||||||
LOGW("dashcamd: connected %dx%d, stride=%d", width, height, y_stride);
|
LOGW("dashcamd: first valid frame %dx%d stride=%d", width, height, y_stride);
|
||||||
|
|
||||||
// Subscribe to carState (gear), deviceState (ignition), gpsLocation (subtitles)
|
// Subscribe to carState (gear), deviceState (ignition), gpsLocation (subtitles)
|
||||||
SubMaster sm({"carState", "deviceState", "gpsLocation"});
|
SubMaster sm({"carState", "deviceState", "gpsLocation"});
|
||||||
|
|||||||
@@ -442,6 +442,13 @@ class Controls:
|
|||||||
# All events here should at least have NO_ENTRY and SOFT_DISABLE.
|
# All events here should at least have NO_ENTRY and SOFT_DISABLE.
|
||||||
num_events = len(self.events)
|
num_events = len(self.events)
|
||||||
|
|
||||||
|
# CLEARPILOT: compute model standby suppression early — used by multiple checks below
|
||||||
|
try:
|
||||||
|
standby_ts = float(self.params_memory.get("ModelStandbyTs") or "0")
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
standby_ts = 0
|
||||||
|
model_suppress = (time.monotonic() - standby_ts) < 2.0
|
||||||
|
|
||||||
not_running = {p.name for p in self.sm['managerState'].processes if not p.running and p.shouldBeRunning}
|
not_running = {p.name for p in self.sm['managerState'].processes if not p.running and p.shouldBeRunning}
|
||||||
if self.sm.recv_frame['managerState'] and (not_running - IGNORE_PROCESSES):
|
if self.sm.recv_frame['managerState'] and (not_running - IGNORE_PROCESSES):
|
||||||
self.events.add(EventName.processNotRunning)
|
self.events.add(EventName.processNotRunning)
|
||||||
@@ -459,7 +466,7 @@ class Controls:
|
|||||||
print(f"CLP controlsdLagging: remaining={self.rk.remaining:.4f} standstill={CS.standstill} vEgo={CS.vEgo:.2f}", file=sys.stderr)
|
print(f"CLP controlsdLagging: remaining={self.rk.remaining:.4f} standstill={CS.standstill} vEgo={CS.vEgo:.2f}", file=sys.stderr)
|
||||||
self.events.add(EventName.controlsdLagging)
|
self.events.add(EventName.controlsdLagging)
|
||||||
if not self.radarless_model:
|
if not self.radarless_model:
|
||||||
if len(self.sm['radarState'].radarErrors) or (not self.rk.lagging and not self.sm.all_checks(['radarState'])):
|
if not model_suppress and (len(self.sm['radarState'].radarErrors) or (not self.rk.lagging and not self.sm.all_checks(['radarState']))):
|
||||||
self.events.add(EventName.radarFault)
|
self.events.add(EventName.radarFault)
|
||||||
if not self.sm.valid['pandaStates']:
|
if not self.sm.valid['pandaStates']:
|
||||||
self.events.add(EventName.usbError)
|
self.events.add(EventName.usbError)
|
||||||
@@ -469,13 +476,6 @@ class Controls:
|
|||||||
self.events.add(EventName.canError)
|
self.events.add(EventName.canError)
|
||||||
|
|
||||||
# generic catch-all. ideally, a more specific event should be added above instead
|
# generic catch-all. ideally, a more specific event should be added above instead
|
||||||
# CLEARPILOT: skip comm check when modeld was recently in standby
|
|
||||||
# ModelStandbyTs is written every 1s while in standby — if < 2s old, suppress
|
|
||||||
try:
|
|
||||||
standby_ts = float(self.params_memory.get("ModelStandbyTs") or "0")
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
standby_ts = 0
|
|
||||||
model_suppress = (time.monotonic() - standby_ts) < 2.0
|
|
||||||
has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE))
|
has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE))
|
||||||
no_system_errors = (not has_disable_events) or (len(self.events) == num_events)
|
no_system_errors = (not has_disable_events) or (len(self.events) == num_events)
|
||||||
if (not self.sm.all_checks() or self.card.can_rcv_timeout) and no_system_errors and not model_suppress:
|
if (not self.sm.all_checks() or self.card.can_rcv_timeout) and no_system_errors and not model_suppress:
|
||||||
@@ -499,13 +499,13 @@ class Controls:
|
|||||||
self.logged_comm_issue = None
|
self.logged_comm_issue = None
|
||||||
|
|
||||||
if not (self.CP.notCar and self.joystick_mode):
|
if not (self.CP.notCar and self.joystick_mode):
|
||||||
if not self.sm['liveLocationKalman'].posenetOK:
|
if not self.sm['liveLocationKalman'].posenetOK and not model_suppress:
|
||||||
self.events.add(EventName.posenetInvalid)
|
self.events.add(EventName.posenetInvalid)
|
||||||
if not self.sm['liveLocationKalman'].deviceStable:
|
if not self.sm['liveLocationKalman'].deviceStable:
|
||||||
self.events.add(EventName.deviceFalling)
|
self.events.add(EventName.deviceFalling)
|
||||||
if not self.sm['liveLocationKalman'].inputsOK:
|
if not self.sm['liveLocationKalman'].inputsOK and not model_suppress:
|
||||||
self.events.add(EventName.locationdTemporaryError)
|
self.events.add(EventName.locationdTemporaryError)
|
||||||
if not self.sm['liveParameters'].valid and not TESTING_CLOSET and (not SIMULATION or REPLAY):
|
if not self.sm['liveParameters'].valid and not TESTING_CLOSET and (not SIMULATION or REPLAY) and not model_suppress:
|
||||||
self.events.add(EventName.paramsdTemporaryError)
|
self.events.add(EventName.paramsdTemporaryError)
|
||||||
|
|
||||||
# conservative HW alert. if the data or frequency are off, locationd will throw an error
|
# conservative HW alert. if the data or frequency are off, locationd will throw an error
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ def allow_uploads(started, params, CP: car.CarParams) -> bool:
|
|||||||
|
|
||||||
# ClearPilot functions
|
# ClearPilot functions
|
||||||
def dashcam_should_run(started, params, CP: car.CarParams) -> bool:
|
def dashcam_should_run(started, params, CP: car.CarParams) -> bool:
|
||||||
return started or params.get_bool("DashcamDebug")
|
return True # CLEARPILOT: dashcamd manages its own trip lifecycle
|
||||||
|
|
||||||
procs = [
|
procs = [
|
||||||
DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"),
|
DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"),
|
||||||
|
|||||||
@@ -241,13 +241,17 @@ def main(demo=False):
|
|||||||
|
|
||||||
sm.update(0)
|
sm.update(0)
|
||||||
|
|
||||||
# CLEARPILOT: standstill power saving — skip inference, keep model loaded
|
# CLEARPILOT: power saving — skip inference when lateral control is not active
|
||||||
standstill = sm['carState'].standstill
|
# Covers standstill, manual driving (no cruise), and disengaged states
|
||||||
if standstill and not model_standby:
|
# Exception: keep processing during lane changes (no_lat_lane_change)
|
||||||
|
lat_active = sm['carControl'].latActive
|
||||||
|
lane_changing = params_memory.get_bool("no_lat_lane_change")
|
||||||
|
should_standby = not lat_active and not lane_changing
|
||||||
|
if should_standby and not model_standby:
|
||||||
params_memory.put_bool("ModelStandby", True)
|
params_memory.put_bool("ModelStandby", True)
|
||||||
model_standby = True
|
model_standby = True
|
||||||
cloudlog.warning("modeld: standby ON (standstill)")
|
cloudlog.warning("modeld: standby ON (lat_active=%s standstill=%s)", lat_active, sm['carState'].standstill)
|
||||||
elif not standstill and model_standby:
|
elif not should_standby and model_standby:
|
||||||
params_memory.put_bool("ModelStandby", False)
|
params_memory.put_bool("ModelStandby", False)
|
||||||
model_standby = False
|
model_standby = False
|
||||||
run_count = 0
|
run_count = 0
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class TiciFanController(BaseFanController):
|
|||||||
self.controller.pos_limit = 0
|
self.controller.pos_limit = 0
|
||||||
elif ignition:
|
elif ignition:
|
||||||
self.controller.neg_limit = -100
|
self.controller.neg_limit = -100
|
||||||
self.controller.pos_limit = -30
|
self.controller.pos_limit = -15
|
||||||
else:
|
else:
|
||||||
self.controller.neg_limit = -30
|
self.controller.neg_limit = -30
|
||||||
self.controller.pos_limit = 0
|
self.controller.pos_limit = 0
|
||||||
|
|||||||
Reference in New Issue
Block a user