From b8e14d85fbb5e3da1af7f3596e0d9eb49965056d Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 17 Aug 2026 21:47:14 -0700 Subject: [PATCH 1/8] chestnut: don't compile if big model is LFS pointer (#38655) * use compiled helper for hardwared alert, source doesn't matter. scons skips compile if it's empty/lfs pointer * log it * rmnl * compile failed * out of scope * rmnl --- openpilot/selfdrive/modeld/SConscript | 6 +++++- openpilot/selfdrive/modeld/helpers.py | 4 ++++ openpilot/system/hardware/hardwared.py | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/openpilot/selfdrive/modeld/SConscript b/openpilot/selfdrive/modeld/SConscript index 30a31aae27..8b2322f94e 100644 --- a/openpilot/selfdrive/modeld/SConscript +++ b/openpilot/selfdrive/modeld/SConscript @@ -7,7 +7,7 @@ from openpilot.common.file_chunker import chunk_file, get_chunk_targets, get_exi from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye from openpilot.common.transformations.model import MEDMODEL_INPUT_SIZE, DM_INPUT_SIZE from openpilot.selfdrive.modeld.constants import ModelConstants -from openpilot.selfdrive.modeld.helpers import TG_INPUT_DEVICES_PATH, usbgpu_present, modeld_pkl_path +from openpilot.selfdrive.modeld.helpers import TG_INPUT_DEVICES_PATH, big_model_source_available, usbgpu_present, modeld_pkl_path CAMERA_CONFIGS = [ @@ -44,6 +44,10 @@ tg_devices = { # which device to put jit inputs to at runtime } USBGPU = usbgpu_present() +if USBGPU and not big_model_source_available(): + print("Big model source unavailable, skipping big model build") + USBGPU = False + if USBGPU: usbgpu_tg_flags = f'DEBUG=2 DEV=USB+AMD:LLVM WARP_DEV={tg_backend} FLOAT16=1 JIT_BATCH_SIZE=0 GMMU=0 TC_OPT=2' # the USB+AMD GPU takes an exclusive flock; serialize all targets that touch it diff --git a/openpilot/selfdrive/modeld/helpers.py b/openpilot/selfdrive/modeld/helpers.py index 37ab0b26d7..ffd59eae06 100644 --- a/openpilot/selfdrive/modeld/helpers.py +++ b/openpilot/selfdrive/modeld/helpers.py @@ -21,6 +21,10 @@ def modeld_pkl_path(usbgpu: bool): prefix = 'big_' if usbgpu else '' return MODELS_DIR / f'{prefix}driving_tinygrad.pkl' +def big_model_source_available() -> bool: + model_path = MODELS_DIR / 'big_driving_supercombo.onnx' + return model_path.is_file() and model_path.stat().st_size >= 1024 + def dump_oob(obj, f): with tempfile.TemporaryFile(dir=".") as tmp: def buffer_callback(pb: pickle.PickleBuffer): diff --git a/openpilot/system/hardware/hardwared.py b/openpilot/system/hardware/hardwared.py index a423d8f97d..2817ef3942 100755 --- a/openpilot/system/hardware/hardwared.py +++ b/openpilot/system/hardware/hardwared.py @@ -16,6 +16,7 @@ from openpilot.common.utils import strip_deprecated_keys from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.params import Params from openpilot.common.realtime import DT_HW +from openpilot.selfdrive.modeld.helpers import usbgpu_compiled from openpilot.selfdrive.selfdrived.alertmanager import set_offroad_alert from openpilot.common.hardware import HARDWARE, COMMA_HARDWARE, PC from openpilot.common.basedir import BASEDIR @@ -237,8 +238,7 @@ def hardware_thread(end_event, hw_queue) -> None: fan_controller = FanController(int(1./DT_HW)) chestnut = Chestnut() - big_model_available = os.path.isfile(os.path.join(BASEDIR, "openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx")) or \ - os.path.isfile(os.path.join(BASEDIR, "openpilot/selfdrive/modeld/models/big_driving_tinygrad.pkl.chunkmanifest")) + big_model_available = usbgpu_compiled() while not end_event.is_set(): sm.update(PANDA_STATES_TIMEOUT) From b7657f6553855a569e30e2a971d6e7043d3badc4 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Mon, 17 Aug 2026 21:54:29 -0700 Subject: [PATCH 2/8] lfs: exclude big driving model in master clones (#38626) * exclude big * lfs * Revert "lfs" This reverts commit b646d5fb50d2a5be1e6e73275f2ee302687e670f. --- .lfsconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.lfsconfig b/.lfsconfig index 42dfa2d944..e538b9d031 100644 --- a/.lfsconfig +++ b/.lfsconfig @@ -1,4 +1,5 @@ [lfs] url = https://gitlab.com/commaai/openpilot-lfs.git/info/lfs pushurl = ssh://git@gitlab.com/commaai/openpilot-lfs.git + fetchexclude = "openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx" locksverify = false From 3d09a47a4754c6960bceb7d9f2cb0b5a5e537867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Sch=C3=A4fer?= Date: Tue, 18 Aug 2026 14:15:20 -0700 Subject: [PATCH 3/8] cruise planner: fix decel jerk from cruise (#38653) * cruise planner: fix decel jerk from cruise * dead variable --- .../controls/lib/longitudinal_planner.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/openpilot/selfdrive/controls/lib/longitudinal_planner.py b/openpilot/selfdrive/controls/lib/longitudinal_planner.py index c2b8b94abb..cc1345a6ae 100755 --- a/openpilot/selfdrive/controls/lib/longitudinal_planner.py +++ b/openpilot/selfdrive/controls/lib/longitudinal_planner.py @@ -47,9 +47,8 @@ def get_cruise_accel(e2e, v_cruise, v_ego, a_cruise_prev, angle_steers, CP, dt, max_accel = min(max_accel, coast_limit) target_accel = np.clip(v_cruise - v_ego, A_CRUISE_MIN, max_accel) - if not e2e: - j_cruise = np.interp(v_ego, A_CRUISE_MAX_BP, J_CRUISE_VALS) - target_accel = float(np.clip(target_accel, a_cruise_prev - j_cruise * dt, a_cruise_prev + j_cruise * dt)) + j_cruise = np.interp(v_ego, A_CRUISE_MAX_BP, J_CRUISE_VALS) + target_accel = float(np.clip(target_accel, a_cruise_prev - j_cruise * dt, a_cruise_prev + j_cruise * dt)) return target_accel @@ -62,10 +61,9 @@ class LongitudinalPlanner: self.dt = dt self.allow_throttle = True - self.a_desired = init_a self.v_desired_filter = FirstOrderFilter(init_v, 2.0, self.dt) - self.a_cruise = 0.0 - self.output_a_target = 0.0 + self.a_cruise = init_a + self.output_a_target = init_a self.output_should_stop = False self.v_desired_trajectory = np.zeros(CONTROL_N) @@ -100,7 +98,8 @@ class LongitudinalPlanner: if reset_state: self.v_desired_filter.x = v_ego - self.a_desired = np.clip(sm['carState'].aEgo, ACCEL_MIN, ACCEL_MAX) + self.output_a_target = np.clip(sm['carState'].aEgo, ACCEL_MIN, ACCEL_MAX) + self.a_cruise = self.output_a_target # Prevent divergence, smooth in current v_ego self.v_desired_filter.x = max(0.0, self.v_desired_filter.update(v_ego)) @@ -109,7 +108,7 @@ class LongitudinalPlanner: prev_accel_constraint = not (reset_state or sm['carState'].standstill) self.mpc.set_weights(prev_accel_constraint, personality=sm['selfdriveState'].personality) - self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired) + self.mpc.set_cur_state(self.v_desired_filter.x, self.output_a_target) self.mpc.update(sm['radarState'], personality=sm['selfdriveState'].personality) self.v_desired_trajectory = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.v_solution) @@ -122,7 +121,7 @@ class LongitudinalPlanner: cloudlog.info("FCW triggered") # Save starting point for next iteration - a_prev = self.a_desired + a_prev = self.output_a_target action_t = self.CP.longitudinalActuatorDelay + DT_MDL output_a_target_mpc = get_accel_from_plan(self.v_desired_trajectory, self.a_desired_trajectory, CONTROL_N_T_IDX, @@ -145,7 +144,6 @@ class LongitudinalPlanner: self.output_should_stop = any(should_stop for _, _, should_stop in candidates) self.output_a_target = np.clip(output_a_target, ACCEL_MIN, ACCEL_MAX) - self.a_desired = float(self.output_a_target) self.v_desired_filter.x = self.v_desired_filter.x + self.dt * (self.output_a_target + a_prev) / 2.0 def publish(self, sm, pm): From 9f1709a7e152be90a3328438adceb99ef88f30f1 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 18 Aug 2026 18:29:33 -0700 Subject: [PATCH 4/8] Revert "lfs: exclude big driving model in master clones (#38626)" This reverts commit b7657f6553855a569e30e2a971d6e7043d3badc4. --- .lfsconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/.lfsconfig b/.lfsconfig index e538b9d031..42dfa2d944 100644 --- a/.lfsconfig +++ b/.lfsconfig @@ -1,5 +1,4 @@ [lfs] url = https://gitlab.com/commaai/openpilot-lfs.git/info/lfs pushurl = ssh://git@gitlab.com/commaai/openpilot-lfs.git - fetchexclude = "openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx" locksverify = false From 03711a13b0a7740f28ac480b42da67a86ed1d1dd Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 18 Aug 2026 18:31:07 -0700 Subject: [PATCH 5/8] Revert "chestnut: don't compile if big model is LFS pointer" (#38670) Revert "chestnut: don't compile if big model is LFS pointer (#38655)" This reverts commit b8e14d85fbb5e3da1af7f3596e0d9eb49965056d. --- openpilot/selfdrive/modeld/SConscript | 6 +----- openpilot/selfdrive/modeld/helpers.py | 4 ---- openpilot/system/hardware/hardwared.py | 4 ++-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/openpilot/selfdrive/modeld/SConscript b/openpilot/selfdrive/modeld/SConscript index 8b2322f94e..30a31aae27 100644 --- a/openpilot/selfdrive/modeld/SConscript +++ b/openpilot/selfdrive/modeld/SConscript @@ -7,7 +7,7 @@ from openpilot.common.file_chunker import chunk_file, get_chunk_targets, get_exi from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye from openpilot.common.transformations.model import MEDMODEL_INPUT_SIZE, DM_INPUT_SIZE from openpilot.selfdrive.modeld.constants import ModelConstants -from openpilot.selfdrive.modeld.helpers import TG_INPUT_DEVICES_PATH, big_model_source_available, usbgpu_present, modeld_pkl_path +from openpilot.selfdrive.modeld.helpers import TG_INPUT_DEVICES_PATH, usbgpu_present, modeld_pkl_path CAMERA_CONFIGS = [ @@ -44,10 +44,6 @@ tg_devices = { # which device to put jit inputs to at runtime } USBGPU = usbgpu_present() -if USBGPU and not big_model_source_available(): - print("Big model source unavailable, skipping big model build") - USBGPU = False - if USBGPU: usbgpu_tg_flags = f'DEBUG=2 DEV=USB+AMD:LLVM WARP_DEV={tg_backend} FLOAT16=1 JIT_BATCH_SIZE=0 GMMU=0 TC_OPT=2' # the USB+AMD GPU takes an exclusive flock; serialize all targets that touch it diff --git a/openpilot/selfdrive/modeld/helpers.py b/openpilot/selfdrive/modeld/helpers.py index ffd59eae06..37ab0b26d7 100644 --- a/openpilot/selfdrive/modeld/helpers.py +++ b/openpilot/selfdrive/modeld/helpers.py @@ -21,10 +21,6 @@ def modeld_pkl_path(usbgpu: bool): prefix = 'big_' if usbgpu else '' return MODELS_DIR / f'{prefix}driving_tinygrad.pkl' -def big_model_source_available() -> bool: - model_path = MODELS_DIR / 'big_driving_supercombo.onnx' - return model_path.is_file() and model_path.stat().st_size >= 1024 - def dump_oob(obj, f): with tempfile.TemporaryFile(dir=".") as tmp: def buffer_callback(pb: pickle.PickleBuffer): diff --git a/openpilot/system/hardware/hardwared.py b/openpilot/system/hardware/hardwared.py index 2817ef3942..a423d8f97d 100755 --- a/openpilot/system/hardware/hardwared.py +++ b/openpilot/system/hardware/hardwared.py @@ -16,7 +16,6 @@ from openpilot.common.utils import strip_deprecated_keys from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.params import Params from openpilot.common.realtime import DT_HW -from openpilot.selfdrive.modeld.helpers import usbgpu_compiled from openpilot.selfdrive.selfdrived.alertmanager import set_offroad_alert from openpilot.common.hardware import HARDWARE, COMMA_HARDWARE, PC from openpilot.common.basedir import BASEDIR @@ -238,7 +237,8 @@ def hardware_thread(end_event, hw_queue) -> None: fan_controller = FanController(int(1./DT_HW)) chestnut = Chestnut() - big_model_available = usbgpu_compiled() + big_model_available = os.path.isfile(os.path.join(BASEDIR, "openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx")) or \ + os.path.isfile(os.path.join(BASEDIR, "openpilot/selfdrive/modeld/models/big_driving_tinygrad.pkl.chunkmanifest")) while not end_event.is_set(): sm.update(PANDA_STATES_TIMEOUT) From 08c83149b0a61f2e18ba3877439bac34683428ac Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 18 Aug 2026 18:31:59 -0700 Subject: [PATCH 6/8] Pin SCons to 4.10.1 (#38669) --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 78fb53ed1d..c1dd803640 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ dependencies = [ "tqdm", # cars (fw_versions.py) on start + many one-off uses # core - "scons", + "scons==4.10.1", # 4.11 removed the qt3 tool still used to build Cabana "pycapnp==2.1.0", # 2.2 introduces a memory leak due to cyclic references "numpy >=2.0", diff --git a/uv.lock b/uv.lock index b9af0d6adf..20fe78c1fb 100644 --- a/uv.lock +++ b/uv.lock @@ -675,7 +675,7 @@ requires-dist = [ { name = "rednose", marker = "extra == 'submodules'", editable = "rednose_repo" }, { name = "requests" }, { name = "ruff", marker = "extra == 'testing'" }, - { name = "scons" }, + { name = "scons", specifier = "==4.10.1" }, { name = "sentry-sdk" }, { name = "setproctitle" }, { name = "sounddevice" }, @@ -923,11 +923,11 @@ wheels = [ [[package]] name = "scons" -version = "4.11.0" +version = "4.10.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dd/82/3c4e089ac8df2eaee8a7f14e489b2a76f94f4c1d8defa4e46c8ad15cae86/scons-4.11.0.tar.gz", hash = "sha256:5ba48f9e2eb6b9178cabdc9893792418e6970c84f43f4b027e4468e20616a89c", size = 3269126, upload-time = "2026-08-11T04:29:45.62Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/c9/2f430bb39e4eccba32ce8008df4a3206df651276422204e177a09e12b30b/scons-4.10.1.tar.gz", hash = "sha256:99c0e94a42a2c1182fa6859b0be697953db07ba936ecc9817ae0d218ced20b15", size = 3258403, upload-time = "2025-11-16T22:43:39.258Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/ac/a4445bbbd58a5fa6a5c8b3b0458ffbee04e4acaff87677058eab9c6af682/scons-4.11.0-py3-none-any.whl", hash = "sha256:2edc077aaeafc43377ba46ce1fa3e7b40edea59c62db9ef7e39e07dc88b754fa", size = 4123742, upload-time = "2026-08-11T04:29:42.881Z" }, + { url = "https://files.pythonhosted.org/packages/ce/bf/931fb9fbb87234c32b8b1b1c15fba23472a10777c12043336675633809a7/scons-4.10.1-py3-none-any.whl", hash = "sha256:bd9d1c52f908d874eba92a8c0c0a8dcf2ed9f3b88ab956d0fce1da479c4e7126", size = 4136069, upload-time = "2025-11-16T22:43:35.933Z" }, ] [[package]] From 3c90b66b65777a233b6288ecd009a3806f1ab439 Mon Sep 17 00:00:00 2001 From: stef <19478336+stefpi@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:40:11 -0400 Subject: [PATCH 7/8] webrtcd: bind to localhost (#38664) check content type and bind to localhost --- openpilot/system/webrtc/tests/test_stream_session.py | 7 ++++++- openpilot/system/webrtc/webrtcd.py | 9 ++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/openpilot/system/webrtc/tests/test_stream_session.py b/openpilot/system/webrtc/tests/test_stream_session.py index d64cf6aed6..03d540c3c2 100644 --- a/openpilot/system/webrtc/tests/test_stream_session.py +++ b/openpilot/system/webrtc/tests/test_stream_session.py @@ -7,7 +7,7 @@ from openpilot.common.test import OpenpilotTestCase from openpilot.cereal import messaging, log from teleoprtc.tracks import VIDEO_CLOCK_RATE -from openpilot.system.webrtc.webrtcd import CerealOutgoingMessageProxy, CerealIncomingMessageProxy +from openpilot.system.webrtc.webrtcd import CerealOutgoingMessageProxy, CerealIncomingMessageProxy, ServerState, handle_get_stream from openpilot.system.webrtc.device.video import LiveStreamVideoStreamTrack @@ -80,3 +80,8 @@ class TestStreamSession(OpenpilotTestCase): start_pts = packet.pts assert abs(i + packet.pts - (start_pts + (((time.monotonic_ns() - start_ns) * VIDEO_CLOCK_RATE) // 1_000_000_000))) < 450 #5ms assert bytes(packet) == b"" + + def test_stream_rejects_non_json_content_type(self): + response = self.loop.run_until_complete(handle_get_stream(ServerState(), b"{}", "text/plain")) + + assert response == (415, b'{"error": "unsupported media type"}', "application/json; charset=utf-8") diff --git a/openpilot/system/webrtc/webrtcd.py b/openpilot/system/webrtc/webrtcd.py index 8e022eda1c..3c0c3037f3 100755 --- a/openpilot/system/webrtc/webrtcd.py +++ b/openpilot/system/webrtc/webrtcd.py @@ -395,7 +395,10 @@ def _text_response(text: str, status: int = 200) -> tuple[int, bytes, str]: return (status, text.encode(), "text/plain; charset=utf-8") -async def handle_get_stream(state: ServerState, raw_body: bytes) -> tuple[int, bytes, str]: +async def handle_get_stream(state: ServerState, raw_body: bytes, content_type: str) -> tuple[int, bytes, str]: + if content_type != "application/json": + return _json_response({"error": "unsupported media type"}, status=415) + stream_dict = state.streams body = StreamRequestBody(**json.loads(raw_body)) @@ -508,7 +511,7 @@ class WebrtcdHandler(BaseHTTPRequestHandler): services = parse_qs(parsed.query).get("services", [""])[0] result = self._run(handle_get_schema(self.server.state, services)) elif parsed.path == "/stream": - result = self._run(handle_get_stream(self.server.state, self._read_body())) + result = self._run(handle_get_stream(self.server.state, self._read_body(), self.headers.get_content_type())) else: # /notify try: payload = json.loads(self._read_body()) @@ -611,7 +614,7 @@ def webrtcd_thread(host: str, port: int): def main(): parser = argparse.ArgumentParser(description="WebRTC daemon") - parser.add_argument("--host", type=str, default="0.0.0.0", help="Host to listen on") + parser.add_argument("--host", type=str, default="127.0.0.1", help="Host to listen on") parser.add_argument("--port", type=int, default=5001, help="Port to listen on") args = parser.parse_args() From 8edce0da4492307df211c710af6c4ece1c4a218e Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Tue, 18 Aug 2026 18:40:54 -0700 Subject: [PATCH 8/8] Clean up big model detection w/ helpers (#38671) use helpers --- openpilot/system/hardware/hardwared.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpilot/system/hardware/hardwared.py b/openpilot/system/hardware/hardwared.py index a423d8f97d..16eb18d153 100755 --- a/openpilot/system/hardware/hardwared.py +++ b/openpilot/system/hardware/hardwared.py @@ -16,6 +16,7 @@ from openpilot.common.utils import strip_deprecated_keys from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.params import Params from openpilot.common.realtime import DT_HW +from openpilot.selfdrive.modeld.helpers import MODELS_DIR, usbgpu_compiled from openpilot.selfdrive.selfdrived.alertmanager import set_offroad_alert from openpilot.common.hardware import HARDWARE, COMMA_HARDWARE, PC from openpilot.common.basedir import BASEDIR @@ -237,8 +238,7 @@ def hardware_thread(end_event, hw_queue) -> None: fan_controller = FanController(int(1./DT_HW)) chestnut = Chestnut() - big_model_available = os.path.isfile(os.path.join(BASEDIR, "openpilot/selfdrive/modeld/models/big_driving_supercombo.onnx")) or \ - os.path.isfile(os.path.join(BASEDIR, "openpilot/selfdrive/modeld/models/big_driving_tinygrad.pkl.chunkmanifest")) + big_model_available = (MODELS_DIR / 'big_driving_supercombo.onnx').is_file() or usbgpu_compiled() while not end_event.is_set(): sm.update(PANDA_STATES_TIMEOUT)