custom accel and screen timeout

This commit is contained in:
firestar5683
2026-04-04 19:12:45 -05:00
parent 5f1e0eeb3a
commit 4ebe5a277a
49 changed files with 424 additions and 117 deletions
Binary file not shown.
+8
View File
@@ -199,6 +199,14 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CurvatureData", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1}},
{"CustomAlerts", {PERSISTENT, BOOL, "0", "0", 0}},
{"CustomAccelProfile", {PERSISTENT, BOOL, "0", "0", 3}},
{"CustomAccelProfile0MPH", {PERSISTENT, FLOAT, "3.0", "3.0", 3}},
{"CustomAccelProfile11MPH", {PERSISTENT, FLOAT, "2.5", "2.5", 3}},
{"CustomAccelProfile22MPH", {PERSISTENT, FLOAT, "2.0", "2.0", 3}},
{"CustomAccelProfile34MPH", {PERSISTENT, FLOAT, "1.5", "1.5", 3}},
{"CustomAccelProfile45MPH", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"CustomAccelProfile56MPH", {PERSISTENT, FLOAT, "0.8", "0.8", 3}},
{"CustomAccelProfile89MPH", {PERSISTENT, FLOAT, "0.6", "0.6", 3}},
{"CustomCruise", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"CustomCruiseLong", {PERSISTENT, FLOAT, "5.0", "5.0", 2}},
{"CustomPersonalities", {PERSISTENT, BOOL, "0", "0", 2}},
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-a695eda0-DEBUG";
const uint8_t gitversion[19] = "DEV-5f1e0eeb-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.
+1 -1
View File
@@ -1 +1 @@
DEV-a695eda0-DEBUG
DEV-5f1e0eeb-DEBUG
Binary file not shown.
BIN
View File
Binary file not shown.
+15 -9
View File
@@ -237,20 +237,26 @@ void Device::updateBrightness(const UIState &s, const StarPilotUIState &fs) {
void Device::updateWakefulness(const UIState &s, const StarPilotUIState &fs) {
const StarPilotUIScene &starpilot_scene = fs.starpilot_scene;
const QJsonObject &starpilot_toggles = starpilot_scene.starpilot_toggles;
const bool standby_mode = starpilot_toggles.value("standby_mode").toBool();
const int screen_timeout = starpilot_toggles.value("screen_timeout").toInt();
const int screen_timeout_onroad = starpilot_toggles.value("screen_timeout_onroad").toInt();
bool ignition_just_turned_off = !s.scene.ignition && ignition_on;
bool ignition_state_changed = s.scene.ignition != ignition_on;
ignition_on = s.scene.ignition;
if (ignition_on && starpilot_toggles.value("standby_mode").toBool()) {
if (starpilot_scene.wake_up_screen) {
resetInteractiveTimeout(starpilot_toggles.value("screen_timeout").toInt(), starpilot_toggles.value("screen_timeout_onroad").toInt());
} else {
// Standby mode should extend the current wake window for alerts and status
// changes, but it must not clear the timer every frame or manual wakes will
// collapse immediately.
if (ignition_on && standby_mode && starpilot_scene.wake_up_screen) {
resetInteractiveTimeout(screen_timeout, screen_timeout_onroad);
}
if (ignition_state_changed) {
if (ignition_on && starpilot_toggles.value("screen_brightness_onroad").toInt() == 0 && !standby_mode) {
resetInteractiveTimeout(0, 0);
} else {
resetInteractiveTimeout(screen_timeout, screen_timeout_onroad);
}
} else if (ignition_just_turned_off) {
resetInteractiveTimeout(starpilot_toggles.value("screen_timeout").toInt(), starpilot_toggles.value("screen_timeout_onroad").toInt());
} else if (ignition_on && starpilot_toggles.value("screen_brightness_onroad").toInt() == 0) {
resetInteractiveTimeout(0, 0);
} else if (interactive_timeout > 0 && --interactive_timeout == 0) {
emit interactiveTimeout();
}
+143
View File
@@ -0,0 +1,143 @@
#!/usr/bin/env python3
from __future__ import annotations
from openpilot.selfdrive.controls.lib.longitudinal_planner import get_max_accel
ACCELERATION_PROFILES = {
"STANDARD": 0,
"ECO": 1,
"SPORT": 2,
"SPORT_PLUS": 3,
}
DECELERATION_PROFILES = {
"STANDARD": 0,
"ECO": 1,
"SPORT": 2,
}
# MPH = [0.0, 11, 22, 34, 45, 56, 89]
A_CRUISE_MAX_BP_CUSTOM = [0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 40.0]
CUSTOM_ACCEL_PROFILE_PARAM_SPECS = [
("CustomAccelProfile0MPH", 0),
("CustomAccelProfile11MPH", 11),
("CustomAccelProfile22MPH", 22),
("CustomAccelProfile34MPH", 34),
("CustomAccelProfile45MPH", 45),
("CustomAccelProfile56MPH", 56),
("CustomAccelProfile89MPH", 89),
]
CUSTOM_ACCEL_PROFILE_PARAM_KEYS = [key for key, _ in CUSTOM_ACCEL_PROFILE_PARAM_SPECS]
CUSTOM_ACCEL_PROFILE_VALUE_MIN = 0.0
CUSTOM_ACCEL_PROFILE_VALUE_MAX = 6.0
A_CRUISE_MAX_VALS_ECO_EV = [1.25, 1.25, 1.25, 1.25, 1.45, 1.50, 2.00]
A_CRUISE_MAX_VALS_STANDARD_EV = [1.35, 1.35, 1.35, 1.35, 1.60, 1.60, 2.10]
A_CRUISE_MAX_VALS_SPORT_EV = [1.55, 1.55, 1.55, 1.55, 1.84, 1.84, 2.42]
A_CRUISE_MAX_VALS_SPORT_PLUS_EV = [1.7825, 1.7825, 1.7825, 1.7825, 2.116, 2.116, 2.783]
A_CRUISE_MAX_VALS_ECO_GAS = [2.0, 1.5, 1.0, 0.8, 0.6, 0.4, 0.2]
A_CRUISE_MAX_VALS_SPORT_GAS = [3.0, 2.5, 2.0, 1.5, 1.0, 0.8, 0.6]
A_CRUISE_MAX_VALS_ECO_TRUCK = [3.00, 1.05, 0.60, 0.50, 0.50, 0.45, 0.35]
A_CRUISE_MAX_VALS_STANDARD_TRUCK = [6.00, 1.10, 0.70, 0.60, 0.55, 0.45, 0.35]
A_CRUISE_MAX_VALS_SPORT_TRUCK = [6.00, 1.15, 0.75, 0.70, 0.60, 0.50, 0.40]
A_CRUISE_MAX_VALS_SPORT_PLUS_TRUCK = [6.00, 1.30, 0.90, 0.80, 0.70, 0.60, 0.45]
def akima_interp(x, xp, fp):
if x <= xp[0]:
return fp[0]
if x >= xp[-1]:
return fp[-1]
i = max(0, min(len(xp) - 2, int(next(idx for idx, bp in enumerate(xp[1:], start=1) if bp >= x) - 1)))
t = (x - xp[i]) / float(xp[i + 1] - xp[i])
t2 = t * t
t3 = t2 * t
t4 = t2 * t2
return (fp[i] * (1 - 10 * t3 + 15 * t4 - 6 * t3 * t2)
+ fp[i + 1] * (10 * t3 - 15 * t4 + 6 * t3 * t2))
def normalize_acceleration_profile(value):
return _normalize_profile(value, ACCELERATION_PROFILES, ACCELERATION_PROFILES["STANDARD"])
def normalize_deceleration_profile(value):
return _normalize_profile(value, DECELERATION_PROFILES, DECELERATION_PROFILES["STANDARD"])
def get_accel_profile_curve_values(acceleration_profile, ev_tuning=True, truck_tuning=False):
profile = normalize_acceleration_profile(acceleration_profile)
if truck_tuning:
ev_tuning = False
if profile == ACCELERATION_PROFILES["ECO"]:
if ev_tuning:
return list(A_CRUISE_MAX_VALS_ECO_EV)
if truck_tuning:
return list(A_CRUISE_MAX_VALS_ECO_TRUCK)
return list(A_CRUISE_MAX_VALS_ECO_GAS)
if profile == ACCELERATION_PROFILES["SPORT"]:
if ev_tuning:
return list(A_CRUISE_MAX_VALS_SPORT_EV)
if truck_tuning:
return list(A_CRUISE_MAX_VALS_SPORT_TRUCK)
return list(A_CRUISE_MAX_VALS_SPORT_GAS)
if profile == ACCELERATION_PROFILES["SPORT_PLUS"]:
if ev_tuning:
return list(A_CRUISE_MAX_VALS_SPORT_PLUS_EV)
if truck_tuning:
return list(A_CRUISE_MAX_VALS_SPORT_PLUS_TRUCK)
return [float(akima_interp(v_ego, [0.0, 5.0, 20.0], [4.0, 4.0, 2.0])) for v_ego in A_CRUISE_MAX_BP_CUSTOM]
if ev_tuning:
return list(A_CRUISE_MAX_VALS_STANDARD_EV)
if truck_tuning:
return list(A_CRUISE_MAX_VALS_STANDARD_TRUCK)
return [float(get_max_accel(v_ego)) for v_ego in A_CRUISE_MAX_BP_CUSTOM]
def interpolate_accel_profile(v_ego, curve_values):
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, curve_values))
def get_max_allowed_accel(v_ego, ev_tuning=True, truck_tuning=False):
return interpolate_accel_profile(v_ego, get_accel_profile_curve_values(ACCELERATION_PROFILES["SPORT_PLUS"], ev_tuning, truck_tuning))
def build_custom_accel_profile_defaults(acceleration_profile, ev_tuning=True, truck_tuning=False):
curve_values = get_accel_profile_curve_values(acceleration_profile, ev_tuning, truck_tuning)
return {
key: float(curve_values[idx])
for idx, key in enumerate(CUSTOM_ACCEL_PROFILE_PARAM_KEYS)
}
def coerce_custom_accel_profile_values(raw_values, acceleration_profile, ev_tuning=True, truck_tuning=False):
defaults = get_accel_profile_curve_values(acceleration_profile, ev_tuning, truck_tuning)
values = []
for idx, default in enumerate(defaults):
try:
value = float(raw_values[idx])
except (IndexError, TypeError, ValueError):
value = default
values.append(min(CUSTOM_ACCEL_PROFILE_VALUE_MAX, max(CUSTOM_ACCEL_PROFILE_VALUE_MIN, value)))
return values
def _normalize_profile(value, profile_map, fallback):
if isinstance(value, bytes):
value = value.decode("utf-8", errors="replace")
if isinstance(value, str):
normalized = value.strip().upper().replace("+", "_PLUS").replace(" ", "_")
if normalized in profile_map:
return profile_map[normalized]
try:
return int(float(value))
except (TypeError, ValueError):
return fallback
+8
View File
@@ -48,6 +48,14 @@ SAFE_MODE_MANAGED_KEYS = (
"AdvancedLongitudinalTune",
"EVTuning",
"TruckTuning",
"CustomAccelProfile",
"CustomAccelProfile0MPH",
"CustomAccelProfile11MPH",
"CustomAccelProfile22MPH",
"CustomAccelProfile34MPH",
"CustomAccelProfile45MPH",
"CustomAccelProfile56MPH",
"CustomAccelProfile89MPH",
"LongitudinalActuatorDelay",
"MaxDesiredAcceleration",
"StartAccel",
+24 -2
View File
@@ -10,6 +10,7 @@ from pathlib import Path
from types import SimpleNamespace
import cereal.messaging as messaging
import numpy as np
from cereal import car, custom, log
from opendbc.car import gen_empty_fingerprint
@@ -25,6 +26,16 @@ from openpilot.common.constants import CV
from openpilot.common.params import Params
from openpilot.selfdrive.controls.lib.latcontrol_torque import KP
from openpilot.selfdrive.modeld.constants import ModelConstants
from openpilot.starpilot.common.accel_profile import (
ACCELERATION_PROFILES,
CUSTOM_ACCEL_PROFILE_PARAM_KEYS,
CUSTOM_ACCEL_PROFILE_VALUE_MAX,
CUSTOM_ACCEL_PROFILE_VALUE_MIN,
DECELERATION_PROFILES,
build_custom_accel_profile_defaults,
normalize_acceleration_profile,
normalize_deceleration_profile,
)
from openpilot.system.hardware import HARDWARE
from openpilot.system.hardware.hw import Paths
from openpilot.system.hardware.power_monitoring import VBATT_PAUSE_CHARGING
@@ -787,8 +798,19 @@ class StarPilotVariables:
toggle.lock_doors_timer = self.get_value("LockDoorsTimer", cast=float, condition=(toggle.car_make == "toyota"))
longitudinal_tuning = toggle.openpilot_longitudinal and self.get_value("LongitudinalTune")
toggle.acceleration_profile = self.get_value("AccelerationProfile", cast=float, condition=longitudinal_tuning)
toggle.deceleration_profile = self.get_value("DecelerationProfile", cast=float, condition=longitudinal_tuning)
toggle.acceleration_profile = normalize_acceleration_profile(
self.get_value("AccelerationProfile", cast=None, condition=longitudinal_tuning, default=ACCELERATION_PROFILES["SPORT"])
)
toggle.deceleration_profile = normalize_deceleration_profile(
self.get_value("DecelerationProfile", cast=None, condition=longitudinal_tuning, default=DECELERATION_PROFILES["ECO"])
)
toggle.custom_accel_profile = self.get_value("CustomAccelProfile", condition=longitudinal_tuning)
custom_accel_defaults = build_custom_accel_profile_defaults(toggle.acceleration_profile, toggle.ev_tuning, toggle.truck_tuning)
toggle.custom_accel_profile_values = [
self.get_value(key, cast=float, condition=longitudinal_tuning, default=custom_accel_defaults[key],
min=CUSTOM_ACCEL_PROFILE_VALUE_MIN, max=CUSTOM_ACCEL_PROFILE_VALUE_MAX)
for key in CUSTOM_ACCEL_PROFILE_PARAM_KEYS
]
toggle.human_acceleration = self.get_value("HumanAcceleration", condition=longitudinal_tuning)
toggle.human_following = self.get_value("HumanFollowing", condition=longitudinal_tuning)
toggle.human_lane_changes = has_radar and self.get_value("HumanLaneChanges", condition=longitudinal_tuning)
@@ -3,6 +3,14 @@ import numpy as np
from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, get_max_accel
from openpilot.starpilot.common.accel_profile import (
ACCELERATION_PROFILES,
DECELERATION_PROFILES,
coerce_custom_accel_profile_values,
get_accel_profile_curve_values,
get_max_allowed_accel as get_profile_max_allowed_accel,
interpolate_accel_profile,
)
from openpilot.starpilot.common.starpilot_variables import CITY_SPEED_LIMIT
def cubic_interp(x, xp, fp):
@@ -45,56 +53,20 @@ def akima_interp(x, xp, fp):
A_CRUISE_MIN_ECO = A_CRUISE_MIN / 2
A_CRUISE_MIN_SPORT = A_CRUISE_MIN * 2
# MPH = [0.0, 11, 22, 34, 45, 56, 89]
A_CRUISE_MAX_BP_CUSTOM = [0.0, 5., 10., 15., 20., 25., 40.]
A_CRUISE_MAX_VALS_ECO_EV = [1.25, 1.25, 1.25, 1.25, 1.45, 1.50, 2.00]
A_CRUISE_MAX_VALS_STANDARD_EV = [1.35, 1.35, 1.35, 1.35, 1.60, 1.60, 2.10]
A_CRUISE_MAX_VALS_SPORT_EV = [1.55, 1.55, 1.55, 1.55, 1.84, 1.84, 2.42]
A_CRUISE_MAX_VALS_SPORT_PLUS_EV = [1.7825, 1.7825, 1.7825, 1.7825, 2.116, 2.116, 2.783]
A_CRUISE_MAX_VALS_ECO_GAS = [2.0, 1.5, 1.0, 0.8, 0.6, 0.4, 0.2]
A_CRUISE_MAX_VALS_SPORT_GAS = [3.0, 2.5, 2.0, 1.5, 1.0, 0.8, 0.6]
A_CRUISE_MAX_VALS_ECO_TRUCK = [3.00, 1.05, 0.60, 0.50, 0.50, 0.45, 0.35]
A_CRUISE_MAX_VALS_STANDARD_TRUCK = [6.00, 1.10, 0.70, 0.60, 0.55, 0.45, 0.35]
A_CRUISE_MAX_VALS_SPORT_TRUCK = [6.00, 1.15, 0.75, 0.70, 0.60, 0.50, 0.40]
A_CRUISE_MAX_VALS_SPORT_PLUS_TRUCK = [6.00, 1.30, 0.90, 0.80, 0.70, 0.60, 0.45]
ACCELERATION_PROFILES = {
"STANDARD": 0,
"ECO": 1,
"SPORT": 2,
"SPORT_PLUS": 3
}
DECELERATION_PROFILES = {
"STANDARD": 0,
"ECO": 1,
"SPORT": 2
}
def get_max_accel_eco(v_ego, ev_tuning=True, truck_tuning=False):
if ev_tuning:
cruise_vals = A_CRUISE_MAX_VALS_ECO_EV
elif truck_tuning:
cruise_vals = A_CRUISE_MAX_VALS_ECO_TRUCK
else:
cruise_vals = A_CRUISE_MAX_VALS_ECO_GAS
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, cruise_vals))
return interpolate_accel_profile(v_ego, get_accel_profile_curve_values(ACCELERATION_PROFILES["ECO"], ev_tuning, truck_tuning))
def get_max_accel_sport(v_ego, ev_tuning=True, truck_tuning=False):
if ev_tuning:
cruise_vals = A_CRUISE_MAX_VALS_SPORT_EV
elif truck_tuning:
cruise_vals = A_CRUISE_MAX_VALS_SPORT_TRUCK
else:
cruise_vals = A_CRUISE_MAX_VALS_SPORT_GAS
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, cruise_vals))
return interpolate_accel_profile(v_ego, get_accel_profile_curve_values(ACCELERATION_PROFILES["SPORT"], ev_tuning, truck_tuning))
def get_max_accel_standard(v_ego, ev_tuning=True, truck_tuning=False):
if ev_tuning:
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_STANDARD_EV))
if truck_tuning:
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_STANDARD_TRUCK))
return get_max_accel(v_ego)
if ev_tuning or truck_tuning:
return interpolate_accel_profile(v_ego, get_accel_profile_curve_values(ACCELERATION_PROFILES["STANDARD"], ev_tuning, truck_tuning))
return float(get_max_accel(v_ego))
def get_max_accel_custom(v_ego, custom_curve, acceleration_profile, ev_tuning=True, truck_tuning=False):
curve_values = coerce_custom_accel_profile_values(custom_curve, acceleration_profile, ev_tuning, truck_tuning)
return interpolate_accel_profile(v_ego, curve_values)
def get_max_accel_low_speeds(max_accel, v_cruise):
return float(akima_interp(v_cruise, [0., CITY_SPEED_LIMIT / 2, CITY_SPEED_LIMIT], [max_accel / 4, max_accel / 2, max_accel]))
@@ -103,11 +75,7 @@ def get_max_accel_ramp_off(max_accel, v_cruise, v_ego):
return float(akima_interp(v_cruise - v_ego, [0., 1., 5., 10.], [0., 0.5, 1.0, max_accel]))
def get_max_allowed_accel(v_ego, ev_tuning=True, truck_tuning=False):
if ev_tuning:
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_SPORT_PLUS_EV))
if truck_tuning:
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_SPORT_PLUS_TRUCK))
return float(akima_interp(v_ego, [0., 5., 20.], [4.0, 4.0, 2.0])) # ISO 15622:2018
return float(get_profile_max_allowed_accel(v_ego, ev_tuning, truck_tuning))
class StarPilotAcceleration:
def __init__(self, StarPilotPlanner):
@@ -121,8 +89,12 @@ class StarPilotAcceleration:
sport_gear = sm["starpilotCarState"].sportGear
ev_tuning = getattr(starpilot_toggles, "ev_tuning", True)
truck_tuning = getattr(starpilot_toggles, "truck_tuning", False)
custom_accel_profile = getattr(starpilot_toggles, "custom_accel_profile", False)
custom_accel_profile_values = getattr(starpilot_toggles, "custom_accel_profile_values", [])
if sm["starpilotCarState"].trafficModeEnabled:
if custom_accel_profile:
self.max_accel = get_max_accel_custom(v_ego, custom_accel_profile_values, starpilot_toggles.acceleration_profile, ev_tuning, truck_tuning)
elif sm["starpilotCarState"].trafficModeEnabled:
self.max_accel = get_max_accel_standard(v_ego, ev_tuning, truck_tuning)
elif starpilot_toggles.map_acceleration and (eco_gear or sport_gear):
if eco_gear:
@@ -6,6 +6,7 @@ const endpointOptionsInflight = {}
// Plain variables — scheduling/routing flags that must NOT be reactive
let syncScheduled = false
let lastParams = null
const DYNAMIC_DEFAULT_DEP_KEYS = new Set(["AccelerationProfile", "EVTuning", "TruckTuning"])
// Module-level state (persists across route changes)
const state = reactive({
@@ -141,6 +142,21 @@ async function fetchDefaultValues() {
}
}
async function refreshParamsAndDefaults() {
await fetchDefaultValues()
try {
const valuesRes = await fetch("/api/params/all")
if (valuesRes.ok) {
const data = await valuesRes.json()
state.values = data || {}
}
} catch (e) {
console.error("Failed to refresh param values:", e)
}
scheduleSyncInputs()
}
async function fetchLayoutAndParams() {
state.loadingLayout = true
state.loadingValues = true
@@ -176,14 +192,13 @@ async function fetchLayoutAndParams() {
// Pull params once at page load; local state handles subsequent edits.
try {
const valuesRes = await fetch("/api/params/all")
const data = await valuesRes.json()
state.values = data
if (!(await fetchDefaultValues())) {
state.defaultValues = {}
}
const valuesRes = await fetch("/api/params/all")
const data = await valuesRes.json()
state.values = data
} catch (e) {
console.error("Failed to fetch param values:", e)
state.defaultValues = {}
@@ -520,7 +535,11 @@ async function updateParam(key, elType) {
const updated = (data.updated && typeof data.updated === "object") ? data.updated : {}
state.values = { ...state.values, [key]: formattedVal, ...updated }
showParamSnackbar(data.message || `Parameter '${key}' updated.`)
scheduleSyncInputs()
if (DYNAMIC_DEFAULT_DEP_KEYS.has(key)) {
await refreshParamsAndDefaults()
} else {
scheduleSyncInputs()
}
} else {
revertInput(key, current, elType)
showParamSnackbar(data.error || "Failed to update parameter", "error")
@@ -254,6 +254,99 @@
"ui_type": "toggle",
"parent_key": "AdvancedLongitudinalTune"
},
{
"key": "CustomAccelProfile",
"label": "Custom Accel Profile",
"description": "Replace the built-in acceleration profile with your own per-speed max-acceleration values. Breakpoint speeds stay fixed, and the starting defaults mirror the currently selected acceleration profile plus EV or Truck tuning.",
"data_type": "bool",
"ui_type": "toggle",
"is_parent_toggle": true,
"parent_key": "AdvancedLongitudinalTune"
},
{
"key": "CustomAccelProfile0MPH",
"label": "0 mph",
"description": "Max acceleration in m/s² at the fixed 0 mph breakpoint.",
"data_type": "float",
"ui_type": "numeric",
"min": 0.0,
"max": 6.0,
"step": 0.01,
"precision": 2,
"parent_key": "CustomAccelProfile"
},
{
"key": "CustomAccelProfile11MPH",
"label": "11 mph",
"description": "Max acceleration in m/s² at the fixed 11 mph breakpoint.",
"data_type": "float",
"ui_type": "numeric",
"min": 0.0,
"max": 6.0,
"step": 0.01,
"precision": 2,
"parent_key": "CustomAccelProfile"
},
{
"key": "CustomAccelProfile22MPH",
"label": "22 mph",
"description": "Max acceleration in m/s² at the fixed 22 mph breakpoint.",
"data_type": "float",
"ui_type": "numeric",
"min": 0.0,
"max": 6.0,
"step": 0.01,
"precision": 2,
"parent_key": "CustomAccelProfile"
},
{
"key": "CustomAccelProfile34MPH",
"label": "34 mph",
"description": "Max acceleration in m/s² at the fixed 34 mph breakpoint.",
"data_type": "float",
"ui_type": "numeric",
"min": 0.0,
"max": 6.0,
"step": 0.01,
"precision": 2,
"parent_key": "CustomAccelProfile"
},
{
"key": "CustomAccelProfile45MPH",
"label": "45 mph",
"description": "Max acceleration in m/s² at the fixed 45 mph breakpoint.",
"data_type": "float",
"ui_type": "numeric",
"min": 0.0,
"max": 6.0,
"step": 0.01,
"precision": 2,
"parent_key": "CustomAccelProfile"
},
{
"key": "CustomAccelProfile56MPH",
"label": "56 mph",
"description": "Max acceleration in m/s² at the fixed 56 mph breakpoint.",
"data_type": "float",
"ui_type": "numeric",
"min": 0.0,
"max": 6.0,
"step": 0.01,
"precision": 2,
"parent_key": "CustomAccelProfile"
},
{
"key": "CustomAccelProfile89MPH",
"label": "89 mph",
"description": "Max acceleration in m/s² at the fixed 89 mph breakpoint.",
"data_type": "float",
"ui_type": "numeric",
"min": 0.0,
"max": 6.0,
"step": 0.01,
"precision": 2,
"parent_key": "CustomAccelProfile"
},
{
"key": "LongitudinalActuatorDelay",
"label": "Actuator Delay",
+83 -47
View File
@@ -41,6 +41,11 @@ from openpilot.system.version import get_build_metadata
from panda import Panda
from openpilot.starpilot.assets.theme_manager import HOLIDAY_THEME_PATH, THEME_COMPONENT_PARAMS
from openpilot.starpilot.common.accel_profile import (
CUSTOM_ACCEL_PROFILE_PARAM_KEYS,
build_custom_accel_profile_defaults,
normalize_acceleration_profile,
)
from openpilot.starpilot.common.maps_catalog import (
MAPS_CATALOG,
MAP_SCHEDULE_OPTIONS,
@@ -629,6 +634,8 @@ _TROUBLESHOOT_ADVANCED_LONGITUDINAL_KEYS = [
"AdvancedLongitudinalTune",
"EVTuning",
"TruckTuning",
"CustomAccelProfile",
*CUSTOM_ACCEL_PROFILE_PARAM_KEYS,
"LongitudinalActuatorDelay",
"StartAccel",
"VEgoStarting",
@@ -1663,6 +1670,7 @@ def _get_layout_type_overrides():
_cached_allowed_keys = None
_cached_param_types = None
_cached_default_values = None
_cached_static_default_values = None
def _get_param_type_info():
global _cached_allowed_keys, _cached_param_types
@@ -1699,15 +1707,18 @@ def _get_param_type_info():
_cached_param_types = types
return _cached_allowed_keys, _cached_param_types
def _get_default_param_values():
global _cached_default_values
if _cached_default_values is None:
_cached_default_values = {
def _get_static_default_param_values():
global _cached_static_default_values
if _cached_static_default_values is None:
_cached_static_default_values = {
key: default_val
for key, default_val, _, _ in starpilot_default_params
if key not in EXCLUDED_KEYS
}
default_values = dict(_cached_default_values)
return _cached_static_default_values
def _get_default_param_values():
default_values = dict(_get_static_default_param_values())
default_values.update(_get_runtime_default_param_overrides())
return default_values
@@ -1790,6 +1801,7 @@ def _has_runtime_default_value(key, raw_value):
def _get_runtime_default_param_overrides():
overrides = {}
static_defaults = _get_static_default_param_values()
for key, stock_key in _RUNTIME_DEFAULT_STOCK_KEYS.items():
stock_raw = _safe_params_get_live_raw(stock_key)
@@ -1798,40 +1810,60 @@ def _get_runtime_default_param_overrides():
overrides[stock_key] = stock_raw
cp_bytes = _safe_params_get_live_raw("CarParamsPersistent")
if not cp_bytes:
return overrides
if cp_bytes:
try:
with car.CarParams.from_bytes(cp_bytes) as cp:
overrides["EVTuning"] = default_ev_tuning_enabled(cp)
try:
with car.CarParams.from_bytes(cp_bytes) as cp:
overrides["EVTuning"] = default_ev_tuning_enabled(cp)
car_param_defaults = {
"SteerDelay": getattr(cp, "steerActuatorDelay", None),
"SteerRatio": getattr(cp, "steerRatio", None),
"LongitudinalActuatorDelay": getattr(cp, "longitudinalActuatorDelay", None),
"StartAccel": getattr(cp, "startAccel", None),
"StopAccel": getattr(cp, "stopAccel", None),
"StoppingDecelRate": getattr(cp, "stoppingDecelRate", None),
"VEgoStarting": getattr(cp, "vEgoStarting", None),
"VEgoStopping": getattr(cp, "vEgoStopping", None),
}
car_param_defaults = {
"SteerDelay": getattr(cp, "steerActuatorDelay", None),
"SteerRatio": getattr(cp, "steerRatio", None),
"LongitudinalActuatorDelay": getattr(cp, "longitudinalActuatorDelay", None),
"StartAccel": getattr(cp, "startAccel", None),
"StopAccel": getattr(cp, "stopAccel", None),
"StoppingDecelRate": getattr(cp, "stoppingDecelRate", None),
"VEgoStarting": getattr(cp, "vEgoStarting", None),
"VEgoStopping": getattr(cp, "vEgoStopping", None),
}
for key, value in car_param_defaults.items():
if key in overrides or value is None:
continue
if key not in _RUNTIME_DEFAULT_ZERO_OK_KEYS and float(value) == 0.0:
continue
overrides[key] = value
except Exception:
pass
for key, value in car_param_defaults.items():
if key in overrides or value is None:
continue
if key not in _RUNTIME_DEFAULT_ZERO_OK_KEYS and float(value) == 0.0:
continue
overrides[key] = value
except Exception:
pass
ev_tuning_raw = _safe_params_get_live_raw("EVTuning")
truck_tuning_raw = _safe_params_get_live_raw("TruckTuning")
acceleration_profile_raw = _safe_params_get_live_raw("AccelerationProfile")
ev_tuning = _coerce_param_value(
ev_tuning_raw if not _is_blank_param_raw(ev_tuning_raw) else overrides.get("EVTuning", static_defaults.get("EVTuning", "0")),
bool,
)
truck_tuning = _coerce_param_value(
truck_tuning_raw if not _is_blank_param_raw(truck_tuning_raw) else static_defaults.get("TruckTuning", "0"),
bool,
)
if truck_tuning:
ev_tuning = False
acceleration_profile = normalize_acceleration_profile(
acceleration_profile_raw if not _is_blank_param_raw(acceleration_profile_raw) else static_defaults.get("AccelerationProfile", "0")
)
overrides.update(build_custom_accel_profile_defaults(acceleration_profile, ev_tuning, truck_tuning))
return overrides
def _get_current_param_value(key, value_type):
safe_type = value_type or str
if safe_type == bool:
return params.get_bool(key)
return _coerce_param_value(params.get(key), safe_type)
def _get_current_param_value(key, value_type, defaults_lookup=None):
raw_value = _safe_params_get_live_raw(key)
if _is_blank_param_raw(raw_value):
if defaults_lookup is None:
defaults_lookup = _get_default_param_values()
raw_value = defaults_lookup.get(key)
return _coerce_param_value(raw_value, value_type)
def _serialize_param_write_value(raw_value):
if isinstance(raw_value, bool):
@@ -3108,6 +3140,22 @@ def setup(app):
if key == "AutomaticUpdates" and params.get_bool("IsOnroad"):
return jsonify({"error": "Cannot change Automatic Updates while driving."}), 403
if key in {"EVTuning", "TruckTuning"}:
enabled = str_val.strip() in ("1", "true", "True")
params.put_bool(key, enabled)
updated = {key: enabled}
if enabled:
other_key = "TruckTuning" if key == "EVTuning" else "EVTuning"
params.put_bool(other_key, False)
updated[other_key] = False
update_starpilot_toggles()
return jsonify({
"message": f"Parameter '{key}' updated successfully.",
"updated": updated,
}), 200
if key == "CarMake":
catalog = _get_fingerprint_catalog()
normalized_make = _normalize_fingerprint_make_key(str_val)
@@ -3225,25 +3273,13 @@ def setup(app):
def get_all_params():
_enforce_cancel_remap_lkas_lock()
allowed_keys, types = _get_param_type_info()
defaults_lookup = _get_default_param_values()
result = {}
for key in allowed_keys:
t = types.get(key, str)
try:
if t == bool:
result[key] = params.get_bool(key)
else:
raw = params.get(key)
raw_str = raw.decode("utf-8", errors="replace") if isinstance(raw, bytes) else str(raw or "")
if not raw_str:
result[key] = 0.0 if t == float else (0 if t == int else "")
elif t == float:
result[key] = float(raw_str)
elif t == int:
result[key] = int(float(raw_str))
else:
result[key] = raw_str
result[key] = _get_current_param_value(key, t, defaults_lookup)
except Exception:
result[key] = None
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.