Compare commits

..

71 Commits

Author SHA1 Message Date
firestar5683 432d575c41 Fix Capn Proto image version detection 2026-08-14 20:55:03 -05:00
firestar5683 8a2f96967a Update GitHub Actions for Node 24 2026-08-14 19:44:19 -05:00
whoisdomi d194762f28 afar stop 2026-08-01 00:28:39 -05:00
firestarsdog 0518b67573 Offroad/onroad guarding 2026-07-31 20:55:53 -05:00
whoisdomi e4ffae42c4 thing 2026-07-31 19:12:40 -05:00
firestarsdog 05594fc947 optimize radar point test 2026-07-31 19:04:26 -05:00
whoisdomi 947c6af636 stop 7 2026-07-31 15:52:09 -05:00
StarPilot Build Bot 159c78147f build 2026-07-30 18:53:57 +00:00
whoisdomi f6d38dbd69 stop 2026-07-30 13:20:00 -05:00
whoisdomi 4cac2f6231 STOP...in the name of stops 2026-07-30 07:37:39 -05:00
firestarsdog 011cf35abd what it do? 2026-07-29 14:45:50 -05:00
StarPilot Build Bot 5e02379759 build 2026-07-29 19:12:46 +00:00
whoisdomi c309cf177c Force Stop: Tweak3 Jerk Scale 2026-07-29 13:33:03 -05:00
whoisdomi 0ab17de780 Force Stop tweak2: a_far 2026-07-29 07:43:10 -05:00
whoisdomi e993cf0bed Stop edge cases: hysteresis 2026-07-29 05:28:55 -05:00
whoisdomi d9ace21a9b Force Stop tweak: red lights 2026-07-29 05:25:12 -05:00
whoisdomi ca6a6f79b7 smoothing hwy 2026-07-29 05:15:19 -05:00
whoisdomi 17b8aca4f5 Close Gap on Lane Changes 2026-07-29 05:15:17 -05:00
whoisdomi 4f24c3e20e Model Manager & Compiler Update
Model Manager allows for local driving models.

