mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-09-01 23:43:46 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 72deb91942 | |||
| d5b5652165 |
@@ -2,6 +2,5 @@ Wen
|
||||
REGIST
|
||||
PullRequest
|
||||
cancelled
|
||||
indeces
|
||||
FOF
|
||||
NoO
|
||||
|
||||
Generated
-7
@@ -21,12 +21,5 @@
|
||||
</clean>
|
||||
</configuration>
|
||||
</target>
|
||||
<target id="f2590b2b-9b93-49f9-8510-da3f3724a2ae" name="replay" defaultType="TOOL">
|
||||
<configuration id="d475264f-6f4c-4092-9b4e-6773309f38b7" name="replay" toolchainName="Default">
|
||||
<build type="TOOL">
|
||||
<tool actionId="Tool_External Tools_uv build tools replay" />
|
||||
</build>
|
||||
</configuration>
|
||||
</target>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-7
@@ -20,11 +20,4 @@
|
||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||
</exec>
|
||||
</tool>
|
||||
<tool name="uv build tools replay" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
||||
<exec>
|
||||
<option name="COMMAND" value="bash" />
|
||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) tools/replay/"" />
|
||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||
</exec>
|
||||
</tool>
|
||||
</toolSet>
|
||||
@@ -1,5 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Build Debug" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="openpilot-special" TARGET_NAME="uv Scons Build Debug" CONFIG_NAME="uv Scons Build Debug" RUN_PATH="ui">
|
||||
<configuration default="false" name="Build Debug" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="sunnypilot" TARGET_NAME="uv Scons Build Debug" CONFIG_NAME="uv Scons Build Debug" RUN_PATH="ui">
|
||||
<envs>
|
||||
<env name="QT_DBL_CLICK_DIST" value="150" />
|
||||
</envs>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Debug Route Controls" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="openpilot-special" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
<env name="FINGERPRINT" value="KIA_EV9" />
|
||||
<env name="SKIP_FW_QUERY" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/selfdrive/car" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/selfdrive/car/card.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,7 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Replay for controls + ui" type="Multirun" separateTabs="false" reuseTabsWithFailures="false" startOneByOne="true" markFailedProcess="true" hideSuccessProcess="false" delayTime="0.0">
|
||||
<runConfiguration name="replay for controls" type="Native Application" />
|
||||
<runConfiguration name="Build Debug" type="Custom Build Application" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,7 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="replay for controls" type="CLionNativeAppRunConfigurationType" focusToolWindowBeforeRun="true" PROGRAM_PARAMS=""$Prompt$" --block "sendcan,carState,carParams,carOutput,liveTracks,carParamsSP,carStateSP,bookmarkButton"" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="true" WORKING_DIR="file://$ProjectFileDir$/tools/replay" PASS_PARENT_ENVS_2="true" PROJECT_NAME="openpilot-special" TARGET_NAME="replay" CONFIG_NAME="replay" version="1" RUN_PATH="replay">
|
||||
<method v="2">
|
||||
<option name="CLION.COMPOUND.BUILD" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
+1
-1
Submodule opendbc_repo updated: 55db8740ec...06743dfb39
@@ -353,7 +353,6 @@ struct OnroadEventSP @0xda96579883444c35 {
|
||||
speedLimitPending @22;
|
||||
e2eChime @23;
|
||||
laneChangeRoadEdge @24;
|
||||
bigModelReady @25;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,6 @@ SP_BRANCH_MIGRATIONS = {
|
||||
("tizi", "release3-staging"): "release-tizi-staging",
|
||||
("mici", "release3"): "release-mici",
|
||||
("mici", "release3-staging"): "release-mici-staging",
|
||||
("tici", "hkg-angle-steering-2025"): "hkg-angle-steering-2025-tici",
|
||||
("tici", "hkg-angle-steering-2025-prebuilt"): "hkg-angle-steering-2025-tici-prebuilt"
|
||||
}
|
||||
|
||||
BUILD_METADATA_FILENAME = "build.json"
|
||||
|
||||
@@ -198,7 +198,6 @@ class SelfdriveD(CruiseHelper):
|
||||
loading = self.params.get_bool("ChestnutLoading")
|
||||
if self.big_model_loading and not loading:
|
||||
self.big_model_ready_t = time.monotonic()
|
||||
self.events_sp.add(custom.OnroadEventSP.EventName.bigModelReady)
|
||||
self.big_model_loading = loading
|
||||
if self.big_model_loading:
|
||||
self.events.add(EventName.bigModelLoading)
|
||||
|
||||
@@ -20,6 +20,7 @@ from openpilot.system.ui.widgets.list_view import button_item
|
||||
|
||||
from openpilot.system.ui.sunnypilot.widgets.html_render import HtmlModalSP
|
||||
from openpilot.system.ui.sunnypilot.widgets.list_view import toggle_item_sp
|
||||
from openpilot.selfdrive.ui.sunnypilot.layouts.settings.external_storage import external_storage_item
|
||||
|
||||
PREBUILT_PATH = os.path.join(Paths.comma_home(), "prebuilt") if PC else "/data/openpilot/prebuilt"
|
||||
|
||||
@@ -52,7 +53,11 @@ class DeveloperLayoutSP(DeveloperLayout):
|
||||
|
||||
self.error_log_btn = button_item(tr("Error Log"), tr("VIEW"), tr("View the error log for sunnypilot crashes."), callback=self._on_error_log_clicked)
|
||||
|
||||
self.items: list = [self.show_advanced_controls, self.enable_github_runner_toggle, self.enable_copyparty_toggle, self.prebuilt_toggle, self.error_log_btn,]
|
||||
self.external_storage = external_storage_item(tr("External Storage"), description=tr("Extend your comma device's storage by inserting a USB drive " +
|
||||
"into the aux port."))
|
||||
|
||||
self.items: list = [self.show_advanced_controls, self.enable_github_runner_toggle, self.enable_copyparty_toggle, self.prebuilt_toggle,
|
||||
self.external_storage, self.error_log_btn,]
|
||||
|
||||
@staticmethod
|
||||
def _on_prebuilt_toggled(state):
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
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
|
||||
import threading
|
||||
import subprocess
|
||||
import copy
|
||||
from enum import Enum
|
||||
from collections.abc import Callable
|
||||
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.hardware import PC
|
||||
from openpilot.system.ui.lib.application import gui_app, FontWeight
|
||||
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
||||
from openpilot.system.ui.lib.multilang import tr, tr_noop
|
||||
from openpilot.system.ui.widgets import DialogResult
|
||||
from openpilot.system.ui.widgets.button import Button, ButtonStyle
|
||||
from openpilot.system.ui.widgets.confirm_dialog import alert_dialog, ConfirmDialog
|
||||
from openpilot.system.ui.widgets.list_view import (
|
||||
ItemAction,
|
||||
ListItem,
|
||||
BUTTON_HEIGHT,
|
||||
BUTTON_BORDER_RADIUS,
|
||||
BUTTON_FONT_SIZE,
|
||||
BUTTON_WIDTH,
|
||||
)
|
||||
|
||||
VALUE_FONT_SIZE = 48
|
||||
|
||||
|
||||
class ExternalStorageState(Enum):
|
||||
DISABLED = tr_noop("DISABLED")
|
||||
LOADING = tr_noop("LOADING")
|
||||
CHECK = tr_noop("CHECK")
|
||||
MOUNT = tr_noop("MOUNT")
|
||||
UNMOUNT = tr_noop("UNMOUNT")
|
||||
FORMAT = tr_noop("FORMAT")
|
||||
|
||||
|
||||
class ExternalStorageAction(ItemAction):
|
||||
MAX_WIDTH = 500
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(self.MAX_WIDTH, True)
|
||||
|
||||
self._params = Params()
|
||||
self._error_message = ""
|
||||
self._text_font = gui_app.font(FontWeight.NORMAL)
|
||||
|
||||
self._button = Button(
|
||||
"",
|
||||
click_callback=self._handle_button_click,
|
||||
button_style=ButtonStyle.LIST_ACTION,
|
||||
border_radius=BUTTON_BORDER_RADIUS,
|
||||
font_size=BUTTON_FONT_SIZE,
|
||||
)
|
||||
|
||||
self._value_text = ""
|
||||
self._formatting = False
|
||||
self._refresh_pending = False
|
||||
|
||||
self._state = ExternalStorageState.CHECK
|
||||
self._refresh_state()
|
||||
self.refresh()
|
||||
|
||||
def set_touch_valid_callback(self, callback):
|
||||
def wrapped():
|
||||
if self._state == ExternalStorageState.DISABLED:
|
||||
return False
|
||||
return callback()
|
||||
super().set_touch_valid_callback(wrapped)
|
||||
self._button.set_touch_valid_callback(wrapped)
|
||||
|
||||
def _run(self, cmd: str) -> bool:
|
||||
return subprocess.call(["sh", "-c", cmd]) == 0
|
||||
|
||||
def _run_output(self, cmd: str) -> str:
|
||||
try:
|
||||
out = subprocess.check_output(["sh", "-c", cmd], universal_newlines=True)
|
||||
return out.strip()
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
def _render(self, rect: rl.Rectangle) -> bool:
|
||||
if self._error_message:
|
||||
msg = copy.copy(self._error_message)
|
||||
gui_app.set_modal_overlay(alert_dialog(msg))
|
||||
self._error_message = ""
|
||||
|
||||
if self._value_text:
|
||||
text_size = measure_text_cached(self._text_font, self._value_text, VALUE_FONT_SIZE)
|
||||
rl.draw_text_ex(
|
||||
self._text_font,
|
||||
self._value_text,
|
||||
(rect.x + rect.width - BUTTON_WIDTH - text_size.x - 30,
|
||||
rect.y + (rect.height - text_size.y) / 2),
|
||||
VALUE_FONT_SIZE,
|
||||
1.0,
|
||||
rl.Color(170, 170, 170, 255),
|
||||
)
|
||||
|
||||
button_rect = rl.Rectangle(
|
||||
rect.x + rect.width - BUTTON_WIDTH,
|
||||
rect.y + (rect.height - BUTTON_HEIGHT) / 2,
|
||||
BUTTON_WIDTH,
|
||||
BUTTON_HEIGHT
|
||||
)
|
||||
self._button.set_rect(button_rect)
|
||||
self._button.set_text(tr(self._state.value))
|
||||
self._button.set_enabled(self._state not in (ExternalStorageState.LOADING,
|
||||
ExternalStorageState.DISABLED))
|
||||
self._button.render(button_rect)
|
||||
return False
|
||||
|
||||
def _refresh_state(self):
|
||||
if PC:
|
||||
self._state = ExternalStorageState.DISABLED
|
||||
self._button.set_enabled(False)
|
||||
self._value_text = ""
|
||||
|
||||
def debounced_refresh(self):
|
||||
if self._refresh_pending:
|
||||
return
|
||||
self._refresh_pending = True
|
||||
|
||||
def _timer():
|
||||
import time
|
||||
time.sleep(0.25)
|
||||
self._refresh_pending = False
|
||||
self.refresh()
|
||||
|
||||
threading.Thread(target=_timer, daemon=True).start()
|
||||
|
||||
def refresh(self):
|
||||
def _work():
|
||||
is_mounted = self._run("findmnt -n /mnt/external_realdata")
|
||||
has_drive = self._run("lsblk -f /dev/sdg")
|
||||
has_fs = self._run("lsblk -f /dev/sdg1 | grep -q ext4")
|
||||
has_label = self._run("blkid /dev/sdg1 | grep -q 'LABEL=\"openpilot\"'")
|
||||
|
||||
info = ""
|
||||
if is_mounted and has_label:
|
||||
info = self._run_output(
|
||||
"df -h /mnt/external_realdata | awk 'NR==2 {print $3 \"/\" $2}'"
|
||||
)
|
||||
|
||||
def apply():
|
||||
if self._formatting:
|
||||
self._value_text = tr("formatting")
|
||||
self._state = ExternalStorageState.FORMAT
|
||||
return
|
||||
|
||||
if not has_drive:
|
||||
self._value_text = tr("insert drive")
|
||||
self._state = ExternalStorageState.CHECK
|
||||
|
||||
elif not has_fs or not has_label:
|
||||
self._value_text = tr("needs format")
|
||||
self._state = ExternalStorageState.FORMAT
|
||||
|
||||
elif is_mounted:
|
||||
self._value_text = info
|
||||
self._state = ExternalStorageState.UNMOUNT
|
||||
|
||||
else:
|
||||
self._value_text = tr("drive detected")
|
||||
self._state = ExternalStorageState.MOUNT
|
||||
|
||||
apply()
|
||||
|
||||
threading.Thread(target=_work, daemon=True).start()
|
||||
|
||||
def _handle_button_click(self):
|
||||
st = self._state
|
||||
|
||||
if st == ExternalStorageState.DISABLED:
|
||||
return
|
||||
|
||||
if st in (ExternalStorageState.CHECK, ExternalStorageState.MOUNT):
|
||||
self.mount_storage()
|
||||
|
||||
elif st == ExternalStorageState.UNMOUNT:
|
||||
self.unmount_storage()
|
||||
|
||||
elif st == ExternalStorageState.FORMAT:
|
||||
dialog = ConfirmDialog(
|
||||
tr("Are you sure you want to format this drive? This will erase all data."),
|
||||
confirm_text=tr("Format"),
|
||||
cancel_text=tr("Cancel"),
|
||||
)
|
||||
gui_app.set_modal_overlay(dialog, callback=self._confirm_format)
|
||||
|
||||
def _confirm_format(self, result: DialogResult):
|
||||
if result == DialogResult.CONFIRM:
|
||||
self.format_storage()
|
||||
|
||||
def mount_storage(self):
|
||||
self._value_text = tr("mounting")
|
||||
self._state = ExternalStorageState.LOADING
|
||||
|
||||
def _work():
|
||||
cmd = """
|
||||
sudo mount -o remount,rw / &&
|
||||
sudo mkdir -p /mnt/external_realdata &&
|
||||
(grep -q '/dev/sdg1 /mnt/external_realdata' /etc/fstab ||
|
||||
echo '/dev/sdg1 /mnt/external_realdata ext4 defaults,nofail 0 2' >> /etc/fstab) &&
|
||||
sudo systemctl daemon-reexec &&
|
||||
sudo mount /mnt/external_realdata &&
|
||||
sudo chown -R comma:comma /mnt/external_realdata &&
|
||||
sudo chmod -R 775 /mnt/external_realdata &&
|
||||
sudo mount -o remount,ro /
|
||||
"""
|
||||
subprocess.call(["sh", "-c", cmd])
|
||||
self.debounced_refresh()
|
||||
|
||||
threading.Thread(target=_work, daemon=True).start()
|
||||
|
||||
def unmount_storage(self):
|
||||
self._value_text = tr("unmounting")
|
||||
self._state = ExternalStorageState.LOADING
|
||||
|
||||
def _work():
|
||||
subprocess.call(["sh", "-c", "sudo umount /mnt/external_realdata"])
|
||||
self.debounced_refresh()
|
||||
|
||||
threading.Thread(target=_work, daemon=True).start()
|
||||
|
||||
def format_storage(self):
|
||||
self._formatting = True
|
||||
self._value_text = tr("formatting")
|
||||
self._state = ExternalStorageState.LOADING
|
||||
|
||||
def _work():
|
||||
cmd = """
|
||||
sudo wipefs -a /dev/sdg &&
|
||||
sudo parted -s /dev/sdg mklabel gpt mkpart primary ext4 0% 100% &&
|
||||
sudo mkfs.ext4 -F -L openpilot /dev/sdg1
|
||||
"""
|
||||
exitcode = subprocess.call(["sh", "-c", cmd])
|
||||
|
||||
def apply():
|
||||
self._formatting = False
|
||||
if exitcode == 0:
|
||||
self.mount_storage()
|
||||
else:
|
||||
self._value_text = tr("needs format")
|
||||
self._state = ExternalStorageState.FORMAT
|
||||
|
||||
apply()
|
||||
|
||||
threading.Thread(target=_work, daemon=True).start()
|
||||
|
||||
def external_storage_item(title: str | Callable[[], str], description: str | Callable[[], str]) -> ListItem:
|
||||
return ListItem(
|
||||
title=title,
|
||||
description=description,
|
||||
action_item=ExternalStorageAction()
|
||||
)
|
||||
@@ -8,22 +8,22 @@ See the LICENSE.md file in the root directory for more details.
|
||||
|
||||
import os
|
||||
os.environ['GMMU'] = '0'
|
||||
import numpy as np
|
||||
import threading
|
||||
import time
|
||||
from setproctitle import setproctitle
|
||||
from tinygrad.tensor import Tensor
|
||||
|
||||
import openpilot.cereal.messaging as messaging
|
||||
from openpilot.common.hardware import COMMA_HARDWARE
|
||||
from openpilot.selfdrive.modeld.helpers import chestnut_present, load_oob
|
||||
import time
|
||||
import numpy as np
|
||||
import openpilot.cereal.messaging as messaging
|
||||
from openpilot.cereal import log
|
||||
from opendbc.car.structs import car
|
||||
from openpilot.cereal.services import SERVICE_LIST
|
||||
from setproctitle import setproctitle
|
||||
from openpilot.cereal.messaging import PubMaster, SubMaster
|
||||
from openpilot.cereal.visionipc import VisionStreamType
|
||||
from msgq.visionipc import VisionIpcClient, VisionBuf
|
||||
from opendbc.car.car_helpers import get_demo_car_params
|
||||
|
||||
from tinygrad.tensor import Tensor
|
||||
|
||||
from openpilot.common.file_chunker import open_file_chunked
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.common.params import Params
|
||||
@@ -42,13 +42,13 @@ from openpilot.sunnypilot.modeld_v2.constants import Plan
|
||||
from openpilot.sunnypilot.modeld_v2.meta_helper import load_meta_constants
|
||||
from openpilot.sunnypilot.modeld_v2.camera_offset_helper import CameraOffsetHelper
|
||||
from openpilot.sunnypilot.modeld_v2.compile_modeld import derive_frame_skip, make_split_input_queues, make_supercombo_input_queues, WARP_INPUTS, POLICY_INPUTS
|
||||
|
||||
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
|
||||
from openpilot.sunnypilot.modeld_v2.modeld_base import ModelStateBase
|
||||
from openpilot.sunnypilot.models.helpers import get_active_bundle
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.relc import RoadEdgeLaneChangeController
|
||||
|
||||
PROCESS_NAME = "openpilot.selfdrive.modeld.modeld_tinygrad"
|
||||
BIG_MODEL_TIMEOUT = 60
|
||||
|
||||
|
||||
def _pkl_exists(path):
|
||||
@@ -68,7 +68,6 @@ def _find_driving_pkl(bundle):
|
||||
pkl_path = os.path.join(model_root, pkl_name)
|
||||
if _pkl_exists(pkl_path):
|
||||
return pkl_path
|
||||
return None
|
||||
|
||||
|
||||
class FrameMeta:
|
||||
@@ -103,7 +102,7 @@ class ModelState(ModelStateBase):
|
||||
self.chestnut = chestnut
|
||||
|
||||
pkl_path = _find_driving_pkl(model_bundle)
|
||||
assert pkl_path is not None, f"No driving pkl found for {'chestnut' if chestnut else 'small model'} — all models must be compiled with compile_modeld.py"
|
||||
assert pkl_path is not None, "No driving pkl found — all models must be compiled with compile_modeld.py"
|
||||
self._init_combined(pkl_path, cam_w, cam_h, model_bundle)
|
||||
|
||||
def _init_combined(self, pkl_path, cam_w, cam_h, bundle):
|
||||
@@ -186,6 +185,9 @@ class ModelState(ModelStateBase):
|
||||
else:
|
||||
self.warp(**{k: self.input_queues[k] for k in WARP_INPUTS}, frame=frame_tensor, big_frame=big_frame_tensor)
|
||||
|
||||
if self.chestnut:
|
||||
self.warmup()
|
||||
|
||||
def warmup(self) -> None:
|
||||
dummy_frames = {k: np.zeros(self.frame_buf_params[k][3], dtype=np.uint8) for k in self._vision_input_names}
|
||||
transforms = {k: np.eye(3, dtype=np.float32) for k in [self._road_key, self._wide_key] if k}
|
||||
@@ -286,7 +288,8 @@ class ModelState(ModelStateBase):
|
||||
buf[0, -1, :] = outputs['desired_curvature'][0, :] if not self.mlsim else 0
|
||||
|
||||
if self.chestnut and not np.all(np.isfinite(outputs.get('plan', np.array([0.])))):
|
||||
raise RuntimeError("model output not finite")
|
||||
cloudlog.error("model output not finite, dropping frame")
|
||||
return None
|
||||
|
||||
return outputs
|
||||
|
||||
@@ -360,26 +363,21 @@ def main(demo=False):
|
||||
|
||||
model = None
|
||||
if CHESTNUT:
|
||||
big_model = None
|
||||
def load_big():
|
||||
nonlocal big_model
|
||||
try:
|
||||
m = ModelState(cam_w=vipc_client_main.width, cam_h=vipc_client_main.height, chestnut=True)
|
||||
m.warmup()
|
||||
big_model = m
|
||||
except Exception:
|
||||
cloudlog.exception("chestnut load failed")
|
||||
loader = threading.Thread(target=load_big, daemon=True)
|
||||
loader.start()
|
||||
loader.join(BIG_MODEL_TIMEOUT)
|
||||
model = big_model
|
||||
params.put_bool("ChestnutActive", model is not None)
|
||||
import threading
|
||||
def load():
|
||||
nonlocal model
|
||||
model = ModelState(cam_w=vipc_client_main.width, cam_h=vipc_client_main.height, chestnut=True)
|
||||
t = threading.Thread(target=load, daemon=True)
|
||||
t.start()
|
||||
t.join(60)
|
||||
if model is None:
|
||||
params.put_bool("ChestnutActive", False)
|
||||
raise RuntimeError("chestnut model load failed or timed out (60s)")
|
||||
params.put_bool("ChestnutActive", True)
|
||||
else:
|
||||
model = ModelState(cam_w=vipc_client_main.width, cam_h=vipc_client_main.height, chestnut=False)
|
||||
|
||||
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:
|
||||
model = small_model
|
||||
params.put_bool("ChestnutLoading", False)
|
||||
assert model is not None
|
||||
cloudlog.warning(f"models loaded in {time.monotonic() - st:.1f}s, modeld starting")
|
||||
|
||||
# messaging
|
||||
@@ -388,7 +386,7 @@ def main(demo=False):
|
||||
sm = SubMaster(["deviceState", "carState", "narrowRoadCameraState", "extrinsicsCalibration", "driverMonitoringState", "carControl", "lateralDelay"])
|
||||
|
||||
publish_state = PublishState()
|
||||
chestnut_state = ChestnutState(pm, model.chestnut) if CHESTNUT else None
|
||||
chestnut_state = ChestnutState(pm, CHESTNUT) if CHESTNUT else None
|
||||
|
||||
# setup filter to track dropped frames
|
||||
frame_dropped_filter = FirstOrderFilter(0., 10., 1. / model.constants.MODEL_FREQ)
|
||||
@@ -511,19 +509,7 @@ def main(demo=False):
|
||||
inputs['action_t'] = np.array([lat_action_t, long_action_t], dtype=np.float32)
|
||||
|
||||
mt1 = time.perf_counter()
|
||||
try:
|
||||
model_output = model.run(bufs, transforms, inputs, prepare_only)
|
||||
except Exception:
|
||||
if not params.get_bool("ChestnutActive"):
|
||||
raise
|
||||
cloudlog.exception("chestnut failed, falling back to small")
|
||||
params.put_bool("ChestnutActive", False)
|
||||
assert small_model is not None
|
||||
model = small_model
|
||||
if chestnut_state is not None:
|
||||
chestnut_state.big = False
|
||||
run_count = 0
|
||||
model_output = None
|
||||
model_output = model.run(bufs, transforms, inputs, prepare_only)
|
||||
mt2 = time.perf_counter()
|
||||
model_execution_time = mt2 - mt1
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
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 io
|
||||
import requests
|
||||
|
||||
from openpilot.common.file_chunker import get_chunk_name
|
||||
from openpilot.common.hardware import hw
|
||||
from openpilot.common.test import OpenpilotTestCase
|
||||
from openpilot.selfdrive.modeld.helpers import dump_oob
|
||||
import openpilot.sunnypilot.modeld_v2.modeld as modeld_module
|
||||
from openpilot.sunnypilot.modeld_v2.tests import helpers as tests_helpers
|
||||
from openpilot.sunnypilot.modeld_v2.tests.helpers import DummyModel, DummyBundle, CAM_W, CAM_H
|
||||
from openpilot.sunnypilot.models.fetcher import ModelParser, ModelFetcher
|
||||
|
||||
tmp_path = tests_helpers.tmp_path
|
||||
|
||||
|
||||
class TestFallback(OpenpilotTestCase):
|
||||
def test_find_dual_model_in_bundle(self, tmp_path, monkeypatch):
|
||||
lebowski_file = 'driving_lebowski.pkl'
|
||||
tsfdo_file = 'driving_tsfdo.pkl'
|
||||
(tmp_path / lebowski_file).write_bytes(b'fkasdjfkljf')
|
||||
(tmp_path / tsfdo_file).write_bytes(b'dskfajklsdjlsfka')
|
||||
|
||||
monkeypatch.setattr(hw.Paths, 'model_root', staticmethod(lambda: str(tmp_path)))
|
||||
big_bundle = DummyBundle(models=[DummyModel('supercombo', lebowski_file)])
|
||||
small_bundle = DummyBundle(models=[DummyModel('supercombo', tsfdo_file)])
|
||||
big_pkl = modeld_module._find_driving_pkl(big_bundle)
|
||||
small_pkl = modeld_module._find_driving_pkl(small_bundle)
|
||||
|
||||
assert big_pkl is not None and lebowski_file in big_pkl
|
||||
assert small_pkl is not None and tsfdo_file in small_pkl
|
||||
|
||||
def test_download_models_and_init_modelstate_fallback(self, tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(hw.Paths, 'model_root', staticmethod(lambda: str(tmp_path)))
|
||||
big_json = requests.get(ModelFetcher.MODEL_URL_CHESTNUT).json()
|
||||
big_bundle = ModelParser.parse_models(big_json)[-1]
|
||||
small_json = requests.get(ModelFetcher.MODEL_URL).json()
|
||||
small_bundle = ModelParser.parse_models(small_json)[-1]
|
||||
|
||||
buf = io.BytesIO()
|
||||
dump_oob(tests_helpers.make_pkl_data(tests_helpers.ARCHETYPES['supercombo_non20hz']), buf)
|
||||
oob_bytes = buf.getvalue()
|
||||
|
||||
for bundle in (big_bundle, small_bundle):
|
||||
artifact = bundle.models[0].artifact
|
||||
for i in range(len(artifact.chunks)):
|
||||
(tmp_path / get_chunk_name(artifact.fileName, i, len(artifact.chunks))).write_bytes(oob_bytes if i == 0 else b"")
|
||||
|
||||
monkeypatch.setattr(modeld_module, 'get_active_bundle', lambda params=None, *, chestnut=None: small_bundle)
|
||||
assert modeld_module.ModelState(CAM_W, CAM_H, chestnut=False).chestnut is False
|
||||
|
||||
monkeypatch.setattr(modeld_module, 'get_active_bundle', lambda params=None, *, chestnut=None: big_bundle)
|
||||
try:
|
||||
assert modeld_module.ModelState(CAM_W, CAM_H, chestnut=True).chestnut is True
|
||||
except Exception as e:
|
||||
assert "AMD" in str(e) or "device" in str(e).lower()
|
||||
@@ -1,14 +1,11 @@
|
||||
import argparse
|
||||
import os
|
||||
import hashlib
|
||||
import requests
|
||||
import re
|
||||
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
from openpilot.sunnypilot import get_file_hash
|
||||
from openpilot.sunnypilot.models.model_name import DEFAULT_MODEL, DEFAULT_BIG_MODEL
|
||||
from openpilot.sunnypilot.models.fetcher import ModelFetcher
|
||||
|
||||
|
||||
def get_default_model() -> str:
|
||||
@@ -33,29 +30,14 @@ def update_model_hash():
|
||||
print(f"Generated and updated new combined model hash to {MODEL_HASH_PATH}")
|
||||
|
||||
|
||||
def get_ref_for_name(url: str, name: str) -> str:
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
bundles = response.json()["bundles"]
|
||||
matching = [b for b in bundles if re.search(name, f"{b['short_name']} {b['display_name']}", re.IGNORECASE)]
|
||||
if matching:
|
||||
return max(matching, key=lambda b: int(b["index"]))["ref"]
|
||||
return ""
|
||||
|
||||
|
||||
def update_default_model_names(default_model_name: str, default_big_model_name: str):
|
||||
print("[CHANGE DEFAULT MODEL NAMES]")
|
||||
small_ref = get_ref_for_name(ModelFetcher.MODEL_URL, default_model_name)
|
||||
big_ref = get_ref_for_name(ModelFetcher.MODEL_URL_CHESTNUT, default_big_model_name)
|
||||
|
||||
with open(DEFAULT_MODEL_NAME_PATH, "w") as f:
|
||||
f.write(f'DEFAULT_MODEL = "{default_model_name}"\n')
|
||||
f.write(f'DEFAULT_MODEL_REF = "{small_ref}"\n')
|
||||
f.write(f'DEFAULT_BIG_MODEL = "{default_big_model_name}"\n')
|
||||
f.write(f'DEFAULT_BIG_MODEL_REF = "{big_ref}"\n')
|
||||
|
||||
print(f'New default small model name: "{default_model_name}" (ref: {small_ref})')
|
||||
print(f'New default big model name: "{default_big_model_name}" (ref: {big_ref})')
|
||||
print(f'New default small model name: "{default_model_name}"')
|
||||
print(f'New default big model name: "{default_big_model_name}"')
|
||||
print("[DONE]")
|
||||
|
||||
|
||||
|
||||
@@ -328,12 +328,6 @@ class ModelManagerSP:
|
||||
validate_active_bundles(self.params, self.source_models)
|
||||
self.active_bundle = get_active_bundle(self.params, chestnut=self.chestnut_present)
|
||||
|
||||
if get_selected_bundle(self.params, "chestnut") is not None and get_selected_bundle(self.params, "qcom") is None:
|
||||
if self.params.get("ModelManager_DownloadRef") is None:
|
||||
from openpilot.sunnypilot.models.model_name import DEFAULT_MODEL_REF
|
||||
if DEFAULT_MODEL_REF:
|
||||
self.params.put("ModelManager_DownloadRef", DEFAULT_MODEL_REF)
|
||||
|
||||
self._process_download_requests()
|
||||
|
||||
if self.params.get("ModelManager_ClearCache"):
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
DEFAULT_MODEL = "CD210"
|
||||
DEFAULT_MODEL_REF = "5b6436a90cf6902b8aaa71c2b6f3d7164d8ae391"
|
||||
DEFAULT_BIG_MODEL = "Lebowski"
|
||||
DEFAULT_BIG_MODEL_REF = "fa0c6876d3cf070e91e25e5353ceadc68a5b3285"
|
||||
|
||||
@@ -252,12 +252,4 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
AlertStatus.userPrompt, AlertSize.small,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 0.1),
|
||||
},
|
||||
|
||||
EventNameSP.bigModelReady: {
|
||||
ET.PERMANENT: Alert(
|
||||
"Big Model Ready",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.small,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 2.),
|
||||
},
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user