IQ.Pilot Release Commit @ 6d177d4

This commit is contained in:
IQ.Lvbs CI [bot]
2026-07-22 23:21:13 -05:00
parent ff4dfcb728
commit 401cac1028
93 changed files with 9223 additions and 4600 deletions

View File

@@ -1,11 +1,6 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
# DISCLAIMER: This code is intended principally for development and debugging purposes.
# Although it provides a standalone entry point to the program, users should refer
# to the actual implementations for consumption. Usage outside of development scenarios
# is not advised and could lead to unpredictable results.
import threading
import traceback
@@ -13,26 +8,27 @@ from openpilot.common.realtime import Ratekeeper, config_realtime_process
from openpilot.iqpilot.iq_maps.road_data import debug_road_data
from openpilot.iqpilot.iq_maps.road_data.iq_road_layer import IQRoadLayer
ROAD_LAYER_HZ = 1
ROAD_LAYER_CORES = [0, 1, 2, 3]
def excepthook(args):
debug_road_data(f'IQ maps threading exception:\n{args}')
def _log_thread_exception(args) -> None:
debug_road_data(f"IQ maps threading exception:\n{args}")
traceback.print_exception(args.exc_type, args.exc_value, args.exc_traceback)
def live_map_data_iq_thread():
config_realtime_process([0, 1, 2, 3], 5)
live_map_iq = IQRoadLayer()
rk = Ratekeeper(1, print_delay_threshold=None)
def run() -> None:
config_realtime_process(ROAD_LAYER_CORES, 5)
layer = IQRoadLayer()
rk = Ratekeeper(ROAD_LAYER_HZ, print_delay_threshold=None)
while True:
live_map_iq.step()
layer.step()
rk.keep_time()
def main():
threading.excepthook = excepthook
live_map_data_iq_thread()
def main() -> None:
threading.excepthook = _log_thread_exception
run()
if __name__ == "__main__":

View File

