diff --git a/selfdrive/clearpilot/dashcamd b/selfdrive/clearpilot/dashcamd index 74e83b4..5ef831a 100755 Binary files a/selfdrive/clearpilot/dashcamd and b/selfdrive/clearpilot/dashcamd differ diff --git a/selfdrive/clearpilot/dashcamd.cc b/selfdrive/clearpilot/dashcamd.cc index cdb529c..9afda31 100644 --- a/selfdrive/clearpilot/dashcamd.cc +++ b/selfdrive/clearpilot/dashcamd.cc @@ -130,18 +130,28 @@ int main(int argc, char *argv[]) { if (do_exit) return 0; 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); while (!do_exit && !vipc.connect(false)) { usleep(100000); } if (do_exit) return 0; + LOGW("dashcamd: vipc connected, waiting for valid frame"); - int width = vipc.buffers[0].width; - int height = vipc.buffers[0].height; - int y_stride = vipc.buffers[0].stride; + // Wait for a frame with valid dimensions (camerad may still be initializing) + VisionBuf *init_buf = nullptr; + 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; - 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) SubMaster sm({"carState", "deviceState", "gpsLocation"}); diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 30e0764..00f9d8c 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -442,6 +442,13 @@ class Controls: # All events here should at least have NO_ENTRY and SOFT_DISABLE. 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} if self.sm.recv_frame['managerState'] and (not_running - IGNORE_PROCESSES): 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) self.events.add(EventName.controlsdLagging) 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) if not self.sm.valid['pandaStates']: self.events.add(EventName.usbError) @@ -469,13 +476,6 @@ class Controls: self.events.add(EventName.canError) # 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)) 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: @@ -499,13 +499,13 @@ class Controls: self.logged_comm_issue = None 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) if not self.sm['liveLocationKalman'].deviceStable: 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) - 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) # conservative HW alert. if the data or frequency are off, locationd will throw an error diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 128cf21..0302fb5 100755 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -54,7 +54,7 @@ def allow_uploads(started, params, CP: car.CarParams) -> bool: # ClearPilot functions 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 = [ DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"), diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 9791723..93011b1 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -241,13 +241,17 @@ def main(demo=False): sm.update(0) - # CLEARPILOT: standstill power saving — skip inference, keep model loaded - standstill = sm['carState'].standstill - if standstill and not model_standby: + # CLEARPILOT: power saving — skip inference when lateral control is not active + # Covers standstill, manual driving (no cruise), and disengaged states + # 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) model_standby = True - cloudlog.warning("modeld: standby ON (standstill)") - elif not standstill and model_standby: + cloudlog.warning("modeld: standby ON (lat_active=%s standstill=%s)", lat_active, sm['carState'].standstill) + elif not should_standby and model_standby: params_memory.put_bool("ModelStandby", False) model_standby = False run_count = 0 diff --git a/selfdrive/thermald/fan_controller.py b/selfdrive/thermald/fan_controller.py index a0e4664..3d08282 100755 --- a/selfdrive/thermald/fan_controller.py +++ b/selfdrive/thermald/fan_controller.py @@ -31,7 +31,7 @@ class TiciFanController(BaseFanController): self.controller.pos_limit = 0 elif ignition: self.controller.neg_limit = -100 - self.controller.pos_limit = -30 + self.controller.pos_limit = -15 else: self.controller.neg_limit = -30 self.controller.pos_limit = 0