Compare commits

...

4 Commits

Author SHA1 Message Date
discountchubbs d811c8ddde modeld_v2: check fusion validation speed 2026-10-18 12:12:34 -07:00
discountchubbs e693544fd7 this gets ignored, just to pass lint 2026-10-16 20:51:10 -07:00
discountchubbs f9c876ca2d upstream sync stuffs 2026-10-16 20:50:25 -07:00
discountchubbs 046a3ead4e https://github.com/commaai/openpilot/commit/2b09bc94a9f52206173cece3b517a2a3262c258f 2026-10-16 20:39:51 -07:00
4 changed files with 46 additions and 10 deletions
+5 -1
View File
@@ -1,7 +1,7 @@
import os
from pathlib import Path
CHESTNUT_FW_VERSION = "ed4e39b7"
CHESTNUT_FW_VERSION = "8516b768"
CHESTNUT_USB_IDS = ((0xADD1, 0x0001), (0x3801, 0x0001))
CHESTNUT_ROM_USB_IDS = ((0x174C, 0x2464), (0x174C, 0x2463))
CHESTNUT_USB_PRODUCT = f"custom {CHESTNUT_FW_VERSION}-CLEAN"
@@ -36,6 +36,10 @@ def read_int(path: Path, base: int = 10) -> int:
return 0
def cable_connected() -> bool:
return read_int(TYPEC_CC_ORIENTATION_PATH) != 0
def usb_devices() -> list[Path]:
try:
devices = (d for d in USB_DEVICES_PATH.glob("*") if (d / "idVendor").exists())
+9
View File
@@ -3,6 +3,7 @@ import os
import pickle
import struct
import sys
import time
from pathlib import Path
from openpilot.common.file_chunker import get_chunk_name, get_manifest_path, open_file_chunked
@@ -41,6 +42,14 @@ def chestnut_present() -> bool:
pass
return False
def wait_for_chestnut(timeout: float = 10.) -> None:
# the cable is detected before chestnut enumerates
st = time.monotonic()
while not chestnut_present():
if time.monotonic() - st > timeout:
raise TimeoutError("chestnut did not enumerate")
time.sleep(0.1)
def chestnut_compiled() -> bool:
path = modeld_pkl_path(chestnut=True)
return (path.is_file() or Path(get_manifest_path(path)).is_file()) and all(
+8 -3
View File
@@ -10,6 +10,7 @@ import builtins
import contextlib
import dataclasses
import functools
import gc
import hashlib
import io
import itertools
@@ -111,17 +112,21 @@ def read_parts(path: str) -> tuple[dict, dict]:
return parts, _MetadataUnpickler(io.BytesIO(bytes(blob[slice(*header["extras"])]))).load()
def _extended(path: str, extend) -> tuple[dict, dict, str]:
def _extended(path: str, extend) -> tuple[dict, dict, str, dict]:
parts, extras = read_parts(path)
added = extend(parts, extras) if extend else {}
return parts | added, extras, _parts_digest(added) if added else ""
return parts | added, extras, _parts_digest(added) if added else "", {key: parts[key] for key in added if key in parts}
def load_model(path: str, device_map: dict | None = None, verify: bool = True, cache: bool = True, extend=None) -> dict:
parts, extras, extra = _extended(path, extend)
parts, extras, extra, replaced = _extended(path, extend)
if cache and (cached := _read_cache(path, parts, device_map, extra)) is not None:
return extras | cached
shared: dict = {}
if verify and replaced:
for header, blob in replaced.values():
PlainJit(header, blob, device_map, verify, shared)
gc.collect()
jits = {key: PlainJit(header, blob, device_map, verify, shared) for key, (header, blob) in parts.items()}
if cache:
_write_cache(path, jits, device_map, extra)
+24 -6
View File
@@ -7,8 +7,10 @@ See the LICENSE.md file in the root directory for more details.
"""
from collections.abc import Callable
import gc
import os
os.environ['GMMU'] = '0'
from tinygrad.device import Device
import numpy as np
import threading
import time
@@ -16,7 +18,7 @@ from setproctitle import setproctitle
import openpilot.cereal.messaging as messaging
from openpilot.common.hardware import COMMA_HARDWARE
from openpilot.selfdrive.modeld.helpers import chestnut_present
from openpilot.selfdrive.modeld.helpers import chestnut_present, wait_for_chestnut
from openpilot.cereal import log
from opendbc.car.structs import car
from openpilot.cereal.services import SERVICE_LIST
@@ -26,6 +28,7 @@ from msgq.visionipc import VisionIpcClient, VisionBuf
from opendbc.car.car_helpers import get_demo_car_params
from openpilot.common.swaglog import cloudlog
from openpilot.common.params import Params
from openpilot.common.hardware.usb import cable_connected
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.realtime import config_realtime_process, DT_MDL
from openpilot.common.transformations.camera import DEVICE_CAMERAS
@@ -179,6 +182,8 @@ class ModelState(ModelStateBase):
self.numpy_inputs['big_tfm'][:, :] = transforms[self._wide_key].reshape(3, 3)
raw_outputs = self.adapter.run()
if self.chestnut and (err := Device[self.DEV].error_state.host.view(fmt='q')[0]):
raise RuntimeError(f"chestnut failed with {err}")
if after_enqueue is not None:
after_enqueue()
@@ -253,9 +258,8 @@ def main(demo=False):
cloudlog.bind(daemon=PROCESS_NAME)
setproctitle(PROCESS_NAME)
config_realtime_process(7, 54)
CHESTNUT = chestnut_present()
CHESTNUT = _find_driving_pkl(get_active_bundle(chestnut=True)) is not None and (chestnut_present() or cable_connected())
if CHESTNUT:
from tinygrad.runtime.ops_amd import AMDDevice
AMDDevice.wait_timeout_ms = 3000
@@ -264,6 +268,8 @@ def main(demo=False):
params.put_bool("ChestnutLoading", CHESTNUT)
params.remove("ChestnutActive")
gc.disable()
# visionipc clients
while True:
available_streams = VisionIpcClient.available_streams("camerad", block=False)
@@ -296,6 +302,7 @@ def main(demo=False):
def load_big():
nonlocal big_model
try:
wait_for_chestnut()
m = ModelState(cam_w=vipc_client_main.width, cam_h=vipc_client_main.height, chestnut=True)
m.warmup()
big_model = m
@@ -305,7 +312,13 @@ def main(demo=False):
loader.start()
loader.join(BIG_MODEL_TIMEOUT)
model = big_model
params.put_bool("ChestnutActive", model is not None)
if model is None and not params.get_bool("ChestnutRetry"):
# a crank can cut the chestnut power during the load, retry once with an onroad cycle
cloudlog.error("big model load failed, cycling onroad to retry")
params.put_bool("ChestnutRetry", True)
params.put_bool("OnroadCycleRequested", True)
else:
params.put_bool("ChestnutActive", model is not None)
small_model = ModelState(cam_w=vipc_client_main.width, cam_h=vipc_client_main.height, chestnut=False) if model is None or CHESTNUT else None
if model is None:
@@ -314,10 +327,13 @@ def main(demo=False):
assert model is not None
cloudlog.warning(f"models loaded in {time.monotonic() - st:.1f}s, modeld starting")
config_realtime_process(7, 54)
# messaging
pub_socks = ["modelV2", "drivingModelData", "cameraOdometry", "modelDataV2SP"] + (["chestnutGpuState"] if CHESTNUT else [])
pm = PubMaster(pub_socks)
sm = SubMaster(["deviceState", "carState", "narrowRoadCameraState", "extrinsicsCalibration", "driverMonitoringState", "carControl", "lateralDelay"])
sm = SubMaster(["deviceState", "carState", "narrowRoadCameraState", "extrinsicsCalibration", "driverMonitoringState",
"carControl", "controlsState", "lateralDelay"])
publish_state = PublishState()
chestnut_state = ChestnutGpuState(pm, model.chestnut) if CHESTNUT else None
@@ -445,7 +461,7 @@ def main(demo=False):
run_count % round(model.constants.MODEL_FREQ / SERVICE_LIST['chestnutGpuState'].frequency) == 0)
model_output = model.run(bufs, transforms, inputs, chestnut_state.send if send_chestnut else None)
except Exception:
if not params.get_bool("ChestnutActive"):
if not model.chestnut:
raise
cloudlog.exception("big model failed, fall back to small")
params.put_bool("ChestnutActive", False)
@@ -464,6 +480,8 @@ def main(demo=False):
posenet_send = messaging.new_message('cameraOdometry')
mdv2sp_send = messaging.new_message('modelDataV2SP')
if not sm['carControl'].latActive:
prev_action.desiredCurvature = sm['controlsState'].curvature
action = model.get_action_from_model(model_output, prev_action, lat_action_t, long_action_t, v_ego)
prev_action = action
fill_model_msg(drivingdata_send, modelv2_send, model_output, action,