Compiler process for adding local driving models faster
2026-07-29 05:15:16 -05:00
firestarsdog 6277ecee4e Road name update 2026-07-29 01:52:23 -04:00
firestarsdog 0078eb477c SLC Sources Bubble Size + DASH -> Dash 2026-07-29 00:18:36 -04:00
firestarsdog c8a1fb3895 Bigger Radar Points 2026-07-29 00:03:07 -04:00
firestarsdog f65be7b584 Faster Bats 2026-07-28 23:24:24 -04:00
firestarsdog 7fbab917fa Performance Enhancing Rugs 2026-07-28 23:24:24 -04:00
firestarsdog a4a1d98f14 Revert "Big UI: Not your Papaw's Cached Params"
This reverts commit 640187f350.
2026-07-27 23:17:38 -04:00
firestarsdog 122672cd45 Revert "Papaw visits MICI... for science"
This reverts commit eaa5a9ad83.
2026-07-27 23:17:35 -04:00
firestarsdog fb1bfd16eb Revert "Big UI: More optimization"
This reverts commit 515f28fcbd.
2026-07-27 23:17:27 -04:00
firestarsdog 2eb88f4b6e Revert "Param Wrapper"
This reverts commit 34ca49517f.
2026-07-27 23:17:08 -04:00
firestarsdog 5b06fb4968 Revert "Comments... because Ill never remember this"
This reverts commit 07adabd70d.
2026-07-27 23:17:04 -04:00
firestarsdog f8c251001f Revert "Scribble is less scribbley"
This reverts commit a0dc562f9a.
2026-07-27 23:17:01 -04:00
firestarsdog 28d03e95d3 Revert "Faster Bats"
This reverts commit e8f526f6b8.
2026-07-27 23:16:58 -04:00
firestarsdog 762ced4157 Revert "Faster faster bats"
This reverts commit b9a83f5873.
2026-07-27 23:16:52 -04:00
firestarsdog b9a83f5873 Faster faster bats 2026-07-27 20:07:38 -04:00
firestarsdog e8f526f6b8 Faster Bats 2026-07-27 19:45:00 -04:00
firestarsdog a0dc562f9a Scribble is less scribbley 2026-07-27 18:59:33 -04:00
firestarsdog 07adabd70d Comments... because Ill never remember this 2026-07-27 17:23:25 -04:00
firestarsdog 34ca49517f Param Wrapper 2026-07-27 16:03:27 -04:00
whoisdomi 749235cda2 SLC override with -/+ bug 2026-07-27 13:55:32 -05:00
firestarsdog 515f28fcbd Big UI: More optimization 2026-07-27 13:58:08 -04:00
firestarsdog eaa5a9ad83 Papaw visits MICI... for science 2026-07-27 13:04:11 -04:00
firestarsdog 640187f350 Big UI: Not your Papaw's Cached Params 2026-07-27 12:46:49 -04:00
firestarsdog 3932dd9fe2 Big UI : Conditional Drive Update 2026-07-25 18:18:06 -04:00
firestarsdog f0e3414d1f Big UI: Conditional Drive oopsie 2026-07-25 18:03:59 -04:00
Dom ba9f216931 Merge pull request #77 from prabhaavp/vasm-bug-fix-2
Fix V-ASM snapshot capture without stored footage
2026-07-24 23:58:32 -05:00
Prabhaav Pillai 4e711173e0 Enhance VASM annotations: clarify button labels and add retry snapshot functionality 2026-07-25 00:48:32 -04:00
firestarsdog 8f945fb6fe Big UI: Remove transition 2026-07-24 16:42:00 -04:00
firestar5683 ec6bf08a65 build 2026-07-24 15:05:17 -05:00
firestar5683 0351e7d817 No Tweak 2026-07-24 15:02:07 -05:00
firestar5683 7eae0e9670 BUMP 2026-07-24 14:37:33 -05:00
firestar5683 8ef7e55e74 tune 2026-07-24 14:17:48 -05:00
firestar5683 0d2f0b6825 tune 2026-07-24 13:15:10 -05:00
firestar5683 6370abd73a G90 2026-07-24 12:46:29 -05:00
firestar5683 8640f06054 fix socket 2026-07-24 01:03:13 -05:00
firestar5683 779b42d8ea 11.8 2026-07-24 00:24:13 -05:00
firestar5683 f5f846f5b6 Pause vision inference while parked
Co-Authored-By: Prabhaav Pillai <143428353+prabhaavp@users.noreply.github.com>
2026-07-24 00:08:26 -05:00
firestar5683 d8b6e43a0d Fix vision CPU throttling with offline cores 2026-07-23 15:20:05 -05:00
firestar5683 b72042042f Sip-smiling away 2026-07-23 14:37:54 -05:00
firestar5683 bd6dced538 Update device_settings_layout.json 2026-07-23 14:13:44 -05:00
firestar5683 66245a5a2e flm update 2026-07-23 10:58:17 -05:00
firestar5683 d4a3bc0f5c offroad alert key 2026-07-23 09:15:19 -05:00
firestarsdog fcc5cc359e Big UI : Aethergauge cleanup 2026-07-23 01:20:47 -04:00
firestar5683 aa381d4d97 BUMP 2026-07-23 00:12:31 -05:00
firestar5683 bc3f215764 build 2026-07-23 00:11:05 -05:00
firestar5683 daf0f84bc9 What If You Lived On The Bottom Of A Rubber Duck? 2026-07-23 00:10:19 -05:00
firestar5683 b945d4c021 Add vision adjacent spot monitoring
Integrate V-ASM from PR #75 with Galaxy-only configuration, stale-state safety, conditional SLV coexistence, and OpenCV inference.

Originally contributed by @prabhaavp in #75.

Co-authored-by: Prabhaav Pillai <143428353+prabhaavp@users.noreply.github.com>
2026-07-23 00:05:43 -05:00
jc01rho 9f1066ce83 feat(lateral): add confidence-gated lane centering
Adapt the lane-centering implementation from PR #74 by @jc01rho.

