From 4d65c52e6d16ac1604d5d21d6f8e691391046bd2 Mon Sep 17 00:00:00 2001 From: James Vecellio-Grant <159560811+Discountchubbs@users.noreply.github.com> Date: Thu, 5 Feb 2026 05:35:57 -0800 Subject: [PATCH 1/4] modeld_v2: refactor abstract class to support off-policy models (#1672) * modeld_v2: refactor abstract class to support off-policy models. * whoops * bump --- cereal/custom.capnp | 1 + release/ci/model_generator.py | 4 ++- sunnypilot/modeld_v2/SConscript | 4 +-- sunnypilot/modeld_v2/install_models_pc.py | 2 +- sunnypilot/models/fetcher.py | 2 +- .../models/runners/tinygrad/model_types.py | 16 ++++++++++ .../runners/tinygrad/tinygrad_runner.py | 32 +++++++++++++++---- 7 files changed, 50 insertions(+), 11 deletions(-) diff --git a/cereal/custom.capnp b/cereal/custom.capnp index 5c0a004fa6..53986262ec 100644 --- a/cereal/custom.capnp +++ b/cereal/custom.capnp @@ -153,6 +153,7 @@ struct ModelManagerSP @0xaedffd8f31e7b55d { navigation @1; vision @2; policy @3; + offPolicy @4; } } diff --git a/release/ci/model_generator.py b/release/ci/model_generator.py index ee41343be8..96352254b6 100755 --- a/release/ci/model_generator.py +++ b/release/ci/model_generator.py @@ -68,8 +68,10 @@ def generate_metadata(model_path: Path, output_dir: Path, short_name: str): metadata_file = metadata_file.rename(output_path / f"{base}_{short_name.lower()}_metadata.pkl") # Build the metadata structure + model_type = "offPolicy" if "off_policy" in base else base.split("_")[-1] + model_metadata = { - "type": base.split("_")[-1] if "dmonitoring" not in base else "dmonitoring", + "type": model_type, "artifact": { "file_name": tinygrad_file.name, "download_uri": { diff --git a/sunnypilot/modeld_v2/SConscript b/sunnypilot/modeld_v2/SConscript index 48b9c75ef5..94033846b0 100644 --- a/sunnypilot/modeld_v2/SConscript +++ b/sunnypilot/modeld_v2/SConscript @@ -39,7 +39,7 @@ if PC: model_dir = Dir("models").abspath cmd = f'python3 {Dir("#sunnypilot/modeld_v2").abspath}/install_models_pc.py {model_dir}' - for model_name in ['supercombo', 'driving_vision', 'driving_policy']: + for model_name in ['supercombo', 'driving_vision', 'driving_off_policy', 'driving_policy']: if File(f"models/{model_name}.onnx").exists(): inputs.append(File(f"models/{model_name}.onnx")) inputs.append(File(f"models/{model_name}_tinygrad.pkl")) @@ -57,7 +57,7 @@ def tg_compile(flags, model_name): ) # Compile small models -for model_name in ['supercombo', 'driving_vision', 'driving_policy']: +for model_name in ['supercombo', 'driving_vision', 'driving_off_policy', 'driving_policy']: if File(f"models/{model_name}.onnx").exists(): flags = { 'larch64': 'DEV=QCOM', diff --git a/sunnypilot/modeld_v2/install_models_pc.py b/sunnypilot/modeld_v2/install_models_pc.py index 3f964dc285..a378d90b11 100755 --- a/sunnypilot/modeld_v2/install_models_pc.py +++ b/sunnypilot/modeld_v2/install_models_pc.py @@ -44,7 +44,7 @@ def generate_metadata_pkl(model_path, output_path): def install_models(model_dir): model_dir = Path(model_dir) - models = ["driving_policy", "driving_vision"] + models = ["driving_off_policy", "driving_policy", "driving_vision"] found_models = [] for model in models: diff --git a/sunnypilot/models/fetcher.py b/sunnypilot/models/fetcher.py index a917d6cbb8..1d8da083a9 100644 --- a/sunnypilot/models/fetcher.py +++ b/sunnypilot/models/fetcher.py @@ -116,7 +116,7 @@ class ModelCache: class ModelFetcher: """Handles fetching and caching of model data from remote source""" - MODEL_URL = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-docs/refs/heads/gh-pages/docs/driving_models_v10.json" + MODEL_URL = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-docs/refs/heads/gh-pages/docs/driving_models_v11.json" def __init__(self, params: Params): self.params = params diff --git a/sunnypilot/models/runners/tinygrad/model_types.py b/sunnypilot/models/runners/tinygrad/model_types.py index ba388aed93..11f0965828 100644 --- a/sunnypilot/models/runners/tinygrad/model_types.py +++ b/sunnypilot/models/runners/tinygrad/model_types.py @@ -13,6 +13,22 @@ SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') CUSTOM_MODEL_PATH = Paths.model_root() +class OffPolicyTinygrad(ModularRunner, ABC): + """ + A TinygradRunner specialized for off-policy models. + + Uses a SplitParser to handle outputs specific to the off-policy part of a split model setup. + """ + def __init__(self): + self._off_policy_parser = SplitParser() + self.parser_method_dict[ModelType.offPolicy] = self._parse_off_policy_outputs + + def _parse_off_policy_outputs(self, model_outputs: np.ndarray) -> NumpyDict: + """Parses off-policy model outputs using SplitParser.""" + result: NumpyDict = self._off_policy_parser.parse_policy_outputs(self._slice_outputs(model_outputs)) + return result + + class PolicyTinygrad(ModularRunner, ABC): """ A TinygradRunner specialized for policy-only models. diff --git a/sunnypilot/models/runners/tinygrad/tinygrad_runner.py b/sunnypilot/models/runners/tinygrad/tinygrad_runner.py index 2800179fb2..7b48e3086b 100644 --- a/sunnypilot/models/runners/tinygrad/tinygrad_runner.py +++ b/sunnypilot/models/runners/tinygrad/tinygrad_runner.py @@ -4,7 +4,7 @@ import numpy as np from openpilot.sunnypilot.modeld_v2.runners.tinygrad_helpers import qcom_tensor_from_opencl_address from openpilot.sunnypilot.models.runners.constants import CLMemDict, FrameDict, NumpyDict, ModelType, ShapeDict, CUSTOM_MODEL_PATH, SliceDict from openpilot.sunnypilot.models.runners.model_runner import ModelRunner -from openpilot.sunnypilot.models.runners.tinygrad.model_types import PolicyTinygrad, VisionTinygrad, SupercomboTinygrad +from openpilot.sunnypilot.models.runners.tinygrad.model_types import PolicyTinygrad, VisionTinygrad, SupercomboTinygrad, OffPolicyTinygrad from openpilot.system.hardware import TICI from openpilot.sunnypilot.models.split_model_constants import SplitModelConstants from openpilot.sunnypilot.modeld_v2.constants import ModelConstants @@ -12,7 +12,7 @@ from openpilot.sunnypilot.modeld_v2.constants import ModelConstants from tinygrad.tensor import Tensor -class TinygradRunner(ModelRunner, SupercomboTinygrad, PolicyTinygrad, VisionTinygrad): +class TinygradRunner(ModelRunner, SupercomboTinygrad, PolicyTinygrad, VisionTinygrad, OffPolicyTinygrad): """ A ModelRunner implementation for executing Tinygrad models. @@ -27,6 +27,7 @@ class TinygradRunner(ModelRunner, SupercomboTinygrad, PolicyTinygrad, VisionTiny SupercomboTinygrad.__init__(self) PolicyTinygrad.__init__(self) VisionTinygrad.__init__(self) + OffPolicyTinygrad.__init__(self) self._constants = ModelConstants self._model_data = self.models.get(model_type) if not self._model_data or not self._model_data.model: @@ -106,13 +107,20 @@ class TinygradSplitRunner(ModelRunner): self.is_20hz_3d = True self.vision_runner = TinygradRunner(ModelType.vision) self.policy_runner = TinygradRunner(ModelType.policy) + self.off_policy_runner = TinygradRunner(ModelType.offPolicy) if self.models.get(ModelType.offPolicy) else None self._constants = SplitModelConstants def _run_model(self) -> NumpyDict: """Runs both vision and policy models and merges their parsed outputs.""" policy_output = self.policy_runner.run_model() vision_output = self.vision_runner.run_model() - return {**policy_output, **vision_output} # Combine results + outputs = {**policy_output, **vision_output} + + if self.off_policy_runner: + off_policy_output = self.off_policy_runner.run_model() + outputs.update(off_policy_output) + + return outputs @property def vision_input_names(self) -> list[str]: @@ -122,12 +130,18 @@ class TinygradSplitRunner(ModelRunner): @property def input_shapes(self) -> ShapeDict: """Returns the combined input shapes from both vision and policy models.""" - return {**self.policy_runner.input_shapes, **self.vision_runner.input_shapes} + shapes = {**self.policy_runner.input_shapes, **self.vision_runner.input_shapes} + if self.off_policy_runner: + shapes.update(self.off_policy_runner.input_shapes) + return shapes @property def output_slices(self) -> SliceDict: """Returns the combined output slices from both vision and policy models.""" - return {**self.policy_runner.output_slices, **self.vision_runner.output_slices} + slices = {**self.policy_runner.output_slices, **self.vision_runner.output_slices} + if self.off_policy_runner: + slices.update(self.off_policy_runner.output_slices) + return slices def prepare_inputs(self, imgs_cl: CLMemDict, numpy_inputs: NumpyDict, frames: FrameDict) -> dict: """Prepares inputs for both vision and policy models.""" @@ -135,5 +149,11 @@ class TinygradSplitRunner(ModelRunner): self.policy_runner.prepare_policy_inputs(numpy_inputs) # Vision inputs depend on imgs_cl and frames self.vision_runner.prepare_vision_inputs(imgs_cl, frames) + inputs = {**self.policy_runner.inputs, **self.vision_runner.inputs} + + if self.off_policy_runner: + self.off_policy_runner.prepare_policy_inputs(numpy_inputs) + inputs.update(self.off_policy_runner.inputs) + # Return combined inputs (though they are stored within respective runners) - return {**self.policy_runner.inputs, **self.vision_runner.inputs} + return inputs From c908189e73af3b3d15f1c1945d8b05dae035fd42 Mon Sep 17 00:00:00 2001 From: royjr Date: Sun, 8 Feb 2026 00:32:12 -0500 Subject: [PATCH 2/4] ui: use correct signals while using PID with Developer UI (#1674) * only if angleState * pidState element --- .../onroad/developer_ui/__init__.py | 7 ++++-- .../onroad/developer_ui/elements.py | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/selfdrive/ui/sunnypilot/onroad/developer_ui/__init__.py b/selfdrive/ui/sunnypilot/onroad/developer_ui/__init__.py index 441a169d23..f74f1f4c30 100644 --- a/selfdrive/ui/sunnypilot/onroad/developer_ui/__init__.py +++ b/selfdrive/ui/sunnypilot/onroad/developer_ui/__init__.py @@ -10,7 +10,7 @@ from openpilot.selfdrive.ui.sunnypilot.onroad.developer_ui.elements import ( UiElement, RelDistElement, RelSpeedElement, SteeringAngleElement, DesiredLateralAccelElement, ActualLateralAccelElement, DesiredSteeringAngleElement, AEgoElement, LeadSpeedElement, FrictionCoefficientElement, LatAccelFactorElement, - SteeringTorqueEpsElement, BearingDegElement, AltitudeElement + SteeringTorqueEpsElement, BearingDegElement, AltitudeElement, DesiredSteeringPIDElement ) from openpilot.system.ui.lib.application import gui_app, FontWeight from openpilot.system.ui.lib.text_measure import measure_text_cached @@ -36,6 +36,7 @@ class DeveloperUiRenderer(Widget): self.desired_lat_accel_elem = DesiredLateralAccelElement() self.actual_lat_accel_elem = ActualLateralAccelElement() self.desired_steer_elem = DesiredSteeringAngleElement() + self.desired_pid_steer_elem = DesiredSteeringPIDElement() self.a_ego_elem = AEgoElement() self.lead_speed_elem = LeadSpeedElement() self.friction_elem = FrictionCoefficientElement() @@ -85,8 +86,10 @@ class DeveloperUiRenderer(Widget): ] if controls_state.lateralControlState.which() == 'torqueState': elements.append(self.desired_lat_accel_elem.update(sm, ui_state.is_metric)) - else: + elif controls_state.lateralControlState.which() == 'angleState': elements.append(self.desired_steer_elem.update(sm, ui_state.is_metric)) + elif controls_state.lateralControlState.which() == 'pidState': + elements.append(self.desired_pid_steer_elem.update(sm, ui_state.is_metric)) elements.append(self.actual_lat_accel_elem.update(sm, ui_state.is_metric)) diff --git a/selfdrive/ui/sunnypilot/onroad/developer_ui/elements.py b/selfdrive/ui/sunnypilot/onroad/developer_ui/elements.py index 652469bddd..94e3af42eb 100644 --- a/selfdrive/ui/sunnypilot/onroad/developer_ui/elements.py +++ b/selfdrive/ui/sunnypilot/onroad/developer_ui/elements.py @@ -191,6 +191,31 @@ class DesiredLateralAccelElement(LateralControlElement): return UiElement(value, "DESIRED L.A.", self.unit, color) +class DesiredSteeringPIDElement(LateralControlElement): + def __init__(self): + self.unit = "" + + def update(self, sm, is_metric: bool) -> UiElement: + car_state = sm['carState'] + controls_state = sm['controlsState'] + lat_active = sm['carControl'].latActive + angle_steers = car_state.steeringAngleDeg + steer_angle_desired = controls_state.lateralControlState.pidState.steeringAngleDesiredDeg + + value = f"{steer_angle_desired:.1f}°" if lat_active else "-" + + color = rl.WHITE + if lat_active: + if abs(angle_steers) > 180: + color = rl.RED + elif abs(angle_steers) > 90: + color = rl.Color(255, 188, 0, 255) + else: + color = rl.Color(0, 255, 0, 255) + + return UiElement(value, "DESIRED STEER", self.unit, color) + + class AEgoElement: def __init__(self): self.unit = "m/s^2" From 81bd8aa0e262ed2a5cfb024d1214d0a34231c352 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 01:03:16 -0500 Subject: [PATCH 3/4] [bot] Update Python packages (#1662) * Update Python packages * bump --------- Co-authored-by: github-actions[bot] Co-authored-by: Jason Wen --- docs/CARS.md | 11 +---------- opendbc_repo | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/docs/CARS.md b/docs/CARS.md index a1f50e41d0..ab1eabeb13 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. -# 344 Supported Cars +# 335 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video|Setup Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -23,10 +23,7 @@ A supported vehicle is one that just works when you install a comma device. All |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,14](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 OBD-C cable (2 ft)
- 1 VW J533 connector
- 1 comma four
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
Buy Here
||| |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 harness box
- 1 mount
Buy Here
||| |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 harness box
- 1 mount
Buy Here
||| -|Chevrolet|Bolt EV Non-ACC 2017|Adaptive Cruise Control (ACC)|Stock|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 harness box
- 1 mount
Buy Here
||| -|Chevrolet|Bolt EV Non-ACC 2018-21|Adaptive Cruise Control (ACC)|Stock|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 harness box
- 1 mount
Buy Here
||| |Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 harness box
- 1 mount
Buy Here
||| -|Chevrolet|Malibu Non-ACC 2016-23|Adaptive Cruise Control (ACC)|Stock|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 harness box
- 1 mount
Buy Here
||| |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 harness box
- 1 mount
Buy Here
||| |Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 harness box
- 1 mount
Buy Here
||| |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| @@ -91,7 +88,6 @@ A supported vehicle is one that just works when you install a comma device. All |Honda|Civic Hatchback Hybrid 2025-26|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Honda|Civic Hybrid 2025-26|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| -|Honda|Clarity 2018-21|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Nidec connector + Honda Clarity Proxy Board
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|15 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Honda|CR-V 2023-26|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch C connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| @@ -122,7 +118,6 @@ A supported vehicle is one that just works when you install a comma device. All |Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| -|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai J connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| @@ -140,9 +135,7 @@ A supported vehicle is one that just works when you install a comma device. All |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai O connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai R connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| -|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai I connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| -|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai B connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Nexo 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| @@ -166,13 +159,11 @@ A supported vehicle is one that just works when you install a comma device. All |Kia|Carnival 2022-24|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| -|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai I connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|EV6 (Southeast Asia only) 2022-24|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai G connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| -|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| |Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 OBD-C cable (2 ft)
- 1 comma four
- 1 comma power v3
- 1 harness box
- 1 mount
Buy Here
||| diff --git a/opendbc_repo b/opendbc_repo index 1abdb9872f..ff2f9686c2 160000 --- a/opendbc_repo +++ b/opendbc_repo @@ -1 +1 @@ -Subproject commit 1abdb9872f22c361322ac9e29d376c35233ba890 +Subproject commit ff2f9686c208824a72b30d4cc540a6ab78c5983e From 35c87a151972c88f8251f8d877be615ced253334 Mon Sep 17 00:00:00 2001 From: royjr Date: Sun, 8 Feb 2026 17:00:37 -0500 Subject: [PATCH 4/4] [TIZI/TICI] ui: steering arc (#1628) * init * lint * add toggle * Update params_keys.h * Update params_metadata.json * Update params_keys.h * bool * decouple * no * make it perfect * fade it * only with torque bar * dynamic * in another PR --------- Co-authored-by: Jason Wen --- common/params_keys.h | 1 + selfdrive/ui/mici/onroad/torque_bar.py | 16 ++++++++------- selfdrive/ui/onroad/augmented_road_view.py | 8 +++++--- .../sunnypilot/onroad/augmented_road_view.py | 20 ++++++++++++++++++- .../ui/sunnypilot/onroad/hud_renderer.py | 9 +++++++++ selfdrive/ui/sunnypilot/ui_state.py | 1 + sunnypilot/sunnylink/params_metadata.json | 4 ++++ 7 files changed, 48 insertions(+), 11 deletions(-) diff --git a/common/params_keys.h b/common/params_keys.h index ecc656cc78..44584c9113 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -115,6 +115,7 @@ inline static std::unordered_map keys = { {"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, {"SshEnabled", {PERSISTENT | BACKUP, BOOL}}, {"TermsVersion", {PERSISTENT, STRING}}, + {"TorqueBar", {PERSISTENT | BACKUP, BOOL, "0"}}, {"TrainingVersion", {PERSISTENT, STRING}}, {"UbloxAvailable", {PERSISTENT, BOOL}}, {"UpdateAvailable", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, diff --git a/selfdrive/ui/mici/onroad/torque_bar.py b/selfdrive/ui/mici/onroad/torque_bar.py index c8485a3101..c1de694633 100644 --- a/selfdrive/ui/mici/onroad/torque_bar.py +++ b/selfdrive/ui/mici/onroad/torque_bar.py @@ -146,9 +146,11 @@ def arc_bar_pts(cx: float, cy: float, class TorqueBar(Widget): - def __init__(self, demo: bool = False): + def __init__(self, demo: bool = False, scale: float = 1.0, always: bool = False): super().__init__() self._demo = demo + self._scale = scale + self._always = always self._torque_filter = FirstOrderFilter(0, 0.1, 1 / gui_app.target_fps) self._torque_line_alpha_filter = FirstOrderFilter(0.0, 0.1, 1 / gui_app.target_fps) @@ -180,8 +182,8 @@ class TorqueBar(Widget): def _render(self, rect: rl.Rectangle) -> None: # adjust y pos with torque - torque_line_offset = np.interp(abs(self._torque_filter.x), [0.5, 1], [22, 26]) - torque_line_height = np.interp(abs(self._torque_filter.x), [0.5, 1], [14, 56]) + torque_line_offset = np.interp(abs(self._torque_filter.x), [0.5, 1], [22 * self._scale, 26 * self._scale]) + torque_line_height = np.interp(abs(self._torque_filter.x), [0.5, 1], [14 * self._scale, 56 * self._scale]) # animate alpha and angle span if not self._demo: @@ -195,7 +197,7 @@ class TorqueBar(Widget): torque_line_bg_color = rl.Color(255, 255, 255, int(255 * 0.15 * self._torque_line_alpha_filter.x)) # draw curved line polygon torque bar - torque_line_radius = 1200 + torque_line_radius = 1200 * self._scale top_angle = -90 torque_bg_angle_span = self._torque_line_alpha_filter.x * TORQUE_ANGLE_SPAN torque_start_angle = top_angle - torque_bg_angle_span / 2 @@ -207,13 +209,13 @@ class TorqueBar(Widget): cy = rect.y + rect.height + torque_line_radius - torque_line_offset # draw bg torque indicator line - bg_pts = arc_bar_pts(cx, cy, mid_r, torque_line_height, torque_start_angle, torque_end_angle) + bg_pts = arc_bar_pts(cx, cy, mid_r, torque_line_height, torque_start_angle, torque_end_angle, cap_radius=7 * self._scale) draw_polygon(rect, bg_pts, color=torque_line_bg_color) # draw torque indicator line a0s = top_angle a1s = a0s + torque_bg_angle_span / 2 * self._torque_filter.x - sl_pts = arc_bar_pts(cx, cy, mid_r, torque_line_height, a0s, a1s) + sl_pts = arc_bar_pts(cx, cy, mid_r, torque_line_height, a0s, a1s, cap_radius=7 * self._scale) # draw beautiful gradient from center to 65% of the bg torque bar width start_grad_pt = cx / rect.width @@ -252,5 +254,5 @@ class TorqueBar(Widget): # draw center torque bar dot if abs(self._torque_filter.x) < 0.5: dot_y = self._rect.y + self._rect.height - torque_line_offset - torque_line_height / 2 - rl.draw_circle(int(cx), int(dot_y), 10 // 2, + rl.draw_circle(int(cx), int(dot_y), (10 // 2 * self._scale), rl.Color(182, 182, 182, int(255 * 0.9 * self._torque_line_alpha_filter.x))) diff --git a/selfdrive/ui/onroad/augmented_road_view.py b/selfdrive/ui/onroad/augmented_road_view.py index bcbcb2dcfb..76e7b078d1 100644 --- a/selfdrive/ui/onroad/augmented_road_view.py +++ b/selfdrive/ui/onroad/augmented_road_view.py @@ -15,7 +15,7 @@ from openpilot.common.transformations.camera import DEVICE_CAMERAS, DeviceCamera from openpilot.common.transformations.orientation import rot_from_euler if gui_app.sunnypilot_ui(): - from openpilot.selfdrive.ui.sunnypilot.onroad.augmented_road_view import BORDER_COLORS_SP + from openpilot.selfdrive.ui.sunnypilot.onroad.augmented_road_view import BORDER_COLORS_SP, AugmentedRoadViewSP from openpilot.selfdrive.ui.sunnypilot.onroad.driver_state import DriverStateRendererSP as DriverStateRenderer from openpilot.selfdrive.ui.sunnypilot.onroad.hud_renderer import HudRendererSP as HudRenderer from openpilot.selfdrive.ui.sunnypilot.ui_state import OnroadTimerStatus @@ -38,9 +38,10 @@ ROAD_CAM_MIN_SPEED = 15.0 # m/s (34 mph) INF_POINT = np.array([1000.0, 0.0, 0.0]) -class AugmentedRoadView(CameraView): +class AugmentedRoadView(CameraView, AugmentedRoadViewSP): def __init__(self, stream_type: VisionStreamType = VisionStreamType.VISION_STREAM_ROAD): - super().__init__("camerad", stream_type) + CameraView.__init__(self, "camerad", stream_type) + AugmentedRoadViewSP.__init__(self) self._set_placeholder_color(BORDER_COLORS[UIStatus.DISENGAGED]) self.device_camera: DeviceCameraConfig | None = None @@ -92,6 +93,7 @@ class AugmentedRoadView(CameraView): # Draw all UI overlays self.model_renderer.render(self._content_rect) + AugmentedRoadViewSP.update_fade_out_bottom_overlay(self, self._content_rect) self._hud_renderer.render(self._content_rect) self.alert_renderer.render(self._content_rect) self.driver_state_renderer.render(self._content_rect) diff --git a/selfdrive/ui/sunnypilot/onroad/augmented_road_view.py b/selfdrive/ui/sunnypilot/onroad/augmented_road_view.py index 0a5739cc00..c7dedee540 100644 --- a/selfdrive/ui/sunnypilot/onroad/augmented_road_view.py +++ b/selfdrive/ui/sunnypilot/onroad/augmented_road_view.py @@ -5,9 +5,27 @@ This file is part of sunnypilot and is licensed under the MIT License. See the LICENSE.md file in the root directory for more details. """ import pyray as rl -from openpilot.selfdrive.ui.ui_state import UIStatus +from openpilot.common.filter_simple import FirstOrderFilter +from openpilot.selfdrive.ui.ui_state import UIStatus, ui_state +from openpilot.system.ui.lib.application import gui_app BORDER_COLORS_SP = { UIStatus.LAT_ONLY: rl.Color(0x00, 0xC8, 0xC8, 0xFF), # Cyan for lateral-only state UIStatus.LONG_ONLY: rl.Color(0x96, 0x1C, 0xA8, 0xFF), # Purple for longitudinal-only state } + + +class AugmentedRoadViewSP: + def __init__(self): + self._fade_texture = gui_app.texture("icons_mici/onroad/onroad_fade.png") + self._fade_alpha_filter = FirstOrderFilter(0, 0.1, 1 / gui_app.target_fps) + + def update_fade_out_bottom_overlay(self, _content_rect): + # Fade out bottom of overlays for looks (only when engaged) + fade_alpha = self._fade_alpha_filter.update(ui_state.status != UIStatus.DISENGAGED) + if ui_state.torque_bar and fade_alpha > 1e-2: + # Scale the fade texture to the content rect + rl.draw_texture_pro(self._fade_texture, + rl.Rectangle(0, 0, self._fade_texture.width, self._fade_texture.height), + _content_rect, rl.Vector2(0, 0), 0.0, + rl.Color(255, 255, 255, int(255 * fade_alpha))) diff --git a/selfdrive/ui/sunnypilot/onroad/hud_renderer.py b/selfdrive/ui/sunnypilot/onroad/hud_renderer.py index 8ca7269802..74e15fe0bd 100644 --- a/selfdrive/ui/sunnypilot/onroad/hud_renderer.py +++ b/selfdrive/ui/sunnypilot/onroad/hud_renderer.py @@ -6,6 +6,7 @@ See the LICENSE.md file in the root directory for more details. """ import pyray as rl +from openpilot.selfdrive.ui.mici.onroad.torque_bar import TorqueBar from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.selfdrive.ui.onroad.hud_renderer import HudRenderer from openpilot.selfdrive.ui.sunnypilot.onroad.developer_ui import DeveloperUiRenderer @@ -23,6 +24,7 @@ class HudRendererSP(HudRenderer): self.rocket_fuel = RocketFuel() self.speed_limit_renderer = SpeedLimitRenderer() self.turn_signal_controller = TurnSignalController() + self._torque_bar = TorqueBar(scale=3.0, always=True) def _update_state(self) -> None: super()._update_state() @@ -32,6 +34,13 @@ class HudRendererSP(HudRenderer): def _render(self, rect: rl.Rectangle) -> None: super()._render(rect) + + if ui_state.torque_bar and ui_state.sm['controlsState'].lateralControlState.which() != 'angleState': + torque_rect = rect + if ui_state.developer_ui in (DeveloperUiRenderer.DEV_UI_BOTTOM, DeveloperUiRenderer.DEV_UI_BOTH): + torque_rect = rl.Rectangle(rect.x, rect.y, rect.width, rect.height - DeveloperUiRenderer.BOTTOM_BAR_HEIGHT) + self._torque_bar.render(torque_rect) + self.developer_ui.render(rect) self.road_name_renderer.render(rect) self.speed_limit_renderer.render(rect) diff --git a/selfdrive/ui/sunnypilot/ui_state.py b/selfdrive/ui/sunnypilot/ui_state.py index f38280d498..98ddbe5266 100644 --- a/selfdrive/ui/sunnypilot/ui_state.py +++ b/selfdrive/ui/sunnypilot/ui_state.py @@ -125,6 +125,7 @@ class UIStateSP: self.rocket_fuel = self.params.get_bool("RocketFuel") self.rainbow_path = self.params.get_bool("RainbowMode") self.chevron_metrics = self.params.get("ChevronInfo") + self.torque_bar = self.params.get_bool("TorqueBar") self.active_bundle = self.params.get("ModelManager_ActiveBundle") self.custom_interactive_timeout = self.params.get("InteractivityTimeout", return_default=True) self.speed_limit_mode = self.params.get("SpeedLimitMode", return_default=True) diff --git a/sunnypilot/sunnylink/params_metadata.json b/sunnypilot/sunnylink/params_metadata.json index 7f597a9621..090beb49f0 100644 --- a/sunnypilot/sunnylink/params_metadata.json +++ b/sunnypilot/sunnylink/params_metadata.json @@ -1239,6 +1239,10 @@ "title": "Tesla Coop Steering", "description": "" }, + "TorqueBar": { + "title": "Steering Arc", + "description": "[TIZI/TICI only] Display steering arc on the driving screen when lateral control is enabled." + }, "TorqueParamsOverrideEnabled": { "title": "Manual Real-Time Tuning", "description": ""