@@ -1,21 +1,25 @@
#!/usr/bin/env python3
import hashlib
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Installs the `mapd` binary by Jacob Pfeifer (github.com/pfeiferj/mapd) — the binary is his work.
"""
import hashlib
import logging
import os
import stat
import time
import traceback
import requests
from pathlib import Path
from urllib.request import urlopen
import requests
from cereal import messaging
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.system.hardware.hw import Paths
from openpilot.common.spinner import Spinner
from openpilot.system.hardware.hw import Paths
from openpilot.system.version import is_prebuilt
from openpilot.iqpilot.iq_maps import VENDOR_MAPD_BIN_DIR, VENDOR_MAPD_PATH
import openpilot.system.sentry as sentry
@@ -23,17 +27,28 @@ import openpilot.system.sentry as sentry
VENDOR_RELEASE_TAG = "v2.0.6"
VENDOR_RELEASE_URL = f"https://github.com/pfeiferj/mapd/releases/download/{VENDOR_RELEASE_TAG}/mapd"
_VERSION_PARAM = "MapdVersion"
_HASH_FILE = os.path.join(BASEDIR, "iqpilot", "iq_maps", "tests", "mapd_hash")
_DOWNLOAD_TIMEOUT_S = 60
_MAX_DOWNLOAD_TRIES = 5
def get_file_hash(path: str) -> str:
"""Hex SHA-256 of a file's contents."""
with open(path, "rb") as handle:
return hashlib.file_digest(handle, "sha256").hexdigest()
def stamp_vendor_version(version: str, params: Params | None = None) -> None:
if params is None:
params = Params()
params.put("MapdVersion", version)
(params or Params()).put(_VERSION_PARAM, version)
def _expected_vendor_hash_path() -> str:
from openpilot.common.basedir import BASEDIR
return os.path.join(BASEDIR, "iqpilot", "iq_maps", "tests", "mapd_hash")
def _pinned_hash() -> str:
try:
with open(_HASH_FILE) as f:
return f.read().strip()
except OSError:
return ""
class VendorMapdInstaller:
@@ -41,98 +56,74 @@ class VendorMapdInstaller:
self._spinner = spinner_ref
self._params = Params()
def fetch(self) -> None:
self.ensure_directories_exist()
self._download_file()
stamp_vendor_version(VENDOR_RELEASE_TAG, self._params)
def get_installed_version(self) -> str:
return str(self._params.get(_VERSION_PARAM) or "")
def check_and_download(self) -> None:
if self.download_needed():
self.fetch()
@staticmethod
def ensure_directories_exist() -> None:
for d in (Paths.mapd_root(), VENDOR_MAPD_BIN_DIR):
os.makedirs(d, exist_ok=True)
def download_needed(self) -> bool:
if not os.path.exists(VENDOR_MAPD_PATH):
return True
if self.get_installed_version() != VENDOR_RELEASE_TAG:
return True
return not self._binary_hash_matches()
@staticmethod
def _binary_hash_matches() -> bool:
pinned = _pinned_hash()
if not pinned:
return False
try:
hash_path = _expected_vendor_hash_path()
with open(hash_path) as f:
expected = f.read().strip()
except Exception:
return True
if not expected:
return True
try:
return get_file_hash(VENDOR_MAPD_PATH) == expected
except Exception:
return get_file_hash(VENDOR_MAPD_PATH) != pinned
except OSError:
return True
@staticmethod
def ensure_directories_exist() -> None:
if not os.path.exists(Paths.mapd_root()):
os.makedirs(Paths.mapd_root())
if not os.path.exists(VENDOR_MAPD_BIN_DIR):
os.makedirs(VENDOR_MAPD_BIN_DIR)
def check_and_download(self) -> None:
if self.download_needed():
self.fetch()
@staticmethod
def _safe_write_and_set_executable(file_path: Path, content: bytes) -> None:
with open(file_path, 'wb') as output:
output.write(content)
output.flush()
os.fsync(output.fileno())
current_permissions = stat.S_IMODE(os.lstat(file_path).st_mode)
os.chmod(file_path, current_permissions | stat.S_IEXEC)
def fetch(self) -> None:
self.ensure_directories_exist()
if self._pull_binary():
stamp_vendor_version(VENDOR_RELEASE_TAG, self._params)
def _download_file(self, num_retries=5) -> None:
temp_file = Path(VENDOR_MAPD_PATH + ".tmp")
download_timeout = 60
for cnt in range(num_retries):
def _pull_binary(self) -> bool:
scratch = Path(f"{VENDOR_MAPD_PATH}.tmp")
for attempt in range(1, _MAX_DOWNLOAD_TRIES + 1):
try:
response = requests.get(VENDOR_RELEASE_URL, stream=True, timeout=download_timeout)
response.raise_for_status()
self._safe_write_and_set_executable(temp_file, response.content)
temp_file.replace(VENDOR_MAPD_PATH)
return
except requests.exceptions.ReadTimeout:
self._spinner.update(f"ReadTimeout caught. Timeout is [{download_timeout}]. Retrying download... [{cnt}]")
time.sleep(0.5)
resp = requests.get(VENDOR_RELEASE_URL, stream=True, timeout=_DOWNLOAD_TIMEOUT_S)
resp.raise_for_status()
with open(scratch, "wb") as out:
out.write(resp.content)
out.flush()
os.fsync(out.fileno())
mode = stat.S_IMODE(os.lstat(scratch).st_mode)
os.chmod(scratch, mode | stat.S_IEXEC)
scratch.replace(VENDOR_MAPD_PATH)
return True
except requests.exceptions.RequestException as e:
self._spinner.update(f"RequestException caught: {e}. Retrying download... [{cnt}]")
self._spinner.update(f"mapd download failed ({e}); retry {attempt}/{_MAX_DOWNLOAD_TRIES}")
time.sleep(0.5)
# Delete temp file if the process was not successful.
if temp_file.exists():
temp_file.unlink()
logging.error("Failed to download file after all retries")
def get_installed_version(self) -> str:
return str(self._params.get("MapdVersion") or "")
scratch.unlink(missing_ok=True)
logging.error("mapd binary download failed after %d attempts", _MAX_DOWNLOAD_TRIES)
return False
def wait_for_internet_connection(self, return_on_failure: bool = False) -> bool:
max_retries = 10
for retries in range(max_retries + 1):
self._spinner.update(f"Waiting for internet connection... [{retries}/{max_retries}]")
attempts = 10
for i in range(attempts + 1):
self._spinner.update(f"Waiting for internet connection... [{i}/{attempts}]")
time.sleep(2)
try:
_ = urlopen('https://sentry.io', timeout=10)
urlopen("https://sentry.io", timeout=10)
return True
except Exception as e:
print(f'Wait for internet failed: {e}')
if return_on_failure and retries == max_retries:
except Exception as e: # noqa: BLE001
print(f"Wait for internet failed: {e}")
if return_on_failure and i == attempts:
return False
return False
def non_prebuilt_install(self) -> None:
sm = messaging.SubMaster(['deviceState'])
metered = sm['deviceState'].networkMetered
if metered:
sm = messaging.SubMaster(["deviceState"])
if sm["deviceState"].networkMetered:
self._spinner.update("Can't proceed with mapd install since network is metered!")
time.sleep(5)
return
@@ -149,14 +140,11 @@ class VendorMapdInstaller:
time.sleep(0.1)
self.check_and_download()
self._spinner.close()
except Exception:
except Exception: # noqa: BLE001
for i in range(6):
self._spinner.update("Failed to download OSM maps won't work until properly downloaded!" +
"Try again manually rebooting. " +
f"Boot will continue in {5 - i}s...")
self._spinner.update("Failed to download OSM maps won't work until properly downloaded!"
f"Try again manually rebooting. Boot will continue in {5 - i}s...")
time.sleep(1)
sentry.init(sentry.SentryProject.SELFDRIVE)
traceback.print_exc()
sentry.capture_exception()
@@ -164,18 +152,12 @@ class VendorMapdInstaller:
if __name__ == "__main__":
spinner = Spinner()
install_manager = VendorMapdInstaller(spinner)
install_manager.ensure_directories_exist()
installer = VendorMapdInstaller(spinner)
installer.ensure_directories_exist()
if is_prebuilt():
debug_msg = f"[DEBUG] This is prebuilt, no vendor mapd install required. VERSION: [{VENDOR_RELEASE_TAG}], Param [{install_manager.get_installed_version()}]"
spinner.update(debug_msg)
spinner.update(f"[DEBUG] Prebuilt build; no vendor mapd install required. "
f"VERSION: [{VENDOR_RELEASE_TAG}], Param [{installer.get_installed_version()}]")
stamp_vendor_version(VENDOR_RELEASE_TAG)
else:
spinner.update(f"Checking if vendor mapd is installed and valid. Prebuilt [{is_prebuilt()}]")
install_manager.non_prebuilt_install()
def get_file_hash(path: str) -> str:
"""Hex SHA-256 of a file's contents."""
with open(path, "rb") as handle:
return hashlib.file_digest(handle, "sha256").hexdigest()
installer.non_prebuilt_install()

View File

@@ -1,3 +1,4 @@
# openpilot model I/O constants (comma.ai, MIT — see LICENSE)
import numpy as np
@@ -14,7 +15,7 @@ class SplitModelConstants:
LEAD_T_OFFSETS = [0., 2., 4.]
META_T_IDXS = [2., 4., 6., 8., 10.]
# model inputs constants
# split-model temporal / history run parameters
MODEL_FREQ = 20
HISTORY_FREQ = 5
HISTORY_LEN_SECONDS = 5