Keep controls in Galaxy developer settings, add confidence and geometry gates, preserve E2E path authority, and reset all related offsets through Safe Mode.
2026-07-23 00:03:23 -05:00
firestarsdog 370654637a Big UI : Map Data update 2026-07-22 21:08:38 -04:00
firestar5683 fb854cecd3 build 2026-07-22 19:36:10 -05:00
firestar5683 713ce294cc revert can ignition 2026-07-22 19:27:37 -05:00
firestarsdog 7450b9de9a Big UI : Speed Racer 2026-07-22 17:12:48 -04:00
firestarsdog 5b2b053afd Big UI Camera Fix - Fix Replay 2026-07-22 16:58:54 -04:00
234 changed files with 7887 additions and 252956 deletions
+2 -2
View File
@@ -34,7 +34,7 @@ runs:
- name: setup github cache
id: gha-cache
if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }}
uses: 'actions/cache@v4'
uses: 'actions/cache@v5'
with:
path: ${{ inputs.path }}
key: ${{ inputs.key }}
@@ -43,7 +43,7 @@ runs:
- name: setup github cache
id: gha-cache-ro
if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }}
uses: 'actions/cache/restore@v4'
uses: 'actions/cache/restore@v5'
with:
path: ${{ inputs.path }}
key: ${{ inputs.key }}
@@ -14,7 +14,7 @@ runs:
${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \
scons -j$(nproc) --cache-populate"
- name: Save scons cache
uses: actions/cache/save@v4
uses: actions/cache/save@v5
if: github.ref == 'refs/heads/master'
with:
path: .ci_cache/scons_cache
+1 -1
View File
@@ -88,7 +88,7 @@ jobs:
fi
- name: Checkout target branch
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ env.BUILD_BRANCH }}
fetch-depth: 0
+1 -1
View File
@@ -48,7 +48,7 @@ jobs:
fi
- name: Checkout target branch
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ env.BUILD_BRANCH }}
fetch-depth: 0
@@ -17,17 +17,17 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push runner image
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .
file: tools/truenas_github_runner/Dockerfile
+10
View File
@@ -224,6 +224,16 @@ struct StarPilotPlan @0xf98d843bfd7004a3 {
struct StarPilotRadarState @0xb86e6369214c01c8 {
leadLeft @0 :LeadData;
leadRight @1 :LeadData;
adjacentStopped @2 :AdjacentStopped;
# A vehicle in an adjacent lane that was observed MOVING and then came to rest.
# Distinct from leadLeft/leadRight, which are moving-target-only by design.
struct AdjacentStopped {
status @0 :Bool;
dRel @1 :Float32;
yRel @2 :Float32;
radarTrackId @3 :Int32 = -1;
}
struct LeadData {
dRel @0 :Float32;
Binary file not shown.
+15 -7
View File
@@ -58,26 +58,34 @@ def file_chunked_exists(path) -> bool:
class ChunkStream(io.RawIOBase):
def __init__(self, paths):
self._paths = iter(paths)
self._buffer = memoryview(b"")
self._file = None
def readable(self):
return True
def readinto(self, buffer):
count = 0
view = memoryview(buffer)
while count < len(buffer):
if not self._buffer:
if self._file is None:
path = next(self._paths, None)
if path is None:
break
self._buffer = memoryview(Path(path).read_bytes())
self._file = open(path, "rb")
bytes_read = self._file.readinto(view[count:])
if not bytes_read:
self._file.close()
self._file = None
continue
take = min(len(buffer) - count, len(self._buffer))
buffer[count:count + take] = self._buffer[:take]
self._buffer = self._buffer[take:]
count += take
count += bytes_read
return count
def close(self):
if self._file is not None:
self._file.close()
self._file = None
super().close()
def open_file_chunked(path):
chunks = get_existing_chunks(path)
Binary file not shown.
+15 -1
View File
@@ -338,7 +338,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"StarPilotFavoriteSlots", {PERSISTENT, JSON, "[]", "[]", 1}},
{"StarPilotStats", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"StarPilotTogglesUpdated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"FrogsGoMoosTweak", {PERSISTENT, BOOL, "1", "0", 2}},
{"GoatScream", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"GoatScreamCriticalAlerts", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"GreenLightAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
@@ -371,7 +370,12 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"IssueReported", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
{"KonikDongleId", {PERSISTENT, STRING, "", "", 0}},
{"KonikMinutes", {PERSISTENT, INT, "0", "0", 0}},
{"LaneCentering", {PERSISTENT, BOOL, "0", "0", 2}},
{"LaneCenteringE2EAuthority", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"LaneCenterOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"LaneChanges", {PERSISTENT, BOOL, "1", "1", 0, SETTINGS_SIMPLE}},
{"LaneChangeCloseGap", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"LaneChangeCloseGapSeconds", {PERSISTENT, FLOAT, "1.0", "1.0", 1, SETTINGS_SIMPLE}},
{"LaneChangeSmoothing", {PERSISTENT, INT, "5", "10", 1, SETTINGS_SIMPLE}},
{"LaneChangeTime", {PERSISTENT, FLOAT, "1.0", "0.0", 1, SETTINGS_SIMPLE}},
{"LaneDetectionWidth", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
@@ -647,6 +651,16 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"UseSI", {PERSISTENT, BOOL, "1", "1", 3}},
{"UserFavorites", {PERSISTENT, STRING, "", "", 1}},
{"UseVienna", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"VASMAnnotationConfig", {PERSISTENT, JSON, "{}", "{}", 2}},
{"VASMConfidenceThreshold", {PERSISTENT, FLOAT, "0.85", "0.85", 2}},
{"VASMEnabled", {PERSISTENT, BOOL, "0", "0", 1}},
{"VASMLeftActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMLeftConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}},
{"VASMLastUpdateMonoTime", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMRightActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMRightConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}},
{"VASMSmoothSeconds", {PERSISTENT, FLOAT, "0.2", "0.2", 2}},
{"VASMTimestampEof", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VEgoStarting", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VEgoStartingStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VEgoStopping", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
Binary file not shown.
+18
View File
@@ -1,3 +1,5 @@
from pathlib import Path
from openpilot.common import file_chunker
@@ -14,3 +16,19 @@ def test_chunked_stream_round_trip(tmp_path, monkeypatch):
assert file_chunker.read_file_chunked(path) == payload
with file_chunker.open_file_chunked(path) as stream:
assert stream.read(9) + stream.read() == payload
def test_unchunked_stream_does_not_materialize_file(tmp_path, monkeypatch):
path = tmp_path / "fat.onnx"
payload = b"large model read through bounded buffers"
path.write_bytes(payload)
original_read_bytes = Path.read_bytes
def reject_whole_file_read(candidate):
if candidate == path:
raise AssertionError("streaming must not call Path.read_bytes()")
return original_read_bytes(candidate)
monkeypatch.setattr(Path, "read_bytes", reject_whole_file_read)
with file_chunker.open_file_chunked(path) as stream:
assert stream.read() == payload
Binary file not shown.
+1
View File
@@ -603,6 +603,7 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kpV = [0.095, 0.085, 0.065, 0.050]
ret.longitudinalTuning.kiV = [0.07, 0.10, 0.15, 0.24]
ret.longitudinalTuning.kfDEPRECATED = 0.20
ret.longitudinalActuatorDelay = 0.6
else:
ret.longitudinalTuning.kfDEPRECATED = 0.25
@@ -66,6 +66,38 @@ class TestGMFingerprint:
class TestGMInterface:
@parameterized.expand([
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
CAR.CHEVROLET_BOLT_CC_2022_2023,
CAR.CHEVROLET_MALIBU_HYBRID_CC,
])
def test_bolt_pedal_long_uses_shared_planning_delay_without_retuning_pid(self, car_model):
CarInterface = interfaces[car_model]
fingerprint = _empty_fingerprint()
fingerprint[0][0x201] = 8
params = Params()
try:
params.put_bool("GMPedalLongitudinal", True)
car_params = CarInterface.get_params(
car_model,
fingerprint,
[],
alpha_long=False,
is_release=False,
docs=False,
starpilot_toggles=_test_starpilot_toggles(),
)
finally:
params.remove("GMPedalLongitudinal")
assert car_params.longitudinalActuatorDelay == pytest.approx(0.6)
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.095, 0.085, 0.065, 0.050])
assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.07, 0.10, 0.15, 0.24])
assert car_params.longitudinalTuning.kfDEPRECATED == pytest.approx(0.20)
def test_bolt_acc_pedal_pid_accel_limits_keep_full_negative_authority(self):
cp = SimpleNamespace(
enableGasInterceptorDEPRECATED=True,
@@ -28,6 +28,7 @@ ENABLE_BUTTONS = (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.can
# Track when ECU disable happened - used to permanently suppress CAN errors from disabled ECU
ECU_DISABLE_TIMESTAMP = 0.0
KONA_NON_SCC_FCA_RADAR_ADDR = 0x602
KIA_EV9_ACCEL_MAX = 2.5
def apply_platform_longitudinal_params(ret: structs.CarParams) -> None:
@@ -80,7 +81,8 @@ class CarInterface(CarInterfaceBase):
@staticmethod
def get_pid_accel_limits(CP, current_speed, cruise_speed):
return ACCEL_MIN, CarControllerParams.ACCEL_MAX
accel_max = KIA_EV9_ACCEL_MAX if CP.carFingerprint == CAR.KIA_EV9 else CarControllerParams.ACCEL_MAX
return ACCEL_MIN, accel_max
@staticmethod
def apply_post_fingerprint_params(CP: structs.CarParams, candidate, fingerprint, car_fw) -> None:
@@ -17,7 +17,7 @@ from opendbc.car.hyundai.carcontroller import CarController, Ioniq6LongitudinalT
direct_angle_request_allowed, get_angle_smoothing_alpha, \
should_use_ev6_gt_line_stop_direct_tracking
from opendbc.car.hyundai.carstate import CarState, decode_canfd_camera_lead, decode_ioniq_6_blindspot_radar_state
from opendbc.car.hyundai.interface import CarInterface
from opendbc.car.hyundai.interface import CarInterface, KIA_EV9_ACCEL_MAX
from opendbc.car.hyundai import hyundaican, hyundaicanfd
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.radar_interface import MRREVO14F_RADAR_START_ADDR, MRR30_RADAR_START_ADDR, MRR35_RADAR_START_ADDR, \
@@ -26,7 +26,7 @@ from opendbc.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR
HYBRID_CAR, EV_CAR, FW_QUERY_CONFIG, LEGACY_SAFETY_MODE_CAR, CANFD_FUZZY_WHITELIST, \
UNSUPPORTED_LONGITUDINAL_CAR, PLATFORM_CODE_ECUS, HYUNDAI_VERSION_REQUEST_LONG, \
LEGACY_LONGITUDINAL_CAR, DBC, HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
HyundaiStarPilotSafetyFlags, Buttons, kia_ev6_gt_line_longitudinal_tuning
HyundaiStarPilotSafetyFlags, Buttons, CarControllerParams, kia_ev6_gt_line_longitudinal_tuning
LongCtrlState = CarControl.Actuators.LongControlState
from opendbc.car.hyundai.fingerprints import FW_VERSIONS
@@ -1117,6 +1117,10 @@ class TestHyundaiFingerprint:
assert CP.startAccel == pytest.approx(0.2)
assert CP.vEgoStarting == pytest.approx(0.5)
assert CP.longitudinalActuatorDelay == pytest.approx(0.3)
assert CarInterface.get_pid_accel_limits(CP, 0.0, 0.0)[1] == pytest.approx(KIA_EV9_ACCEL_MAX)
ioniq_6_cp = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, gen_empty_fingerprint(), [], True, False, False, toggles)
assert CarInterface.get_pid_accel_limits(ioniq_6_cp, 0.0, 0.0)[1] == pytest.approx(CarControllerParams.ACCEL_MAX)
def test_ioniq_6_longitudinal_tuning_helper_matches_dynamic_profile(self):
state = Ioniq6LongitudinalTuningState()
@@ -73,7 +73,6 @@ def get_test_starpilot_toggles() -> SimpleNamespace:
cluster_offset=1.0,
disable_openpilot_long=False,
force_fingerprint=False,
frogsgomoo_tweak=False,
lock_doors=False,
reverse_cruise_increase=False,
sng_hack=False,
@@ -444,10 +444,7 @@ class CarController(CarControllerBase):
self.aego.update(a_ego_blended)
j_ego = (self.aego.x - prev_aego) / (DT_CTRL * 3)
if starpilot_toggles.frogsgomoo_tweak:
future_t = float(np.interp(CS.out.vEgo, [2., 5.], [0.35, 1.0]))
else:
future_t = float(np.interp(CS.out.vEgo, [2., 5.], [0.25, 0.5]))
future_t = float(np.interp(CS.out.vEgo, [2., 5.], [0.25, 0.5]))
a_ego_future = a_ego_blended + j_ego * future_t
if CC.longActive:
@@ -194,6 +194,9 @@ class CarInterface(CarInterfaceBase):
ret.vEgoStarting = 0.25
ret.stoppingDecelRate = 0.3
if candidate == CAR.TOYOTA_HIGHLANDER and ret.openpilotLongitudinalControl and not ret.flags & ToyotaFlags.HYBRID.value:
ret.longitudinalActuatorDelay = 0.4
if ret.enableGasInterceptorDEPRECATED:
# Pedal/SDSU Toyotas feel best with a softer final stop clamp.
ret.longitudinalActuatorDelay = max(ret.longitudinalActuatorDelay, 0.2)
@@ -101,6 +101,32 @@ class TestToyotaInterfaces:
assert abs(car_params.vEgoStopping - 0.25) < 1e-6
assert abs(car_params.vEgoStarting - 0.25) < 1e-6
def test_highlander_ice_openpilot_long_uses_measured_actuator_delay(self):
stock_params = CarInterface.get_params(
CAR.TOYOTA_HIGHLANDER,
{bus: {} for bus in range(8)},
[],
alpha_long=False,
is_release=False,
docs=False,
starpilot_toggles=SimpleNamespace(),
)
long_params = CarInterface.get_params(
CAR.TOYOTA_HIGHLANDER,
{bus: ({0x2FF: 8} if bus == 0 else {}) for bus in range(8)},
[],
alpha_long=False,
is_release=False,
docs=False,
starpilot_toggles=SimpleNamespace(),
)
assert not stock_params.openpilotLongitudinalControl
assert stock_params.longitudinalActuatorDelay == pytest.approx(0.15)
assert long_params.openpilotLongitudinalControl
assert not long_params.flags & ToyotaFlags.HYBRID.value
assert long_params.longitudinalActuatorDelay == pytest.approx(0.4)
@pytest.mark.parametrize("camera_message", [0x343, 0x4CB])
def test_dsu_bypass_enables_longitudinal(self, camera_message):
fingerprint = {bus: {} for bus in range(8)}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,2 +1,2 @@
extern const uint8_t gitversion[19];
const uint8_t gitversion[19] = "DEV-d773ad90-DEBUG";
const uint8_t gitversion[19] = "DEV-f6d38dbd-DEBUG";
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
DEV-d773ad90-DEBUG
DEV-f6d38dbd-DEBUG
+6 -1
View File
@@ -166,7 +166,12 @@ expected_capnp_version() {
image_capnp_version() {
local engine="$1"
"${engine}" run --rm --platform linux/arm64 "${IMAGE_NAME}" bash -lc "capnp --version | awk '{print \$4}'" 2>/dev/null || true
local version_output=""
version_output="$("${engine}" run --rm --platform linux/arm64 "${IMAGE_NAME}" capnp --version 2>&1 || true)"
printf '%s\n' "${version_output}" \
| sed -nE 's/.*version[[:space:]]+([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' \
| head -n 1
}
ensure_image_capnp_version() {
+2
View File
@@ -210,6 +210,8 @@ import msgq.ipc_pyx # noqa: F401
import msgq.visionipc.visionipc_pyx # noqa: F401
import openpilot.selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx # noqa: F401
import openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx # noqa: F401
assert hasattr(msgq.visionipc.visionipc_pyx.VisionBuf, "frame_id")
PY
}
+2
View File
@@ -212,6 +212,8 @@ import msgq.ipc_pyx # noqa: F401
import msgq.visionipc.visionipc_pyx # noqa: F401
import openpilot.selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx # noqa: F401
import openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx # noqa: F401
assert hasattr(msgq.visionipc.visionipc_pyx.VisionBuf, "frame_id")
PY
}
+74 -8
View File
@@ -5,6 +5,7 @@ import hashlib
import json
import os
import pickle
import shutil
import subprocess
import sys
from pathlib import Path
@@ -19,6 +20,7 @@ COMPILE_SCRIPT = REPO_ROOT / "tinygrad_repo/examples/openpilot/compile3.py"
DRIVING_COMPILE_SCRIPT = REPO_ROOT / "selfdrive/modeld/compile_modeld.py"
DM_WARP_COMPILE_SCRIPT = REPO_ROOT / "selfdrive/modeld/compile_dm_warp.py"
MODEL_VERSIONS_CACHE = Path("/data/models/.model_versions.json")
MODELS_PATH = MODEL_VERSIONS_CACHE.parent # runtime dir modeld loads from: /data/models
DM_MODEL_KEY = "dm"
DM_MODEL_NAME = "dmonitoring_model"
@@ -84,6 +86,11 @@ def parse_args() -> argparse.Namespace:
help="Compile the driving artifact for the USB AMD GPU.")
parser.add_argument("--split-artifact", type=Path, help="Split an existing oversized PKL without compiling.")
parser.add_argument("--chunk-size-mib", type=int, default=95, help="Multipart size in MiB; must be below 100.")
parser.add_argument("--no-split", action="store_true",
help="Keep a single .pkl even if >100 MiB (for local installs, which need one "
"file). Auto-enabled for local- model IDs.")
parser.add_argument("--no-install", action="store_true",
help="Do not auto-copy a local- model into /data/models after compiling.")
parser.add_argument(
"--image-history-pipeline",
choices=("policy", "warp"),
@@ -302,6 +309,48 @@ def multipart_output_paths(artifact: Path, output_dir: Path | None = None) -> li
]
def install_local_artifact(artifact: Path, model_key: str, version: str) -> None:
"""Copy a freshly compiled local- model into the runtime dir modeld loads from,
and ensure its <id>.json sidecar carries the correct version.
The sidecar version is NOT cosmetic: without it _discover_local_models() records
an empty version, which downstream parses on the wrong contract (a v15 model then
drives like v11). Since we know the build version here, we write it so the local
install is correct by default. Local models must be a single is_file() in
/data/models to show in the picker. No-ops off-device (no /data/models).
"""
if not MODELS_PATH.is_dir():
print(f" skipped auto-install: {MODELS_PATH} not present (not on device?)")
return
dest = MODELS_PATH / artifact.name
shutil.copy2(artifact, dest)
print(f" installed -> {dest}")
sidecar = MODELS_PATH / f"{model_key}.json"
info: dict = {}
if sidecar.is_file():
try:
loaded = json.loads(sidecar.read_text())
if isinstance(loaded, dict):
info = loaded
except Exception as error:
print(f" WARN: existing sidecar {sidecar.name} is malformed, rewriting: {error}")
if not version:
if not str(info.get("version") or "").strip():
print(f" WARN: could not determine version -- set it by hand in {sidecar.name} "
"or the model may drive on the wrong version contract")
return
# keep any user-set name/series; only guarantee a correct, non-empty version
if str(info.get("version") or "").strip() == version and sidecar.is_file():
print(f" sidecar ok: {sidecar.name} (version {version})")
return
info.setdefault("name", model_key[len("local-"):].replace("_", " ").replace("-", " ").strip())
info.setdefault("series", "Local")
info["version"] = version
sidecar.write_text(json.dumps(info, indent=2) + "\n")
print(f" wrote sidecar {sidecar.name} (version {version})")
def split_oversized_artifact(
artifact: Path,
output_dir: Path | None = None,
@@ -507,17 +556,34 @@ def main() -> int:
if not version and input_format == "supercombo":
version = "v15"
version_label = version or "unspecified behavior"
print(f"Compiling {model_key} ({input_format}, {version_label}) from {args.input_dir} -> {args.output_dir}")
will_install = model_key.startswith("local-") and not args.no_install
target = f"{args.output_dir}" + (f" -> {MODELS_PATH} (auto-install)" if will_install else "")
print(f"Compiling {model_key} ({input_format}, {version_label}) from {args.input_dir} -> {target}")
output = compile_driving(model_key, files, input_format, version, args.output_dir,
args.image_history_pipeline, args.external_gpu)
print(f" saved {output.name}")
multipart_outputs = split_oversized_artifact(output)
if multipart_outputs:
print(" artifact exceeds 100 MiB; created repository-safe multipart files:")
for multipart_output in multipart_outputs:
print(f" {multipart_output.name} ({multipart_output.stat().st_size} bytes)")
output.unlink()
print(f" removed oversized source artifact {output.name}")
# Local models install as a single is_file() and never go to GitHub, so the >100 MiB
# repo split is pointless for them (you'd only have to reassemble it). Keep one .pkl.
keep_single = args.no_split or model_key.startswith("local-")
if keep_single:
is_local = model_key.startswith("local-")
if output.stat().st_size > REPOSITORY_FILE_LIMIT:
size_mb = output.stat().st_size / 1e6
if is_local:
print(f" local model: kept as one {size_mb:.1f} MB file (repo split not needed)")
else:
print(f" --no-split: kept one {size_mb:.1f} MB file; over 100 MB, so split it "
"before committing to a repo (re-run without --no-split, or --split-artifact)")
if is_local and not args.no_install:
install_local_artifact(output, model_key, version)
else:
multipart_outputs = split_oversized_artifact(output)
if multipart_outputs:
print(" artifact exceeds 100 MiB; created repository-safe multipart files:")
for multipart_output in multipart_outputs:
print(f" {multipart_output.name} ({multipart_output.stat().st_size} bytes)")
output.unlink()
print(f" removed oversized source artifact {output.name}")
print("Done.")
return 0
-1
View File
@@ -42,7 +42,6 @@ def get_test_starpilot_toggles() -> SimpleNamespace:
cluster_offset=1.0,
disable_openpilot_long=False,
force_fingerprint=False,
frogsgomoo_tweak=False,
lock_doors=False,
reverse_cruise_increase=False,
sng_hack=False,
+11
View File
@@ -14,6 +14,7 @@ from opendbc.car.chrysler.values import pacifica_hybrid_aol_stock_acc_mode
from opendbc.car.gm.values import CAR as GM_CAR
from opendbc.car.vehicle_model import VehicleModel
from openpilot.selfdrive.controls.lib.drive_helpers import MAX_LATERAL_JERK, clip_curvature, get_lateral_active
from openpilot.selfdrive.controls.lib.lane_centering import LaneCenteringController
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD
@@ -305,6 +306,7 @@ class Controls:
self.curvature = 0.0
self.desired_curvature = 0.0
self.lc_smooth_release = 0.0
self.lane_centering = LaneCenteringController()
self.lc_entry_sign = 0.0
self.lc_arrest_jerk_factor = 1.0
self.turn_hold_curvature = 0.0
@@ -419,6 +421,7 @@ class Controls:
if not CC.latActive:
self.LaC.reset()
self.lane_centering.reset()
if not CC.longActive:
self.LoC.reset()
@@ -585,6 +588,14 @@ class Controls:
held_mag = min(lead_curvature * blinker_dir, abs(self.turn_hold_curvature) + CURVATURE_HOLD_RATCHET_RATE * DT_CTRL)
self.turn_hold_curvature = math.copysign(held_mag, lead_curvature)
new_desired_curvature = self.lane_centering.update(
new_desired_curvature, model_v2, CS.vEgo,
self.starpilot_toggles.lane_centering,
self.starpilot_toggles.lane_center_offset,
self.starpilot_toggles.lane_centering_e2e_authority,
CC.latActive,
bool(self.sm.all_checks(['modelV2'])))
jerk_factor = 1.0
if self.starpilot_toggles.lane_change_pace < 10:
set_jerk = self.starpilot_toggles.lane_change_jerk_factor
+134
View File
@@ -0,0 +1,134 @@
from cereal import log
import numpy as np
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.controls.lib.drive_helpers import smooth_value
_MIN_V_EGO = 5.0
_MIN_LANE_PROB = 0.6
_MAX_LANE_STD = 0.3
_MIN_LANE_WIDTH = 2.6
_MAX_LANE_WIDTH = 4.8
_MAX_OFFSET = 0.3
_MIN_CENTER_TO_LINE = 1.1
_MAX_RAW_CORRECTION = 0.004
_MAX_GAIN = 0.30
_SMOOTH_TAU = 0.4
_E2E_MAX_PATH_STD = 0.35
_E2E_BREAK_IN_START = 0.25
_E2E_BREAK_IN_FULL = 0.75
class LaneCenteringController:
def __init__(self) -> None:
self._correction = 0.0
def reset(self) -> None:
self._correction = 0.0
def update(self, model_curvature, model_v2, v_ego, enabled, offset, e2e_authority, lat_active, model_valid) -> float:
model_curvature = float(model_curvature)
try:
v_ego = float(v_ego)
offset = float(offset)
e2e_authority = float(e2e_authority)
except (TypeError, ValueError):
self.reset()
return model_curvature
if not np.isfinite([v_ego, offset, e2e_authority]).all():
self.reset()
return model_curvature
if not model_valid or not enabled or not lat_active or v_ego < _MIN_V_EGO:
self.reset()
return model_curvature
try:
if model_v2.meta.laneChangeState != log.LaneChangeState.off:
self.reset()
return model_curvature
except (AttributeError, TypeError, ValueError):
self.reset()
return model_curvature
valid, raw_correction = self._raw_correction(
model_v2,
v_ego,
float(np.clip(offset, -_MAX_OFFSET, _MAX_OFFSET)),
float(np.clip(e2e_authority, 0.0, 1.0)),
)
if not valid:
self.reset()
return model_curvature
target = float(np.clip(raw_correction, -_MAX_RAW_CORRECTION, _MAX_RAW_CORRECTION)) * _MAX_GAIN
self._correction = float(smooth_value(target, self._correction, _SMOOTH_TAU, dt=DT_CTRL))
return model_curvature + self._correction
@staticmethod
def _valid_path(x, y) -> bool:
return x.size >= 2 and x.size == y.size and np.isfinite(x).all() and np.isfinite(y).all() and np.all(np.diff(x) > 0)
@staticmethod
def _covers(x, distance: float) -> bool:
return bool(x[0] <= distance <= x[-1])
def _raw_correction(self, model_v2, v_ego: float, offset: float, e2e_authority: float) -> tuple[bool, float]:
try:
lane_lines = model_v2.laneLines
probs = np.asarray(model_v2.laneLineProbs, dtype=float)
stds = np.asarray(model_v2.laneLineStds, dtype=float)
if len(lane_lines) < 3 or probs.size < 3 or stds.size < 3:
return False, 0.0
if not np.isfinite(probs[[1, 2]]).all() or not np.isfinite(stds[[1, 2]]).all():
return False, 0.0
if np.any(probs[[1, 2]] < _MIN_LANE_PROB) or np.any(probs[[1, 2]] > 1.0):
return False, 0.0
if np.any(stds[[1, 2]] < 0.0) or np.any(stds[[1, 2]] > _MAX_LANE_STD):
return False, 0.0
left_x = np.asarray(lane_lines[1].x, dtype=float)
left_y = np.asarray(lane_lines[1].y, dtype=float)
right_x = np.asarray(lane_lines[2].x, dtype=float)
right_y = np.asarray(lane_lines[2].y, dtype=float)
pos_x = np.asarray(model_v2.position.x, dtype=float)
pos_y = np.asarray(model_v2.position.y, dtype=float)
if not (self._valid_path(left_x, left_y) and self._valid_path(right_x, right_y) and self._valid_path(pos_x, pos_y)):
return False, 0.0
lookahead = float(np.clip(v_ego, 8.0, 35.0))
if not all(self._covers(x, lookahead) for x in (left_x, right_x, pos_x)):
return False, 0.0
left = float(np.interp(lookahead, left_x, left_y))
right = float(np.interp(lookahead, right_x, right_y))
width = right - left
if not _MIN_LANE_WIDTH <= width <= _MAX_LANE_WIDTH:
return False, 0.0
max_safe_offset = min(_MAX_OFFSET, max(0.0, width * 0.5 - _MIN_CENTER_TO_LINE))
target_y = 0.5 * (left + right) + float(np.clip(offset, -max_safe_offset, max_safe_offset))
model_y = float(np.interp(lookahead, pos_x, pos_y))
error = target_y - model_y
try:
pos_y_std = np.asarray(model_v2.position.yStd, dtype=float)
if self._valid_path(pos_x, pos_y_std):
path_std = float(np.interp(lookahead, pos_x, pos_y_std))
if 0.0 <= path_std <= _E2E_MAX_PATH_STD:
break_in = np.clip(
(abs(error) - _E2E_BREAK_IN_START) / (_E2E_BREAK_IN_FULL - _E2E_BREAK_IN_START),
0.0,
1.0,
)
error *= 1.0 - e2e_authority * float(break_in)
except (AttributeError, TypeError, ValueError):
pass
return True, float(2.0 * error / lookahead ** 2)
except (AttributeError, IndexError, TypeError, ValueError):
return False, 0.0

Some files were not shown because too many files have changed in this diff Show More