From 06af2abe67db217f96e6152ebf4f018fa1cb4bca Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Tue, 1 Sep 2026 07:20:56 -0700 Subject: [PATCH] modeld: wait for stable chestnut (#38742) modeld: wait for stable chestnut --- openpilot/common/params_keys.h | 1 + openpilot/selfdrive/modeld/helpers.py | 6 ++++++ openpilot/selfdrive/modeld/modeld.py | 24 +++++++++++++++++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/openpilot/common/params_keys.h b/openpilot/common/params_keys.h index ba6eae3dd5..07a2283ece 100644 --- a/openpilot/common/params_keys.h +++ b/openpilot/common/params_keys.h @@ -135,5 +135,6 @@ inline static std::unordered_map keys = { {"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}}, {"ChestnutActive", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION | CLEAR_ON_IGNITION_ON, BOOL}}, {"ChestnutLoading", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION | CLEAR_ON_IGNITION_ON, BOOL}}, + {"ChestnutModelError", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION | CLEAR_ON_IGNITION_ON, BOOL}}, {"Version", {PERSISTENT, STRING}}, }; diff --git a/openpilot/selfdrive/modeld/helpers.py b/openpilot/selfdrive/modeld/helpers.py index d081050055..23eb6cbd21 100644 --- a/openpilot/selfdrive/modeld/helpers.py +++ b/openpilot/selfdrive/modeld/helpers.py @@ -11,6 +11,8 @@ from openpilot.common.hardware.usb import CHESTNUT_USB_PRODUCT, USB_DEVICES_PATH MODELS_DIR = Path(__file__).resolve().parent / 'models' TG_INPUT_DEVICES_PATH = MODELS_DIR / 'tg_input_devices.json' +CHESTNUT_POWERED_VOLTAGE = 5000 +CHESTNUT_PCIE_READY = 0x78 def get_tg_input_devices(process_name: str, chestnut: bool): @@ -58,3 +60,7 @@ def chestnut_present() -> bool: def chestnut_compiled() -> bool: return Path(get_manifest_path(modeld_pkl_path(chestnut=True))).is_file() + + +def chestnut_ready(state) -> bool: + return state.supplyVoltage >= CHESTNUT_POWERED_VOLTAGE and not state.supplyFault and state.pcieLtssm == CHESTNUT_PCIE_READY diff --git a/openpilot/selfdrive/modeld/modeld.py b/openpilot/selfdrive/modeld/modeld.py index 1178349c47..c31418ee0d 100755 --- a/openpilot/selfdrive/modeld/modeld.py +++ b/openpilot/selfdrive/modeld/modeld.py @@ -31,7 +31,7 @@ from openpilot.selfdrive.modeld.compile_modeld import make_input_queues, WARP_IN from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_driving_model_data, fill_pose_msg, PublishState from openpilot.common.file_chunker import open_file_chunked from openpilot.selfdrive.modeld.constants import ModelConstants, Plan -from openpilot.selfdrive.modeld.helpers import chestnut_present, chestnut_compiled, modeld_pkl_path, get_tg_input_devices, load_oob +from openpilot.selfdrive.modeld.helpers import chestnut_present, chestnut_compiled, chestnut_ready, modeld_pkl_path, get_tg_input_devices, load_oob PROCESS_NAME = "openpilot.selfdrive.modeld.modeld" SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') @@ -205,12 +205,25 @@ class ModelState: def main(demo=False): cloudlog.warning("modeld init") - CHESTNUT = chestnut_present() and chestnut_compiled() + chestnut_available = chestnut_present() and chestnut_compiled() + CHESTNUT = False + if chestnut_available: + poller = messaging.Poller() + sock = messaging.sub_sock("chestnutState", poller=poller, conflate=True) + deadline = time.monotonic() + 4. / SERVICE_LIST['deviceState'].frequency + while not CHESTNUT and (remaining := deadline - time.monotonic()) > 0.: + if not poller.poll(round(remaining * 1000)): + break + msg = messaging.recv_one_or_none(sock) + CHESTNUT = msg is not None and msg.valid and chestnut_ready(msg.chestnutState) if CHESTNUT: os.environ['HCQDEV_WAIT_TIMEOUT_MS'] = '3000' params = Params() params.put_bool("ChestnutLoading", CHESTNUT) - params.remove("ChestnutActive") + if chestnut_available and not CHESTNUT: + params.put_bool("ChestnutActive", False) + else: + params.remove("ChestnutActive") config_realtime_process(7, 54) @@ -254,7 +267,11 @@ def main(demo=False): loader.start() loader.join(BIG_MODEL_TIMEOUT) model = big_model + if model is None: + params.put_bool("ChestnutModelError", True) params.put_bool("ChestnutActive", model is not None) + if model is not None: + params.remove("ChestnutModelError") small_model = ModelState(vipc_client_main.width, vipc_client_main.height, False) if model is None or CHESTNUT else None if model is None: @@ -385,6 +402,7 @@ def main(demo=False): raise # fallback to small model cloudlog.exception("big model failed, fall back to small") + params.put_bool("ChestnutModelError", True) params.put_bool("ChestnutActive", False) model = small_model if chestnut_state is not None: