Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 235c1cab79 | |||
| eb507d5ea8 | |||
| 159ca85be2 | |||
| 40d8eb8a4e | |||
| ebf77baf33 | |||
| 7c2fa00aec | |||
| 9bd0463c64 | |||
| e247249033 | |||
| ea48457d72 | |||
| 8a4e817f6b | |||
| a8767be7b1 | |||
| 0c249d253e | |||
| 9bb9d6ed2c | |||
| ceac092b67 | |||
| 2d23f740cc | |||
| 80c20399f1 | |||
| 4f65f90567 | |||
| 0a217baf18 | |||
| b81d6fb1eb | |||
| 944fc51f8a | |||
| 086570b29f | |||
| 8face05df0 | |||
| 7231aeb5ee |
@@ -1048,6 +1048,8 @@ struct ModelDataV2 {
|
|||||||
|
|
||||||
struct Action {
|
struct Action {
|
||||||
desiredCurvature @0 :Float32;
|
desiredCurvature @0 :Float32;
|
||||||
|
desiredAcceleration @1 :Float32;
|
||||||
|
shouldStop @2 :Bool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from openpilot.frogpilot.assets.download_functions import GITLAB_URL, download_f
|
|||||||
from openpilot.frogpilot.common.frogpilot_utilities import delete_file
|
from openpilot.frogpilot.common.frogpilot_utilities import delete_file
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import DEFAULT_CLASSIC_MODEL, DEFAULT_MODEL, DEFAULT_TINYGRAD_MODEL, MODELS_PATH, params, params_default, params_memory
|
from openpilot.frogpilot.common.frogpilot_variables import DEFAULT_CLASSIC_MODEL, DEFAULT_MODEL, DEFAULT_TINYGRAD_MODEL, MODELS_PATH, params, params_default, params_memory
|
||||||
|
|
||||||
VERSION = "v14"
|
VERSION = "v15"
|
||||||
|
|
||||||
CANCEL_DOWNLOAD_PARAM = "CancelModelDownload"
|
CANCEL_DOWNLOAD_PARAM = "CancelModelDownload"
|
||||||
DOWNLOAD_PROGRESS_PARAM = "ModelDownloadProgress"
|
DOWNLOAD_PROGRESS_PARAM = "ModelDownloadProgress"
|
||||||
|
|||||||
|
After Width: | Height: | Size: 371 KiB |
|
Before Width: | Height: | Size: 778 KiB After Width: | Height: | Size: 503 KiB |
@@ -19,7 +19,6 @@ from cereal import log
|
|||||||
from openpilot.common.realtime import DT_DMON, DT_HW
|
from openpilot.common.realtime import DT_DMON, DT_HW
|
||||||
from openpilot.selfdrive.car.toyota.carcontroller import LOCK_CMD
|
from openpilot.selfdrive.car.toyota.carcontroller import LOCK_CMD
|
||||||
from openpilot.system.hardware import HARDWARE
|
from openpilot.system.hardware import HARDWARE
|
||||||
from openpilot.system.manager.process_config import managed_processes
|
|
||||||
from panda import Panda
|
from panda import Panda
|
||||||
|
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import EARTH_RADIUS, KONIK_PATH, MAPD_PATH, MAPS_PATH, params, params_memory
|
from openpilot.frogpilot.common.frogpilot_variables import EARTH_RADIUS, KONIK_PATH, MAPD_PATH, MAPS_PATH, params, params_memory
|
||||||
@@ -39,6 +38,10 @@ locks = {
|
|||||||
"update_openpilot": threading.Lock(),
|
"update_openpilot": threading.Lock(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_managed_processes():
|
||||||
|
from openpilot.system.manager.process_config import managed_processes
|
||||||
|
return managed_processes
|
||||||
|
|
||||||
def run_thread_with_lock(name, target, args=(), report=True):
|
def run_thread_with_lock(name, target, args=(), report=True):
|
||||||
if not running_threads.get(name, threading.Thread()).is_alive():
|
if not running_threads.get(name, threading.Thread()).is_alive():
|
||||||
with locks[name]:
|
with locks[name]:
|
||||||
@@ -170,7 +173,7 @@ def restart_processes(sm):
|
|||||||
|
|
||||||
if not any(ps.ignitionLine or ps.ignitionCan for ps in sm["pandaStates"] if ps.pandaType != log.PandaState.PandaType.unknown):
|
if not any(ps.ignitionLine or ps.ignitionCan for ps in sm["pandaStates"] if ps.pandaType != log.PandaState.PandaType.unknown):
|
||||||
for name in ["mapd", "ui"]:
|
for name in ["mapd", "ui"]:
|
||||||
managed_processes[name].stop(block=False, retry=False)
|
get_managed_processes()[name].stop(block=False, retry=False)
|
||||||
|
|
||||||
def run_cmd(cmd, success_message, fail_message, report=True):
|
def run_cmd(cmd, success_message, fail_message, report=True):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ DEFAULT_MODEL = "national-public-radio"
|
|||||||
DEFAULT_MODEL_NAME = "National Public Radio 👀📡"
|
DEFAULT_MODEL_NAME = "National Public Radio 👀📡"
|
||||||
DEFAULT_MODEL_VERSION = "v6"
|
DEFAULT_MODEL_VERSION = "v6"
|
||||||
|
|
||||||
DEFAULT_TINYGRAD_MODEL = "filet-o-fish"
|
DEFAULT_TINYGRAD_MODEL = "tomb-raider"
|
||||||
DEFAULT_TINYGRAD_MODEL_NAME = "Filet-O-Fish 👀📡"
|
DEFAULT_TINYGRAD_MODEL_NAME = "Vikander 👀📡"
|
||||||
DEFAULT_TINYGRAD_MODEL_VERSION = "v8"
|
DEFAULT_TINYGRAD_MODEL_VERSION = "v8"
|
||||||
|
|
||||||
EXCLUDED_KEYS = {
|
EXCLUDED_KEYS = {
|
||||||
@@ -373,12 +373,16 @@ misc_tuning_levels: list[tuple[str, str | bytes, int]] = [
|
|||||||
("WheelControls", "", 2)
|
("WheelControls", "", 2)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def scale_threshold(v_ego):
|
||||||
|
return 0.0 if v_ego > 31.3 else np.interp(v_ego, [0, 17.9, 26.8, 35.8, 44.7], [0.63, 0.63, 0.65, 0.95, 0.95])
|
||||||
|
|
||||||
class FrogPilotVariables:
|
class FrogPilotVariables:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.frogpilot_toggles = get_frogpilot_toggles(block=False)
|
self.frogpilot_toggles = get_frogpilot_toggles(block=False)
|
||||||
self.tuning_levels = {key: lvl for key, _, lvl in frogpilot_default_params + misc_tuning_levels}
|
self.tuning_levels = {key: lvl for key, _, lvl in frogpilot_default_params + misc_tuning_levels}
|
||||||
|
|
||||||
self.short_branch = get_build_metadata().channel
|
self.short_branch = "FrogPilot-Staging"
|
||||||
self.development_branch = self.short_branch == "FrogPilot-Development"
|
self.development_branch = self.short_branch == "FrogPilot-Development"
|
||||||
self.release_branch = self.short_branch == "FrogPilot"
|
self.release_branch = self.short_branch == "FrogPilot"
|
||||||
self.staging_branch = self.short_branch == "FrogPilot-Staging"
|
self.staging_branch = self.short_branch == "FrogPilot-Staging"
|
||||||
@@ -388,7 +392,7 @@ class FrogPilotVariables:
|
|||||||
self.frogpilot_toggles.frogs_go_moo = Path("/persist/frogsgomoo.py").is_file()
|
self.frogpilot_toggles.frogs_go_moo = Path("/persist/frogsgomoo.py").is_file()
|
||||||
self.frogpilot_toggles.block_user = self.development_branch and not self.frogpilot_toggles.frogs_go_moo
|
self.frogpilot_toggles.block_user = self.development_branch and not self.frogpilot_toggles.frogs_go_moo
|
||||||
|
|
||||||
self.not_vetted = Path("/data/openpilot/not_vetted").is_file()
|
self.not_vetted = False
|
||||||
|
|
||||||
self.frogpilot_toggles.use_konik_server = params.get_bool("UseKonikServer")
|
self.frogpilot_toggles.use_konik_server = params.get_bool("UseKonikServer")
|
||||||
self.frogpilot_toggles.use_konik_server |= self.not_vetted
|
self.frogpilot_toggles.use_konik_server |= self.not_vetted
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
from openpilot.common.filter_simple import FirstOrderFilter
|
from openpilot.common.filter_simple import FirstOrderFilter
|
||||||
from openpilot.common.realtime import DT_MDL
|
from openpilot.common.realtime import DT_MDL
|
||||||
|
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT, CRUISING_SPEED, THRESHOLD, params_memory
|
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT, CRUISING_SPEED, THRESHOLD, params_memory, scale_threshold
|
||||||
|
|
||||||
class ConditionalExperimentalMode:
|
class ConditionalExperimentalMode:
|
||||||
def __init__(self, FrogPilotPlanner):
|
def __init__(self, FrogPilotPlanner):
|
||||||
@@ -53,7 +53,7 @@ class ConditionalExperimentalMode:
|
|||||||
self.status_value = 8
|
self.status_value = 8
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if frogpilot_toggles.conditional_lead and self.slow_lead_detected:
|
if frogpilot_toggles.conditional_lead and self.slow_lead_detected and v_ego <= 29.1:
|
||||||
self.status_value = 9 if self.frogpilot_planner.lead_one.vLead < 1 else 10
|
self.status_value = 9 if self.frogpilot_planner.lead_one.vLead < 1 else 10
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ class ConditionalExperimentalMode:
|
|||||||
|
|
||||||
def update_conditions(self, frogpilotCarState, v_ego, frogpilot_toggles):
|
def update_conditions(self, frogpilotCarState, v_ego, frogpilot_toggles):
|
||||||
self.curve_detection(v_ego, frogpilot_toggles)
|
self.curve_detection(v_ego, frogpilot_toggles)
|
||||||
self.slow_lead(frogpilot_toggles)
|
self.slow_lead(frogpilot_toggles, v_ego)
|
||||||
self.stop_sign_and_light(frogpilotCarState, v_ego, frogpilot_toggles)
|
self.stop_sign_and_light(frogpilotCarState, v_ego, frogpilot_toggles)
|
||||||
|
|
||||||
def curve_detection(self, v_ego, frogpilot_toggles):
|
def curve_detection(self, v_ego, frogpilot_toggles):
|
||||||
@@ -78,13 +78,14 @@ class ConditionalExperimentalMode:
|
|||||||
self.curvature_filter.update(self.frogpilot_planner.road_curvature_detected or curve_active)
|
self.curvature_filter.update(self.frogpilot_planner.road_curvature_detected or curve_active)
|
||||||
self.curve_detected = self.curvature_filter.x >= THRESHOLD and v_ego > CRUISING_SPEED
|
self.curve_detected = self.curvature_filter.x >= THRESHOLD and v_ego > CRUISING_SPEED
|
||||||
|
|
||||||
def slow_lead(self, frogpilot_toggles):
|
def slow_lead(self, frogpilot_toggles, v_ego):
|
||||||
|
v_lead = self.frogpilot_planner.lead_one.vLead
|
||||||
if self.frogpilot_planner.tracking_lead:
|
if self.frogpilot_planner.tracking_lead:
|
||||||
slower_lead = frogpilot_toggles.conditional_slower_lead and self.frogpilot_planner.frogpilot_following.slower_lead
|
slower_lead = frogpilot_toggles.conditional_slower_lead and self.frogpilot_planner.frogpilot_following.slower_lead
|
||||||
stopped_lead = frogpilot_toggles.conditional_stopped_lead and self.frogpilot_planner.lead_one.vLead < 1
|
stopped_lead = frogpilot_toggles.conditional_stopped_lead and v_lead < 1
|
||||||
|
lead_threshold = scale_threshold(v_ego)
|
||||||
self.slow_lead_filter.update(slower_lead or stopped_lead)
|
self.slow_lead_filter.update(slower_lead or stopped_lead)
|
||||||
self.slow_lead_detected = self.slow_lead_filter.x >= THRESHOLD
|
self.slow_lead_detected = self.slow_lead_filter.x >= lead_threshold
|
||||||
else:
|
else:
|
||||||
self.slow_lead_filter.x = 0
|
self.slow_lead_filter.x = 0
|
||||||
self.slow_lead_detected = False
|
self.slow_lead_detected = False
|
||||||
|
|||||||
@@ -1,6 +1,43 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
def cubic_interp(x, xp, fp):
|
||||||
|
"""Cubic interpolation using NumPy's native operations for speed."""
|
||||||
|
# Boundary conditions
|
||||||
|
if x <= xp[0]:
|
||||||
|
return fp[0]
|
||||||
|
elif x >= xp[-1]:
|
||||||
|
return fp[-1]
|
||||||
|
|
||||||
|
# Find interval
|
||||||
|
i = np.searchsorted(xp, x) - 1
|
||||||
|
i = max(0, min(i, len(xp)-2)) # clamp the index
|
||||||
|
|
||||||
|
# Normalized position
|
||||||
|
t = (x - xp[i]) / float(xp[i+1] - xp[i])
|
||||||
|
|
||||||
|
# Hermite cubic formula
|
||||||
|
return fp[i]*(1 - 3*t**2 + 2*t**3) + fp[i+1]*(3*t**2 - 2*t**3)
|
||||||
|
|
||||||
|
def akima_interp(x, xp, fp):
|
||||||
|
"""Akima-inspired interpolation with reduced overshoot characteristics."""
|
||||||
|
if x <= xp[0]:
|
||||||
|
return fp[0]
|
||||||
|
elif x >= xp[-1]:
|
||||||
|
return fp[-1]
|
||||||
|
|
||||||
|
i = np.searchsorted(xp, x) - 1
|
||||||
|
i = max(0, min(i, len(xp)-2)) # clamp the index
|
||||||
|
|
||||||
|
t = (x - xp[i]) / float(xp[i+1] - xp[i])
|
||||||
|
|
||||||
|
# Quintic polynomial to reduce overshoot
|
||||||
|
t2 = t*t
|
||||||
|
t4 = t2*t2
|
||||||
|
t3 = t2*t
|
||||||
|
return (fp[i]*(1 - 10*t3 + 15*t4 - 6*t3*t2)
|
||||||
|
+ fp[i+1]*(10*t3 - 15*t4 + 6*t3*t2))
|
||||||
|
|
||||||
from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, get_max_accel
|
from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, get_max_accel
|
||||||
|
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT
|
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT
|
||||||
@@ -11,26 +48,26 @@ A_CRUISE_MIN_SPORT = A_CRUISE_MIN * 2
|
|||||||
# MPH = [0.0, 11, 22, 34, 45, 56, 89]
|
# 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_BP_CUSTOM = [0.0, 5., 10., 15., 20., 25., 40.]
|
||||||
A_CRUISE_MAX_VALS_ECO = [2.0, 1.5, 1.0, 0.8, 0.6, 0.4, 0.2]
|
A_CRUISE_MAX_VALS_ECO = [2.0, 1.5, 1.0, 0.8, 0.6, 0.4, 0.2]
|
||||||
A_CRUISE_MAX_VALS_SPORT = [3.0, 2.5, 2.0, 1.5, 1.0, 0.8, 0.6]
|
A_CRUISE_MAX_VALS_SPORT = [1.5, 1.5, 1.25, 1.5, 1.5, 1.5, 2.0]
|
||||||
A_CRUISE_MAX_VALS_SPORT_PLUS = [4.0, 3.5, 3.0, 2.5, 2.0, 1.5, 1.0]
|
A_CRUISE_MAX_VALS_SPORT_PLUS = [2.5, 2.5, 3.0, 2.5, 2.5, 2.5, 2.5]
|
||||||
|
|
||||||
def get_max_accel_eco(v_ego):
|
def get_max_accel_eco(v_ego):
|
||||||
return float(np.interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_ECO))
|
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_ECO))
|
||||||
|
|
||||||
def get_max_accel_sport(v_ego):
|
def get_max_accel_sport(v_ego):
|
||||||
return float(np.interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_SPORT))
|
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_SPORT))
|
||||||
|
|
||||||
def get_max_accel_sport_plus(v_ego):
|
def get_max_accel_sport_plus(v_ego):
|
||||||
return float(np.interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_SPORT_PLUS))
|
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_SPORT_PLUS))
|
||||||
|
|
||||||
def get_max_accel_low_speeds(max_accel, v_cruise):
|
def get_max_accel_low_speeds(max_accel, v_cruise):
|
||||||
return float(np.interp(v_cruise, [0., CITY_SPEED_LIMIT / 2, CITY_SPEED_LIMIT], [max_accel / 4, max_accel / 2, max_accel]))
|
return float(akima_interp(v_cruise, [0., CITY_SPEED_LIMIT / 2, CITY_SPEED_LIMIT], [max_accel / 4, max_accel / 2, max_accel]))
|
||||||
|
|
||||||
def get_max_accel_ramp_off(max_accel, v_cruise, v_ego):
|
def get_max_accel_ramp_off(max_accel, v_cruise, v_ego):
|
||||||
return float(np.interp(v_cruise - v_ego, [0., 1., 5., 10.], [0., 0.5, 1.0, max_accel]))
|
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):
|
def get_max_allowed_accel(v_ego):
|
||||||
return float(np.interp(v_ego, [0., 5., 20.], [4.0, 4.0, 2.0])) # ISO 15622:2018
|
return float(akima_interp(v_ego, [0., 5., 20.], [4.0, 4.0, 2.0])) # ISO 15622:2018
|
||||||
|
|
||||||
class FrogPilotAcceleration:
|
class FrogPilotAcceleration:
|
||||||
def __init__(self, FrogPilotPlanner):
|
def __init__(self, FrogPilotPlanner):
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 402 KiB |
@@ -40,7 +40,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<title>FrogPilot: {% block title %}{% endblock %}</title>
|
<title>StarPilot: {% block title %}{% endblock %}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-fixed-top navbar-expand-sm navbar-dark bg-dark">
|
<nav class="navbar navbar-fixed-top navbar-expand-sm navbar-dark bg-dark">
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ def fill_lane_line_meta(builder, lane_lines, lane_line_probs):
|
|||||||
builder.rightProb = lane_line_probs[2]
|
builder.rightProb = lane_line_probs[2]
|
||||||
|
|
||||||
def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._DynamicStructBuilder,
|
def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._DynamicStructBuilder,
|
||||||
net_output_data: dict[str, np.ndarray], v_ego: float, delay: float,
|
net_output_data: dict[str, np.ndarray], action: log.ModelDataV2.Action,
|
||||||
publish_state: PublishState, vipc_frame_id: int, vipc_frame_id_extra: int,
|
publish_state: PublishState, vipc_frame_id: int, vipc_frame_id_extra: int,
|
||||||
frame_id: int, frame_drop: float, timestamp_eof: int, model_execution_time: float,
|
frame_id: int, frame_drop: float, timestamp_eof: int, model_execution_time: float,
|
||||||
valid: bool) -> None:
|
valid: bool) -> None:
|
||||||
@@ -71,7 +71,8 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
|||||||
driving_model_data.frameIdExtra = vipc_frame_id_extra
|
driving_model_data.frameIdExtra = vipc_frame_id_extra
|
||||||
driving_model_data.frameDropPerc = frame_drop_perc
|
driving_model_data.frameDropPerc = frame_drop_perc
|
||||||
driving_model_data.modelExecutionTime = model_execution_time
|
driving_model_data.modelExecutionTime = model_execution_time
|
||||||
driving_model_data.action.desiredCurvature = float(net_output_data['desired_curvature'][0,0])
|
|
||||||
|
driving_model_data.action = action
|
||||||
|
|
||||||
modelV2 = extended_msg.modelV2
|
modelV2 = extended_msg.modelV2
|
||||||
modelV2.frameId = vipc_frame_id
|
modelV2.frameId = vipc_frame_id
|
||||||
@@ -89,17 +90,17 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
|||||||
fill_xyzt(modelV2.orientationRate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
|
fill_xyzt(modelV2.orientationRate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
|
||||||
|
|
||||||
# temporal pose
|
# temporal pose
|
||||||
temporal_pose = modelV2.temporalPose
|
#temporal_pose = modelV2.temporalPose
|
||||||
temporal_pose.trans = net_output_data['sim_pose'][0,:ModelConstants.POSE_WIDTH//2].tolist()
|
#temporal_pose.trans = net_output_data['sim_pose'][0,:ModelConstants.POSE_WIDTH//2].tolist()
|
||||||
temporal_pose.transStd = net_output_data['sim_pose_stds'][0,:ModelConstants.POSE_WIDTH//2].tolist()
|
#temporal_pose.transStd = net_output_data['sim_pose_stds'][0,:ModelConstants.POSE_WIDTH//2].tolist()
|
||||||
temporal_pose.rot = net_output_data['sim_pose'][0,ModelConstants.POSE_WIDTH//2:].tolist()
|
#temporal_pose.rot = net_output_data['sim_pose'][0,ModelConstants.POSE_WIDTH//2:].tolist()
|
||||||
temporal_pose.rotStd = net_output_data['sim_pose_stds'][0,ModelConstants.POSE_WIDTH//2:].tolist()
|
#temporal_pose.rotStd = net_output_data['sim_pose_stds'][0,ModelConstants.POSE_WIDTH//2:].tolist()
|
||||||
|
|
||||||
# poly path
|
# poly path
|
||||||
fill_xyz_poly(driving_model_data.path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
|
fill_xyz_poly(driving_model_data.path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
|
||||||
|
|
||||||
# lateral planning
|
# action
|
||||||
modelV2.action.desiredCurvature = float(net_output_data['desired_curvature'][0,0])
|
modelV2.action = action
|
||||||
|
|
||||||
# times at X_IDXS of edges and lines aren't used
|
# times at X_IDXS of edges and lines aren't used
|
||||||
LINE_T_IDXS: list[float] = []
|
LINE_T_IDXS: list[float] = []
|
||||||
|
|||||||
@@ -88,6 +88,12 @@ class Parser:
|
|||||||
self.parse_mdn('pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
self.parse_mdn('pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
||||||
self.parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(ModelConstants.WIDE_FROM_DEVICE_WIDTH,))
|
self.parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(ModelConstants.WIDE_FROM_DEVICE_WIDTH,))
|
||||||
self.parse_mdn('road_transform', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
self.parse_mdn('road_transform', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
||||||
|
self.parse_mdn('lane_lines', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_LANE_LINES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
||||||
|
self.parse_mdn('road_edges', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_ROAD_EDGES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
||||||
|
self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION,
|
||||||
|
out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH))
|
||||||
|
for k in ['lead_prob', 'lane_lines_prob']:
|
||||||
|
self.parse_binary_crossentropy(k, outs)
|
||||||
self.parse_categorical_crossentropy('desire_pred', outs, out_shape=(ModelConstants.DESIRE_PRED_LEN,ModelConstants.DESIRE_PRED_WIDTH))
|
self.parse_categorical_crossentropy('desire_pred', outs, out_shape=(ModelConstants.DESIRE_PRED_LEN,ModelConstants.DESIRE_PRED_WIDTH))
|
||||||
self.parse_binary_crossentropy('meta', outs)
|
self.parse_binary_crossentropy('meta', outs)
|
||||||
return outs
|
return outs
|
||||||
@@ -95,17 +101,10 @@ class Parser:
|
|||||||
def parse_policy_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]:
|
def parse_policy_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]:
|
||||||
self.parse_mdn('plan', outs, in_N=ModelConstants.PLAN_MHP_N, out_N=ModelConstants.PLAN_MHP_SELECTION,
|
self.parse_mdn('plan', outs, in_N=ModelConstants.PLAN_MHP_N, out_N=ModelConstants.PLAN_MHP_SELECTION,
|
||||||
out_shape=(ModelConstants.IDX_N,ModelConstants.PLAN_WIDTH))
|
out_shape=(ModelConstants.IDX_N,ModelConstants.PLAN_WIDTH))
|
||||||
self.parse_mdn('lane_lines', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_LANE_LINES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
|
||||||
self.parse_mdn('road_edges', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_ROAD_EDGES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH))
|
|
||||||
self.parse_mdn('sim_pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
|
|
||||||
self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION,
|
|
||||||
out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH))
|
|
||||||
if 'lat_planner_solution' in outs:
|
if 'lat_planner_solution' in outs:
|
||||||
self.parse_mdn('lat_planner_solution', outs, in_N=0, out_N=0, out_shape=(ModelConstants.IDX_N,ModelConstants.LAT_PLANNER_SOLUTION_WIDTH))
|
self.parse_mdn('lat_planner_solution', outs, in_N=0, out_N=0, out_shape=(ModelConstants.IDX_N,ModelConstants.LAT_PLANNER_SOLUTION_WIDTH))
|
||||||
if 'desired_curvature' in outs:
|
if 'desired_curvature' in outs:
|
||||||
self.parse_mdn('desired_curvature', outs, in_N=0, out_N=0, out_shape=(ModelConstants.DESIRED_CURV_WIDTH,))
|
self.parse_mdn('desired_curvature', outs, in_N=0, out_N=0, out_shape=(ModelConstants.DESIRED_CURV_WIDTH,))
|
||||||
for k in ['lead_prob', 'lane_lines_prob']:
|
|
||||||
self.parse_binary_crossentropy(k, outs)
|
|
||||||
self.parse_categorical_crossentropy('desire_state', outs, out_shape=(ModelConstants.DESIRE_PRED_WIDTH,))
|
self.parse_categorical_crossentropy('desire_state', outs, out_shape=(ModelConstants.DESIRE_PRED_WIDTH,))
|
||||||
return outs
|
return outs
|
||||||
|
|
||||||
|
|||||||
@@ -20,19 +20,21 @@ from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
|
|||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.common.filter_simple import FirstOrderFilter
|
from openpilot.common.filter_simple import FirstOrderFilter
|
||||||
from openpilot.common.realtime import config_realtime_process
|
from openpilot.common.realtime import config_realtime_process, DT_MDL
|
||||||
from openpilot.common.transformations.camera import DEVICE_CAMERAS
|
from openpilot.common.transformations.camera import DEVICE_CAMERAS
|
||||||
from openpilot.common.transformations.model import get_warp_matrix
|
from openpilot.common.transformations.model import get_warp_matrix
|
||||||
from openpilot.system import sentry
|
from openpilot.system import sentry
|
||||||
from openpilot.selfdrive.car.car_helpers import get_demo_car_params
|
from openpilot.selfdrive.car.car_helpers import get_demo_car_params
|
||||||
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
|
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
|
||||||
|
from openpilot.selfdrive.controls.lib.drive_helpers import get_accel_from_plan_tomb_raider, smooth_value, get_curvature_from_plan
|
||||||
from openpilot.frogpilot.tinygrad_modeld.parse_model_outputs import Parser
|
from openpilot.frogpilot.tinygrad_modeld.parse_model_outputs import Parser
|
||||||
from openpilot.frogpilot.tinygrad_modeld.fill_model_msg import fill_model_msg, fill_pose_msg, PublishState
|
from openpilot.frogpilot.tinygrad_modeld.fill_model_msg import fill_model_msg, fill_pose_msg, PublishState
|
||||||
from openpilot.frogpilot.tinygrad_modeld.constants import ModelConstants
|
from openpilot.frogpilot.tinygrad_modeld.constants import ModelConstants, Plan
|
||||||
from openpilot.frogpilot.tinygrad_modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext
|
from openpilot.frogpilot.tinygrad_modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext
|
||||||
|
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import get_frogpilot_toggles
|
from openpilot.frogpilot.common.frogpilot_variables import get_frogpilot_toggles
|
||||||
|
|
||||||
|
|
||||||
PROCESS_NAME = "frogpilot.tinygrad_modeld.tinygrad_modeld"
|
PROCESS_NAME = "frogpilot.tinygrad_modeld.tinygrad_modeld"
|
||||||
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||||
|
|
||||||
@@ -41,6 +43,30 @@ POLICY_PKL_PATH = Path(__file__).parent / 'models/driving_policy_tinygrad.pkl'
|
|||||||
VISION_METADATA_PATH = Path(__file__).parent / 'models/driving_vision_metadata.pkl'
|
VISION_METADATA_PATH = Path(__file__).parent / 'models/driving_vision_metadata.pkl'
|
||||||
POLICY_METADATA_PATH = Path(__file__).parent / 'models/driving_policy_metadata.pkl'
|
POLICY_METADATA_PATH = Path(__file__).parent / 'models/driving_policy_metadata.pkl'
|
||||||
|
|
||||||
|
LAT_SMOOTH_SECONDS = 0.2
|
||||||
|
LONG_SMOOTH_SECONDS = 0.2
|
||||||
|
MIN_LAT_CONTROL_SPEED = 0.3
|
||||||
|
|
||||||
|
|
||||||
|
def get_action_from_model(model_output: dict[str, np.ndarray], prev_action: log.ModelDataV2.Action,
|
||||||
|
lat_action_t: float, long_action_t: float, v_ego: float) -> log.ModelDataV2.Action:
|
||||||
|
plan = model_output['plan'][0]
|
||||||
|
desired_accel, should_stop = get_accel_from_plan_tomb_raider(plan[:,Plan.VELOCITY][:,0],
|
||||||
|
plan[:,Plan.ACCELERATION][:,0],
|
||||||
|
ModelConstants.T_IDXS,
|
||||||
|
action_t=long_action_t)
|
||||||
|
desired_accel = smooth_value(desired_accel, prev_action.desiredAcceleration, LONG_SMOOTH_SECONDS)
|
||||||
|
|
||||||
|
desired_curvature = model_output['desired_curvature'][0, 0]
|
||||||
|
if v_ego > MIN_LAT_CONTROL_SPEED:
|
||||||
|
desired_curvature = smooth_value(desired_curvature, prev_action.desiredCurvature, LAT_SMOOTH_SECONDS)
|
||||||
|
else:
|
||||||
|
desired_curvature = prev_action.desiredCurvature
|
||||||
|
|
||||||
|
return log.ModelDataV2.Action(desiredCurvature=float(desired_curvature),
|
||||||
|
desiredAcceleration=float(desired_accel),
|
||||||
|
shouldStop=bool(should_stop))
|
||||||
|
|
||||||
class FrameMeta:
|
class FrameMeta:
|
||||||
frame_id: int = 0
|
frame_id: int = 0
|
||||||
timestamp_sof: int = 0
|
timestamp_sof: int = 0
|
||||||
@@ -148,7 +174,7 @@ class ModelState:
|
|||||||
# TODO model only uses last value now
|
# TODO model only uses last value now
|
||||||
self.full_prev_desired_curv[0,:-1] = self.full_prev_desired_curv[0,1:]
|
self.full_prev_desired_curv[0,:-1] = self.full_prev_desired_curv[0,1:]
|
||||||
self.full_prev_desired_curv[0,-1,:] = policy_outputs_dict['desired_curvature'][0, :]
|
self.full_prev_desired_curv[0,-1,:] = policy_outputs_dict['desired_curvature'][0, :]
|
||||||
self.numpy_inputs['prev_desired_curv'][:] = self.full_prev_desired_curv[0, self.temporal_idxs]
|
self.numpy_inputs['prev_desired_curv'][:] = 0*self.full_prev_desired_curv[0, self.temporal_idxs]
|
||||||
|
|
||||||
combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict}
|
combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict}
|
||||||
if SEND_RAW_PRED:
|
if SEND_RAW_PRED:
|
||||||
@@ -223,7 +249,10 @@ def main(demo=False):
|
|||||||
cloudlog.info("tinygrad_modeld got CarParams: %s", CP.carName)
|
cloudlog.info("tinygrad_modeld got CarParams: %s", CP.carName)
|
||||||
|
|
||||||
# TODO this needs more thought, use .2s extra for now to estimate other delays
|
# TODO this needs more thought, use .2s extra for now to estimate other delays
|
||||||
steer_delay = CP.steerActuatorDelay + .2
|
# TODO Move smooth seconds to action function
|
||||||
|
lat_delay = CP.steerActuatorDelay + .2 + LAT_SMOOTH_SECONDS
|
||||||
|
long_delay = CP.longitudinalActuatorDelay + LONG_SMOOTH_SECONDS
|
||||||
|
prev_action = log.ModelDataV2.Action()
|
||||||
|
|
||||||
DH = DesireHelper()
|
DH = DesireHelper()
|
||||||
|
|
||||||
@@ -268,7 +297,7 @@ def main(demo=False):
|
|||||||
is_rhd = sm["driverMonitoringState"].isRHD
|
is_rhd = sm["driverMonitoringState"].isRHD
|
||||||
frame_id = sm["roadCameraState"].frameId
|
frame_id = sm["roadCameraState"].frameId
|
||||||
v_ego = max(sm["carState"].vEgo, 0.)
|
v_ego = max(sm["carState"].vEgo, 0.)
|
||||||
lateral_control_params = np.array([v_ego, steer_delay], dtype=np.float32)
|
lateral_control_params = np.array([v_ego, lat_delay], dtype=np.float32)
|
||||||
if sm.updated["liveCalibration"] and sm.seen['roadCameraState'] and sm.seen['deviceState']:
|
if sm.updated["liveCalibration"] and sm.seen['roadCameraState'] and sm.seen['deviceState']:
|
||||||
device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32)
|
device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32)
|
||||||
dc = DEVICE_CAMERAS[(str(sm['deviceState'].deviceType), str(sm['roadCameraState'].sensor))]
|
dc = DEVICE_CAMERAS[(str(sm['deviceState'].deviceType), str(sm['roadCameraState'].sensor))]
|
||||||
@@ -311,7 +340,10 @@ def main(demo=False):
|
|||||||
modelv2_send = messaging.new_message('modelV2')
|
modelv2_send = messaging.new_message('modelV2')
|
||||||
drivingdata_send = messaging.new_message('drivingModelData')
|
drivingdata_send = messaging.new_message('drivingModelData')
|
||||||
posenet_send = messaging.new_message('cameraOdometry')
|
posenet_send = messaging.new_message('cameraOdometry')
|
||||||
fill_model_msg(drivingdata_send, modelv2_send, model_output, v_ego, steer_delay,
|
|
||||||
|
action = get_action_from_model(model_output, prev_action, lat_delay + DT_MDL, long_delay + DT_MDL, v_ego)
|
||||||
|
prev_action = action
|
||||||
|
fill_model_msg(drivingdata_send, modelv2_send, model_output, action,
|
||||||
publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id,
|
publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id,
|
||||||
frame_drop_ratio, meta_main.timestamp_eof, model_execution_time, live_calib_seen)
|
frame_drop_ratio, meta_main.timestamp_eof, model_execution_time, live_calib_seen)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
|
||||||
if [ -z "$BASEDIR" ]; then
|
if [ -z "$BASEDIR" ]; then
|
||||||
BASEDIR="/data/openpilot"
|
BASEDIR="/data/openpilot"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
|
|||||||
export VECLIB_MAXIMUM_THREADS=1
|
export VECLIB_MAXIMUM_THREADS=1
|
||||||
|
|
||||||
if [ -z "$AGNOS_VERSION" ]; then
|
if [ -z "$AGNOS_VERSION" ]; then
|
||||||
export AGNOS_VERSION="10.1"
|
export AGNOS_VERSION="10.1.1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export STAGING_ROOT="/data/safe_staging"
|
export STAGING_ROOT="/data/safe_staging"
|
||||||
|
|||||||
@@ -82,6 +82,12 @@ VAL_TABLE_ HandsOffSWDetectionMode 2 "Failed" 1 "Enabled" 0 "Disabled" ;
|
|||||||
|
|
||||||
BO_ 189 EBCMRegenPaddle: 7 K17_EBCM
|
BO_ 189 EBCMRegenPaddle: 7 K17_EBCM
|
||||||
SG_ RegenPaddle : 7|4@0+ (1,0) [0|0] "" NEO
|
SG_ RegenPaddle : 7|4@0+ (1,0) [0|0] "" NEO
|
||||||
|
SG_ Byte1 : 8|8@1+ (1,0) [0|255] "" NEO
|
||||||
|
SG_ Byte2 : 16|8@1+ (1,0) [0|255] "" NEO
|
||||||
|
SG_ Byte3 : 24|8@1+ (1,0) [0|255] "" NEO
|
||||||
|
SG_ Byte4 : 32|8@1+ (1,0) [0|255] "" NEO
|
||||||
|
SG_ Byte5 : 40|8@1+ (1,0) [0|255] "" NEO
|
||||||
|
SG_ Byte6 : 48|8@1+ (1,0) [0|255] "" NEO
|
||||||
|
|
||||||
BO_ 190 ECMAcceleratorPos: 6 K20_ECM
|
BO_ 190 ECMAcceleratorPos: 6 K20_ECM
|
||||||
SG_ BrakePedalPos : 15|8@0+ (1,0) [0|0] "sticky" NEO
|
SG_ BrakePedalPos : 15|8@0+ (1,0) [0|0] "sticky" NEO
|
||||||
@@ -192,10 +198,15 @@ BO_ 500 SportMode: 6 XXX
|
|||||||
SG_ SportMode : 15|1@0+ (1,0) [0|1] "" XXX
|
SG_ SportMode : 15|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
BO_ 501 ECMPRDNL2: 8 K20_ECM
|
BO_ 501 ECMPRDNL2: 8 K20_ECM
|
||||||
SG_ TransmissionState : 48|4@1+ (1,0) [0|7] "" NEO
|
SG_ Byte0 : 0|8@1+ (1,0) [0|255] "" NEO
|
||||||
|
SG_ Byte1 : 8|8@1+ (1,0) [0|255] "" NEO
|
||||||
|
SG_ Byte2 : 16|8@1+ (1,0) [0|255] "" NEO
|
||||||
SG_ PRNDL2 : 27|4@0+ (1,0) [0|255] "" NEO
|
SG_ PRNDL2 : 27|4@0+ (1,0) [0|255] "" NEO
|
||||||
|
SG_ Byte4 : 32|8@1+ (1,0) [0|255] "" NEO
|
||||||
SG_ ManualMode : 41|1@0+ (1,0) [0|1] "" NEO
|
SG_ ManualMode : 41|1@0+ (1,0) [0|1] "" NEO
|
||||||
|
SG_ TransmissionState : 48|4@1+ (1,0) [0|7] "" NEO
|
||||||
|
SG_ Byte7 : 56|8@1+ (1,0) [0|255] "" NEO
|
||||||
|
|
||||||
BO_ 532 BRAKE_RELATED: 6 XXX
|
BO_ 532 BRAKE_RELATED: 6 XXX
|
||||||
SG_ UserBrakePressure : 0|9@0+ (1,0) [0|511] "" XXX
|
SG_ UserBrakePressure : 0|9@0+ (1,0) [0|511] "" XXX
|
||||||
|
|
||||||
@@ -370,6 +381,6 @@ VAL_ 715 GasRegenCmdActive 1 "Active" 0 "Inactive" ;
|
|||||||
VAL_ 320 Intellibeam 1 "Active" 0 "Inactive" ;
|
VAL_ 320 Intellibeam 1 "Active" 0 "Inactive" ;
|
||||||
VAL_ 320 HighBeamsActive 1 "Active" 0 "Inactive" ;
|
VAL_ 320 HighBeamsActive 1 "Active" 0 "Inactive" ;
|
||||||
VAL_ 320 HighBeamsTemporary 1 "Active" 0 "Inactive" ;
|
VAL_ 320 HighBeamsTemporary 1 "Active" 0 "Inactive" ;
|
||||||
VAL_ 501 PRNDL2 6 "L" 4 "D" 3 "N" 2 "R" 1 "P" 0 "Shifting";
|
VAL_ 501 PRNDL2 7 "L2" 6 "L" 5 "L3" 4 "D" 3 "N" 2 "R" 1 "P" 0 "Shifting";
|
||||||
VAL_ 501 TransmissionState 11 "Shifting" 10 "Reverse" 9 "Forward" 8 "Disengaged";
|
VAL_ 501 TransmissionState 11 "Shifting" 10 "Reverse" 9 "Forward" 8 "Disengaged";
|
||||||
VAL_ 501 ManualMode 1 "Active" 0 "Inactive"
|
VAL_ 501 ManualMode 1 "Active" 0 "Inactive"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 418 KiB |
@@ -209,7 +209,8 @@ def get_car(logcan, sendcan, experimental_long_allowed, params, num_pandas=1, fr
|
|||||||
CP.fingerprintSource = source
|
CP.fingerprintSource = source
|
||||||
CP.fuzzyFingerprint = not exact_match
|
CP.fuzzyFingerprint = not exact_match
|
||||||
|
|
||||||
return get_car_interface(CP, FPCP), CP, FPCP
|
interface_instance = get_car_interface(CP, None)
|
||||||
|
return interface_instance, CP, FPCP
|
||||||
|
|
||||||
def write_car_param(platform=MOCK.MOCK):
|
def write_car_param(platform=MOCK.MOCK):
|
||||||
params = Params()
|
params = Params()
|
||||||
|
|||||||
@@ -57,17 +57,16 @@ class CarController(CarControllerBase):
|
|||||||
self.accel_g = 0.0
|
self.accel_g = 0.0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def calc_pedal_command(accel: float, long_active: bool) -> float:
|
def calc_pedal_command(accel: float, long_active: bool, car_velocity) -> float:
|
||||||
if not long_active: return 0.
|
if not long_active: return 0.
|
||||||
|
|
||||||
zero = 0.15625 # 40/256
|
if accel < -0.5:
|
||||||
if accel > 0.:
|
pedal_gas = 0
|
||||||
# Scales the accel from 0-1 to 0.156-1
|
|
||||||
pedal_gas = clip(((1 - zero) * accel + zero), 0., 1.)
|
|
||||||
else:
|
else:
|
||||||
# if accel is negative, -0.1 -> 0.015625
|
|
||||||
pedal_gas = clip(zero + accel, 0., zero) # Make brake the same size as gas, but clip to regen
|
|
||||||
|
|
||||||
|
pedaloffset = interp(car_velocity, [0., 3, 6, 30], [0.10, 0.175, 0.240, 0.240])
|
||||||
|
pedal_gas = clip((pedaloffset + accel * 0.6), 0.0, 1.0)
|
||||||
|
|
||||||
return pedal_gas
|
return pedal_gas
|
||||||
|
|
||||||
|
|
||||||
@@ -160,7 +159,7 @@ class CarController(CarControllerBase):
|
|||||||
self.apply_gas = self.params.INACTIVE_REGEN
|
self.apply_gas = self.params.INACTIVE_REGEN
|
||||||
if self.CP.carFingerprint in CC_ONLY_CAR:
|
if self.CP.carFingerprint in CC_ONLY_CAR:
|
||||||
# gas interceptor only used for full long control on cars without ACC
|
# gas interceptor only used for full long control on cars without ACC
|
||||||
interceptor_gas_cmd = self.calc_pedal_command(actuators.accel, CC.longActive)
|
interceptor_gas_cmd = self.calc_pedal_command(actuators.accel, CC.longActive, CS.out.vEgo)
|
||||||
|
|
||||||
if self.CP.enableGasInterceptor and self.apply_gas > self.params.INACTIVE_REGEN and CS.out.cruiseState.standstill:
|
if self.CP.enableGasInterceptor and self.apply_gas > self.params.INACTIVE_REGEN and CS.out.cruiseState.standstill:
|
||||||
# "Tap" the accelerator pedal to re-engage ACC
|
# "Tap" the accelerator pedal to re-engage ACC
|
||||||
|
|||||||
@@ -92,11 +92,16 @@ class CarState(CarStateBase):
|
|||||||
# Regen braking is braking
|
# Regen braking is braking
|
||||||
if self.CP.transmissionType == TransmissionType.direct:
|
if self.CP.transmissionType == TransmissionType.direct:
|
||||||
ret.regenBraking = pt_cp.vl["EBCMRegenPaddle"]["RegenPaddle"] != 0
|
ret.regenBraking = pt_cp.vl["EBCMRegenPaddle"]["RegenPaddle"] != 0
|
||||||
self.single_pedal_mode = ret.gearShifter == GearShifter.low or pt_cp.vl["EVDriveMode"]["SinglePedalModeActive"] == 1 or (ret.regenBraking and GearShifter.manumatic)
|
self.single_pedal_mode = (
|
||||||
|
ret.gearShifter == GearShifter.low
|
||||||
|
or pt_cp.vl["EVDriveMode"]["SinglePedalModeActive"] == 1
|
||||||
|
or pt_cp.vl["ECMPRDNL2"]["TransmissionState"] == 21
|
||||||
|
or (ret.regenBraking and GearShifter.manumatic)
|
||||||
|
)
|
||||||
|
|
||||||
if self.CP.enableGasInterceptor:
|
if self.CP.enableGasInterceptor:
|
||||||
ret.gas = (pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2.
|
ret.gas = (pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2.
|
||||||
threshold = 10 if self.CP.carFingerprint in CAMERA_ACC_CAR else 4 # Panda 515 threshold = 10.88. Set lower to avoid panda blocking messages and GasInterceptor faulting.
|
threshold = 12 if self.CP.carFingerprint in CAMERA_ACC_CAR else 4 # Panda 515 threshold = 10.88. Set lower to avoid panda blocking messages and GasInterceptor faulting.
|
||||||
ret.gasPressed = ret.gas > threshold
|
ret.gasPressed = ret.gas > threshold
|
||||||
else:
|
else:
|
||||||
ret.gas = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254.
|
ret.gas = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254.
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ CAM_MSG = 0x320 # AEBCmd
|
|||||||
ACCELERATOR_POS_MSG = 0xbe
|
ACCELERATOR_POS_MSG = 0xbe
|
||||||
|
|
||||||
NON_LINEAR_TORQUE_PARAMS = {
|
NON_LINEAR_TORQUE_PARAMS = {
|
||||||
CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178],
|
CAR.CHEVROLET_BOLT_EUV: [1.8, 1.1, 0.290, -0.045],
|
||||||
CAR.CHEVROLET_BOLT_CC: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178],
|
CAR.CHEVROLET_BOLT_CC: [1.8, 1.1, 0.290, -0.045],
|
||||||
CAR.GMC_ACADIA: [4.78003305, 1.0, 0.3122, 0.05591772],
|
CAR.GMC_ACADIA: [4.78003305, 1.0, 0.3122, 0.05591772],
|
||||||
CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122]
|
CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122]
|
||||||
}
|
}
|
||||||
@@ -74,8 +74,8 @@ class CarInterface(CarInterfaceBase):
|
|||||||
# ToDo: To generalize to other GMs, explore tanh function as the nonlinear
|
# ToDo: To generalize to other GMs, explore tanh function as the nonlinear
|
||||||
non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint)
|
non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint)
|
||||||
assert non_linear_torque_params, "The params are not defined"
|
assert non_linear_torque_params, "The params are not defined"
|
||||||
a, b, c, _ = non_linear_torque_params
|
a, b, c, d = non_linear_torque_params
|
||||||
steer_torque = (sig(latcontrol_inputs.lateral_acceleration * a) * b) + (latcontrol_inputs.lateral_acceleration * c)
|
steer_torque = (sig(latcontrol_inputs.lateral_acceleration * a) * b) + (latcontrol_inputs.lateral_acceleration * c) + d
|
||||||
return float(steer_torque) + friction
|
return float(steer_torque) + friction
|
||||||
|
|
||||||
def torque_from_lateral_accel_neural(self, latcontrol_inputs: LatControlInputs, torque_params: car.CarParams.LateralTorqueTuning, lateral_accel_error: float,
|
def torque_from_lateral_accel_neural(self, latcontrol_inputs: LatControlInputs, torque_params: car.CarParams.LateralTorqueTuning, lateral_accel_error: float,
|
||||||
@@ -87,13 +87,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
return float(self.neural_ff_model.predict(inputs)) + friction
|
return float(self.neural_ff_model.predict(inputs)) + friction
|
||||||
|
|
||||||
def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType:
|
def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType:
|
||||||
if self.CP.carFingerprint in (CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_BOLT_CC):
|
|
||||||
self.neural_ff_model = NanoFFModel(NEURAL_PARAMS_PATH, self.CP.carFingerprint)
|
|
||||||
return self.torque_from_lateral_accel_neural
|
|
||||||
elif self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS:
|
|
||||||
return self.torque_from_lateral_accel_siglin
|
return self.torque_from_lateral_accel_siglin
|
||||||
else:
|
|
||||||
return self.torque_from_lateral_accel_linear
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs, frogpilot_toggles):
|
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs, frogpilot_toggles):
|
||||||
@@ -104,13 +98,15 @@ class CarInterface(CarInterfaceBase):
|
|||||||
if PEDAL_MSG in fingerprint[0]:
|
if PEDAL_MSG in fingerprint[0]:
|
||||||
ret.enableGasInterceptor = True
|
ret.enableGasInterceptor = True
|
||||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_GAS_INTERCEPTOR
|
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_GAS_INTERCEPTOR
|
||||||
|
# When a pedal interceptor is present, always use normal longitudinal (block stock cruise)
|
||||||
|
experimental_long = False
|
||||||
|
|
||||||
if candidate in EV_CAR:
|
if candidate in EV_CAR:
|
||||||
ret.transmissionType = TransmissionType.direct
|
ret.transmissionType = TransmissionType.direct
|
||||||
else:
|
else:
|
||||||
ret.transmissionType = TransmissionType.automatic
|
ret.transmissionType = TransmissionType.automatic
|
||||||
|
|
||||||
ret.longitudinalTuning.kiBP = [5., 35.]
|
ret.longitudinalTuning.kiBP = [5., 35., 60.]
|
||||||
|
|
||||||
if candidate in CAMERA_ACC_CAR:
|
if candidate in CAMERA_ACC_CAR:
|
||||||
ret.experimentalLongitudinalAvailable = candidate not in CC_ONLY_CAR
|
ret.experimentalLongitudinalAvailable = candidate not in CC_ONLY_CAR
|
||||||
@@ -122,13 +118,14 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.minSteerSpeed = 10 * CV.KPH_TO_MS
|
ret.minSteerSpeed = 10 * CV.KPH_TO_MS
|
||||||
|
|
||||||
# Tuning for experimental long
|
# Tuning for experimental long
|
||||||
ret.longitudinalTuning.kiV = [2.0, 1.5]
|
ret.longitudinalTuning.kiV = [0.5, 0.5, 0.5]
|
||||||
ret.vEgoStopping = 0.1
|
ret.vEgoStopping = 0.1
|
||||||
ret.vEgoStarting = 0.1
|
ret.vEgoStarting = 0.1
|
||||||
|
|
||||||
ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling
|
ret.stoppingDecelRate = 1.0 # reach brake quickly after enabling
|
||||||
ret.vEgoStopping = 0.25
|
ret.vEgoStopping = 0.25
|
||||||
ret.vEgoStarting = 0.25
|
ret.vEgoStarting = 0.25
|
||||||
|
ret.stopAccel = -0.25
|
||||||
|
|
||||||
if experimental_long:
|
if experimental_long:
|
||||||
ret.pcmCruise = False
|
ret.pcmCruise = False
|
||||||
@@ -136,7 +133,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
|
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
|
||||||
|
|
||||||
elif candidate in SDGM_CAR:
|
elif candidate in SDGM_CAR:
|
||||||
ret.longitudinalTuning.kiV = [0., 0.] # TODO: tuning
|
ret.longitudinalTuning.kiV = [0., 0., 0.] # TODO: tuning
|
||||||
ret.experimentalLongitudinalAvailable = False
|
ret.experimentalLongitudinalAvailable = False
|
||||||
ret.networkLocation = NetworkLocation.fwdCamera
|
ret.networkLocation = NetworkLocation.fwdCamera
|
||||||
ret.pcmCruise = True
|
ret.pcmCruise = True
|
||||||
@@ -155,7 +152,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.minSteerSpeed = 7 * CV.MPH_TO_MS
|
ret.minSteerSpeed = 7 * CV.MPH_TO_MS
|
||||||
|
|
||||||
# Tuning
|
# Tuning
|
||||||
ret.longitudinalTuning.kiV = [2.4, 1.5]
|
ret.longitudinalTuning.kiV = [0.5, 0.5, 0.5]
|
||||||
|
|
||||||
if ret.enableGasInterceptor:
|
if ret.enableGasInterceptor:
|
||||||
# Need to set ASCM long limits when using pedal interceptor, instead of camera ACC long limits
|
# Need to set ASCM long limits when using pedal interceptor, instead of camera ACC long limits
|
||||||
@@ -206,6 +203,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
elif candidate in (CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_BOLT_CC):
|
elif candidate in (CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_BOLT_CC):
|
||||||
ret.steerActuatorDelay = 0.2
|
ret.steerActuatorDelay = 0.2
|
||||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||||
|
ret.lateralTuning.torque.kp = 0.6
|
||||||
|
|
||||||
if ret.enableGasInterceptor:
|
if ret.enableGasInterceptor:
|
||||||
# ACC Bolts use pedal for full longitudinal control, not just sng
|
# ACC Bolts use pedal for full longitudinal control, not just sng
|
||||||
@@ -271,13 +269,13 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.stoppingControl = True
|
ret.stoppingControl = True
|
||||||
ret.autoResumeSng = True
|
ret.autoResumeSng = True
|
||||||
|
|
||||||
if candidate in CC_ONLY_CAR:
|
if candidate in CC_ONLY_CAR: #pedal interceptor tuning
|
||||||
ret.flags |= GMFlags.PEDAL_LONG.value
|
ret.flags |= GMFlags.PEDAL_LONG.value
|
||||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_PEDAL_LONG
|
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_PEDAL_LONG
|
||||||
# Note: Low speed, stop and go not tested. Should be fairly smooth on highway
|
# Note: Low speed, stop and go not tested. Should be fairly smooth on highway
|
||||||
ret.longitudinalTuning.kiBP = [0.0, 5., 35.]
|
ret.longitudinalTuning.kiBP = [0., 3., 6., 35.]
|
||||||
ret.longitudinalTuning.kiV = [0.0, 0.35, 0.5]
|
ret.longitudinalTuning.kiV = [0.125, 0.175, 0.225, 0.33]
|
||||||
ret.longitudinalTuning.kf = 0.15
|
ret.longitudinalTuning.kf = 0.25
|
||||||
ret.stoppingDecelRate = 0.8
|
ret.stoppingDecelRate = 0.8
|
||||||
else: # Pedal used for SNG, ACC for longitudinal control otherwise
|
else: # Pedal used for SNG, ACC for longitudinal control otherwise
|
||||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
|
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
|
||||||
@@ -293,17 +291,17 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.minEnableSpeed = 24 * CV.MPH_TO_MS
|
ret.minEnableSpeed = 24 * CV.MPH_TO_MS
|
||||||
ret.openpilotLongitudinalControl = not frogpilot_toggles.disable_openpilot_long
|
ret.openpilotLongitudinalControl = not frogpilot_toggles.disable_openpilot_long
|
||||||
ret.pcmCruise = False
|
ret.pcmCruise = False
|
||||||
|
experimental_long = False
|
||||||
|
|
||||||
ret.stoppingDecelRate = 11.18 # == 25 mph/s (.04 rate)
|
if not ret.enableGasInterceptor and candidate in CC_ONLY_CAR: #redneck tuning
|
||||||
|
ret.longitudinalTuning.kpBP = [10.7, 10.8, 28.] # 10.7 m/s == 24 mph
|
||||||
ret.longitudinalTuning.deadzoneBP = [0.]
|
ret.longitudinalTuning.kpV = [0., 20., 20.] # set lower end to 0 since we can't drive below that speed
|
||||||
ret.longitudinalTuning.deadzoneV = [0.56] # == 2 km/h/s, 1.25 mph/s
|
ret.longitudinalTuning.deadzoneBP = [0.]
|
||||||
ret.longitudinalActuatorDelay = 1. # TODO: measure this
|
ret.longitudinalTuning.deadzoneV = [0.56] # == 2 km/h/s, 1.25 mph/s
|
||||||
|
ret.longitudinalActuatorDelay = 1. # TODO: measure this
|
||||||
ret.longitudinalTuning.kpBP = [10.7, 10.8, 28.] # 10.7 m/s == 24 mph
|
ret.longitudinalTuning.kiBP = [0.]
|
||||||
ret.longitudinalTuning.kpV = [0., 20., 20.] # set lower end to 0 since we can't drive below that speed
|
ret.longitudinalTuning.kiV = [0.1]
|
||||||
ret.longitudinalTuning.kiBP = [0.]
|
ret.stoppingDecelRate = 11.18 # == 25 mph/s (.04 rate)
|
||||||
ret.longitudinalTuning.kiV = [0.1]
|
|
||||||
|
|
||||||
if candidate in CC_ONLY_CAR:
|
if candidate in CC_ONLY_CAR:
|
||||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_NO_ACC
|
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_NO_ACC
|
||||||
|
|||||||
@@ -205,15 +205,15 @@ class CAR(Platforms):
|
|||||||
CHEVROLET_SUBURBAN.specs,
|
CHEVROLET_SUBURBAN.specs,
|
||||||
)
|
)
|
||||||
GMC_YUKON_CC = GMPlatformConfig(
|
GMC_YUKON_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("GMC Yukon - No-ACC")],
|
[GMCarDocs("GMC Yukon No ACC")],
|
||||||
CarSpecs(mass=2541, wheelbase=2.95, steerRatio=16.3, centerToFrontRatio=0.4),
|
CarSpecs(mass=2541, wheelbase=2.95, steerRatio=16.3, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
CADILLAC_CT6_CC = GMPlatformConfig(
|
CADILLAC_CT6_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Cadillac CT6 - No-ACC")],
|
[GMCarDocs("Cadillac CT6 No ACC")],
|
||||||
CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4),
|
CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
CHEVROLET_TRAILBLAZER_CC = GMPlatformConfig(
|
CHEVROLET_TRAILBLAZER_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Trailblazer 2021-22 - No-ACC")],
|
[GMCarDocs("Chevrolet Trailblazer 2021-22")],
|
||||||
CHEVROLET_TRAILBLAZER.specs,
|
CHEVROLET_TRAILBLAZER.specs,
|
||||||
)
|
)
|
||||||
CADILLAC_XT4 = GMPlatformConfig(
|
CADILLAC_XT4 = GMPlatformConfig(
|
||||||
@@ -221,7 +221,7 @@ class CAR(Platforms):
|
|||||||
CarSpecs(mass=1660, wheelbase=2.78, steerRatio=14.4, centerToFrontRatio=0.4),
|
CarSpecs(mass=1660, wheelbase=2.78, steerRatio=14.4, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
CADILLAC_XT5_CC = GMPlatformConfig(
|
CADILLAC_XT5_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Cadillac XT5 - No-ACC")],
|
[GMCarDocs("Cadillac XT5 No ACC")],
|
||||||
CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5),
|
CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5),
|
||||||
)
|
)
|
||||||
CHEVROLET_TRAVERSE = GMPlatformConfig(
|
CHEVROLET_TRAVERSE = GMPlatformConfig(
|
||||||
@@ -233,7 +233,7 @@ class CAR(Platforms):
|
|||||||
CarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.0, centerToFrontRatio=0.5),
|
CarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.0, centerToFrontRatio=0.5),
|
||||||
)
|
)
|
||||||
CHEVROLET_MALIBU_CC = GMPlatformConfig(
|
CHEVROLET_MALIBU_CC = GMPlatformConfig(
|
||||||
[GMCarDocs("Chevrolet Malibu 2023 - No-ACC")],
|
[GMCarDocs("Chevrolet Malibu 2023 No ACC")],
|
||||||
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4),
|
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4),
|
||||||
)
|
)
|
||||||
CHEVROLET_TRAX = GMPlatformConfig(
|
CHEVROLET_TRAX = GMPlatformConfig(
|
||||||
|
|||||||
@@ -218,9 +218,10 @@ class CarInterfaceBase(ABC):
|
|||||||
self.silent_steer_warning = True
|
self.silent_steer_warning = True
|
||||||
self.v_ego_cluster_seen = False
|
self.v_ego_cluster_seen = False
|
||||||
|
|
||||||
self.CS = CarState(CP, FPCP)
|
self.CS = CarState(CP, None)
|
||||||
self.cp = self.CS.get_can_parser(CP, FPCP)
|
fp = FPCP if FPCP is not None else getattr(self, "FPCP", None)
|
||||||
self.cp_cam = self.CS.get_cam_can_parser(CP, FPCP)
|
self.cp = self.CS.get_can_parser(CP, fp)
|
||||||
|
self.cp_cam = self.CS.get_cam_can_parser(CP, fp)
|
||||||
self.cp_adas = self.CS.get_adas_can_parser(CP)
|
self.cp_adas = self.CS.get_adas_can_parser(CP)
|
||||||
self.cp_body = self.CS.get_body_can_parser(CP)
|
self.cp_body = self.CS.get_body_can_parser(CP)
|
||||||
self.cp_loopback = self.CS.get_loopback_can_parser(CP)
|
self.cp_loopback = self.CS.get_loopback_can_parser(CP)
|
||||||
@@ -411,7 +412,7 @@ class CarInterfaceBase(ABC):
|
|||||||
|
|
||||||
tune.init('torque')
|
tune.init('torque')
|
||||||
tune.torque.useSteeringAngle = use_steering_angle
|
tune.torque.useSteeringAngle = use_steering_angle
|
||||||
tune.torque.kp = 1.0
|
tune.torque.kp = 0.6
|
||||||
tune.torque.kf = 1.0
|
tune.torque.kf = 1.0
|
||||||
tune.torque.ki = 0.1
|
tune.torque.ki = 0.1
|
||||||
tune.torque.friction = params['FRICTION']
|
tune.torque.friction = params['FRICTION']
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import math
|
import math
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
from cereal import car, log
|
from cereal import car, log
|
||||||
from openpilot.common.conversions import Conversions as CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
from openpilot.common.numpy_fast import clip, interp
|
from openpilot.common.numpy_fast import clip, interp
|
||||||
from openpilot.common.realtime import DT_CTRL
|
from openpilot.common.realtime import DT_CTRL, DT_MDL
|
||||||
|
|
||||||
# WARNING: this value was determined based on the model's training distribution,
|
# WARNING: this value was determined based on the model's training distribution,
|
||||||
# model predictions above this speed can be unpredictable
|
# model predictions above this speed can be unpredictable
|
||||||
@@ -178,6 +179,9 @@ def apply_center_deadzone(error, deadzone):
|
|||||||
def rate_limit(new_value, last_value, dw_step, up_step):
|
def rate_limit(new_value, last_value, dw_step, up_step):
|
||||||
return clip(new_value, last_value + dw_step, last_value + up_step)
|
return clip(new_value, last_value + dw_step, last_value + up_step)
|
||||||
|
|
||||||
|
def smooth_value(val, prev_val, tau, dt=DT_MDL):
|
||||||
|
alpha = 1 - np.exp(-dt/tau) if tau > 0 else 1
|
||||||
|
return alpha * val + (1 - alpha) * prev_val
|
||||||
|
|
||||||
def clip_curvature(v_ego, prev_curvature, new_curvature, planner_curves):
|
def clip_curvature(v_ego, prev_curvature, new_curvature, planner_curves):
|
||||||
if planner_curves:
|
if planner_curves:
|
||||||
@@ -208,3 +212,29 @@ def get_speed_error(modelV2: log.ModelDataV2, v_ego: float) -> float:
|
|||||||
vel_err = clip(modelV2.temporalPose.trans[0] - v_ego, -MAX_VEL_ERR, MAX_VEL_ERR)
|
vel_err = clip(modelV2.temporalPose.trans[0] - v_ego, -MAX_VEL_ERR, MAX_VEL_ERR)
|
||||||
return float(vel_err)
|
return float(vel_err)
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def get_accel_from_plan_tomb_raider(speeds, accels, t_idxs, action_t=DT_MDL, vEgoStopping=0.05):
|
||||||
|
if len(speeds) == len(t_idxs):
|
||||||
|
v_now = speeds[0]
|
||||||
|
a_now = accels[0]
|
||||||
|
v_target = np.interp(action_t, t_idxs, speeds)
|
||||||
|
a_target = 2 * (v_target - v_now) / (action_t) - a_now
|
||||||
|
v_target_1sec = np.interp(action_t + 1.0, t_idxs, speeds)
|
||||||
|
else:
|
||||||
|
v_target = 0.0
|
||||||
|
v_target_1sec = 0.0
|
||||||
|
a_target = 0.0
|
||||||
|
should_stop = (v_target < vEgoStopping and
|
||||||
|
v_target_1sec < vEgoStopping)
|
||||||
|
return a_target, should_stop
|
||||||
|
|
||||||
|
def curv_from_psis(psi_target, psi_rate, vego, action_t):
|
||||||
|
vego = np.clip(vego, MIN_SPEED, np.inf)
|
||||||
|
curv_from_psi = psi_target / (vego * action_t)
|
||||||
|
return 2*curv_from_psi - psi_rate / vego
|
||||||
|
|
||||||
|
def get_curvature_from_plan(yaws, yaw_rates, t_idxs, vego, action_t):
|
||||||
|
psi_target = np.interp(action_t, t_idxs, yaws)
|
||||||
|
psi_rate = yaw_rates[0]
|
||||||
|
return curv_from_psis(psi_target, psi_rate, vego, action_t)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ from openpilot.common.realtime import DT_CTRL
|
|||||||
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_deadzone
|
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_deadzone
|
||||||
from openpilot.selfdrive.controls.lib.pid import PIDController
|
from openpilot.selfdrive.controls.lib.pid import PIDController
|
||||||
from openpilot.selfdrive.modeld.constants import ModelConstants
|
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||||
|
from openpilot.common.filter_simple import FirstOrderFilter
|
||||||
|
from openpilot.selfdrive.car.gm.values import CarControllerParams
|
||||||
|
|
||||||
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
|
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
|
||||||
|
|
||||||
@@ -85,17 +87,48 @@ def long_control_state_trans_old_long(CP, active, long_control_state, v_ego, v_t
|
|||||||
|
|
||||||
return long_control_state
|
return long_control_state
|
||||||
|
|
||||||
|
|
||||||
class LongControl:
|
class LongControl:
|
||||||
def __init__(self, CP):
|
def __init__(self, CP):
|
||||||
self.CP = CP
|
self.CP = CP
|
||||||
self.long_control_state = LongCtrlState.off
|
self.long_control_state = LongCtrlState.off
|
||||||
|
self.experimental_mode = False
|
||||||
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
|
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
|
||||||
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
|
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
|
||||||
k_f=CP.longitudinalTuning.kf, rate=1 / DT_CTRL)
|
k_f=CP.longitudinalTuning.kf, rate=1 / DT_CTRL,
|
||||||
|
pos_p_limit=None)
|
||||||
self.v_pid = 0.0
|
self.v_pid = 0.0
|
||||||
|
self._mode_setup()
|
||||||
self.last_output_accel = 0.0
|
self.last_output_accel = 0.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def update_mpc_mode(self, experimental_mode):
|
||||||
|
new_mode = 'blended' if experimental_mode else 'acc'
|
||||||
|
|
||||||
|
if self.transitioning and self.prev_mode == 'blended' and self.current_mode == 'acc':
|
||||||
|
self.mode_transition_timer = 0.0
|
||||||
|
|
||||||
|
if new_mode != self.current_mode:
|
||||||
|
self.prev_mode = self.current_mode
|
||||||
|
self.transitioning = True
|
||||||
|
self.mode_transition_timer = 0.0
|
||||||
|
self.mode_transition_filter.x = self.last_output_accel
|
||||||
|
|
||||||
|
self.current_mode = new_mode
|
||||||
|
|
||||||
|
if self.transitioning:
|
||||||
|
self.mode_transition_timer += DT_CTRL
|
||||||
|
if self.mode_transition_timer >= self.mode_transition_duration:
|
||||||
|
self.transitioning = False
|
||||||
|
|
||||||
|
def _mode_setup(self):
|
||||||
|
self.prev_mode = 'acc'
|
||||||
|
self.current_mode = 'acc'
|
||||||
|
self.mode_transition_filter = FirstOrderFilter(0.0, 0.5, DT_CTRL)
|
||||||
|
self.mode_transition_timer = 0.0
|
||||||
|
self.mode_transition_duration = 1.0
|
||||||
|
self.transitioning = False
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.pid.reset()
|
self.pid.reset()
|
||||||
|
|
||||||
@@ -124,8 +157,19 @@ class LongControl:
|
|||||||
|
|
||||||
else: # LongCtrlState.pid
|
else: # LongCtrlState.pid
|
||||||
error = a_target - CS.aEgo
|
error = a_target - CS.aEgo
|
||||||
output_accel = self.pid.update(error, speed=CS.vEgo,
|
self.update_mpc_mode(self.experimental_mode)
|
||||||
feedforward=a_target)
|
raw_output_accel = self.pid.update(error, speed=CS.vEgo, feedforward=a_target)
|
||||||
|
|
||||||
|
|
||||||
|
if self.transitioning and self.prev_mode == 'acc' and self.current_mode == 'blended':
|
||||||
|
if raw_output_accel < 0 and raw_output_accel < self.last_output_accel:
|
||||||
|
progress = min(1.0, self.mode_transition_timer / self.mode_transition_duration)
|
||||||
|
blend_factor = 1.0 - (1.0 - progress) * (1.0 - abs(raw_output_accel / CarControllerParams.ACCEL_MIN))
|
||||||
|
output_accel = self.last_output_accel + (raw_output_accel - self.last_output_accel) * blend_factor
|
||||||
|
else:
|
||||||
|
output_accel = raw_output_accel
|
||||||
|
else:
|
||||||
|
output_accel = raw_output_accel
|
||||||
|
|
||||||
self.last_output_accel = clip(output_accel, accel_limits[0], accel_limits[1])
|
self.last_output_accel = clip(output_accel, accel_limits[0], accel_limits[1])
|
||||||
return self.last_output_accel
|
return self.last_output_accel
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from openpilot.selfdrive.car.interfaces import ACCEL_MIN, ACCEL_MAX
|
|||||||
from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState
|
from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState
|
||||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
|
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
|
||||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC, LEAD_ACCEL_TAU
|
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC, LEAD_ACCEL_TAU
|
||||||
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, V_CRUISE_UNSET, CONTROL_N, get_speed_error
|
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, V_CRUISE_UNSET, CONTROL_N, get_speed_error, get_accel_from_plan_tomb_raider
|
||||||
from openpilot.common.swaglog import cloudlog
|
from openpilot.common.swaglog import cloudlog
|
||||||
|
|
||||||
LON_MPC_STEP = 0.2 # first step is 0.2s
|
LON_MPC_STEP = 0.2 # first step is 0.2s
|
||||||
@@ -203,8 +203,12 @@ class LongitudinalPlanner:
|
|||||||
throttle_prob = 1.0
|
throttle_prob = 1.0
|
||||||
return x, v, a, j, throttle_prob
|
return x, v, a, j, throttle_prob
|
||||||
|
|
||||||
def update(self, radarless_model, sm, frogpilot_toggles):
|
def update(self, radarless_model, tomb_raider, sm, frogpilot_toggles):
|
||||||
self.mpc.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc'
|
if tomb_raider:
|
||||||
|
self.mpc.mode = 'acc'
|
||||||
|
self.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc'
|
||||||
|
else:
|
||||||
|
self.mpc.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc'
|
||||||
|
|
||||||
if len(sm['carControl'].orientationNED) == 3:
|
if len(sm['carControl'].orientationNED) == 3:
|
||||||
accel_coast = get_coast_accel(sm['carControl'].orientationNED[1])
|
accel_coast = get_coast_accel(sm['carControl'].orientationNED[1])
|
||||||
@@ -294,7 +298,7 @@ class LongitudinalPlanner:
|
|||||||
self.a_desired = float(interp(self.dt, CONTROL_N_T_IDX, self.a_desired_trajectory))
|
self.a_desired = float(interp(self.dt, CONTROL_N_T_IDX, self.a_desired_trajectory))
|
||||||
self.v_desired_filter.x = self.v_desired_filter.x + self.dt * (self.a_desired + a_prev) / 2.0
|
self.v_desired_filter.x = self.v_desired_filter.x + self.dt * (self.a_desired + a_prev) / 2.0
|
||||||
|
|
||||||
def publish(self, classic_model, sm, pm, frogpilot_toggles):
|
def publish(self, classic_model, tomb_raider, sm, pm, frogpilot_toggles):
|
||||||
plan_send = messaging.new_message('longitudinalPlan')
|
plan_send = messaging.new_message('longitudinalPlan')
|
||||||
|
|
||||||
plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState'])
|
plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState'])
|
||||||
@@ -314,12 +318,25 @@ class LongitudinalPlanner:
|
|||||||
|
|
||||||
if classic_model:
|
if classic_model:
|
||||||
a_target, should_stop = get_accel_from_plan_classic(self.CP, longitudinalPlan.speeds, longitudinalPlan.accels, vEgoStopping=frogpilot_toggles.vEgoStopping)
|
a_target, should_stop = get_accel_from_plan_classic(self.CP, longitudinalPlan.speeds, longitudinalPlan.accels, vEgoStopping=frogpilot_toggles.vEgoStopping)
|
||||||
|
elif tomb_raider:
|
||||||
|
action_t = self.CP.longitudinalActuatorDelay + DT_MDL
|
||||||
|
output_a_target_mpc, output_should_stop_mpc = get_accel_from_plan_tomb_raider(self.v_desired_trajectory, self.a_desired_trajectory, CONTROL_N_T_IDX,
|
||||||
|
action_t=action_t, vEgoStopping=frogpilot_toggles.vEgoStopping)
|
||||||
|
output_a_target_e2e = sm['modelV2'].action.desiredAcceleration
|
||||||
|
output_should_stop_e2e = sm['modelV2'].action.shouldStop
|
||||||
|
|
||||||
|
if self.mode == 'acc':
|
||||||
|
a_target = output_a_target_mpc
|
||||||
|
should_stop = output_should_stop_mpc
|
||||||
|
else:
|
||||||
|
a_target = min(output_a_target_mpc, output_a_target_e2e)
|
||||||
|
should_stop = output_should_stop_e2e or output_should_stop_mpc
|
||||||
else:
|
else:
|
||||||
action_t = self.CP.longitudinalActuatorDelay + DT_MDL
|
action_t = self.CP.longitudinalActuatorDelay + DT_MDL
|
||||||
a_target, should_stop = get_accel_from_plan(longitudinalPlan.speeds, longitudinalPlan.accels,
|
a_target, should_stop = get_accel_from_plan(longitudinalPlan.speeds, longitudinalPlan.accels,
|
||||||
action_t=action_t, vEgoStopping=frogpilot_toggles.vEgoStopping)
|
action_t=action_t, vEgoStopping=frogpilot_toggles.vEgoStopping)
|
||||||
longitudinalPlan.aTarget = a_target
|
longitudinalPlan.aTarget = float(a_target)
|
||||||
longitudinalPlan.shouldStop = should_stop
|
longitudinalPlan.shouldStop = bool(should_stop)
|
||||||
longitudinalPlan.allowBrake = True
|
longitudinalPlan.allowBrake = True
|
||||||
longitudinalPlan.allowThrottle = self.allow_throttle
|
longitudinalPlan.allowThrottle = self.allow_throttle
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ from openpilot.common.numpy_fast import clip, interp
|
|||||||
|
|
||||||
|
|
||||||
class PIDController:
|
class PIDController:
|
||||||
def __init__(self, k_p, k_i, k_f=0., k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100):
|
def __init__(self, k_p, k_i, k_f=0., k_d=0.,
|
||||||
|
pos_limit=1e308, neg_limit=-1e308, rate=100,
|
||||||
|
pos_p_limit=None, neg_p_limit=None):
|
||||||
self._k_p = k_p
|
self._k_p = k_p
|
||||||
self._k_i = k_i
|
self._k_i = k_i
|
||||||
self._k_d = k_d
|
self._k_d = k_d
|
||||||
@@ -20,6 +22,9 @@ class PIDController:
|
|||||||
self.pos_limit = pos_limit
|
self.pos_limit = pos_limit
|
||||||
self.neg_limit = neg_limit
|
self.neg_limit = neg_limit
|
||||||
|
|
||||||
|
self.pos_p_limit = pos_p_limit
|
||||||
|
self.neg_p_limit = neg_p_limit
|
||||||
|
|
||||||
self.i_unwind_rate = 0.3 / rate
|
self.i_unwind_rate = 0.3 / rate
|
||||||
self.i_rate = 1.0 / rate
|
self.i_rate = 1.0 / rate
|
||||||
self.speed = 0.0
|
self.speed = 0.0
|
||||||
@@ -53,6 +58,10 @@ class PIDController:
|
|||||||
self.speed = speed
|
self.speed = speed
|
||||||
|
|
||||||
self.p = float(error) * self.k_p
|
self.p = float(error) * self.k_p
|
||||||
|
if self.pos_p_limit is not None and self.p > self.pos_p_limit:
|
||||||
|
self.p = self.pos_p_limit
|
||||||
|
elif self.neg_p_limit is not None and self.p < self.neg_p_limit:
|
||||||
|
self.p = self.neg_p_limit
|
||||||
self.f = feedforward * self.k_f
|
self.f = feedforward * self.k_f
|
||||||
self.d = error_rate * self.k_d
|
self.d = error_rate * self.k_d
|
||||||
|
|
||||||
|
|||||||
@@ -39,12 +39,13 @@ def plannerd_thread():
|
|||||||
|
|
||||||
classic_model = frogpilot_toggles.classic_model
|
classic_model = frogpilot_toggles.classic_model
|
||||||
radarless_model = frogpilot_toggles.radarless_model
|
radarless_model = frogpilot_toggles.radarless_model
|
||||||
|
tomb_raider = frogpilot_toggles.model == "tomb-raider"
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
sm.update()
|
sm.update()
|
||||||
if sm.updated['modelV2']:
|
if sm.updated['modelV2']:
|
||||||
longitudinal_planner.update(radarless_model, sm, frogpilot_toggles)
|
longitudinal_planner.update(radarless_model, tomb_raider, sm, frogpilot_toggles)
|
||||||
longitudinal_planner.publish(classic_model, sm, pm, frogpilot_toggles)
|
longitudinal_planner.publish(classic_model, tomb_raider, sm, pm, frogpilot_toggles)
|
||||||
publish_ui_plan(sm, pm, longitudinal_planner)
|
publish_ui_plan(sm, pm, longitudinal_planner)
|
||||||
|
|
||||||
# Update FrogPilot parameters
|
# Update FrogPilot parameters
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from openpilot.common.simple_kalman import KF1D
|
|||||||
from openpilot.frogpilot.common.frogpilot_variables import get_frogpilot_toggles
|
from openpilot.frogpilot.common.frogpilot_variables import get_frogpilot_toggles
|
||||||
|
|
||||||
# Default lead acceleration decay set to 50% at 1s
|
# Default lead acceleration decay set to 50% at 1s
|
||||||
_LEAD_ACCEL_TAU = 1.5
|
_LEAD_ACCEL_TAU = 0.6
|
||||||
|
|
||||||
# radar tracks
|
# radar tracks
|
||||||
SPEED, ACCEL = 0, 1 # Kalman filter states enum
|
SPEED, ACCEL = 0, 1 # Kalman filter states enum
|
||||||
@@ -79,7 +79,7 @@ class Track:
|
|||||||
|
|
||||||
# Learn if constant acceleration
|
# Learn if constant acceleration
|
||||||
if abs(self.aLeadK) < 0.5:
|
if abs(self.aLeadK) < 0.5:
|
||||||
self.aLeadTau.x = _LEAD_ACCEL_TAU
|
self.aLeadTau.x = min(max(self.aLeadTau, 1e-2) * 1.1, _LEAD_ACCEL_TAU)
|
||||||
else:
|
else:
|
||||||
self.aLeadTau.update(0.0)
|
self.aLeadTau.update(0.0)
|
||||||
|
|
||||||
@@ -163,14 +163,16 @@ def match_vision_to_track(v_ego: float, lead: capnp._DynamicStructReader, tracks
|
|||||||
|
|
||||||
|
|
||||||
def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: float, model_v_ego: float):
|
def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: float, model_v_ego: float):
|
||||||
lead_v_rel_pred = lead_msg.v[0] - model_v_ego
|
prev_aLeadK = getattr(get_RadarState_from_vision, "prev_aLeadK", 0.0)
|
||||||
|
blended_aLeadK = 0.8 * float(lead_msg.a[0]) + 0.2 * prev_aLeadK
|
||||||
|
get_RadarState_from_vision.prev_aLeadK = blended_aLeadK
|
||||||
return {
|
return {
|
||||||
"dRel": float(lead_msg.x[0] - RADAR_TO_CAMERA),
|
"dRel": float(lead_msg.x[0] - RADAR_TO_CAMERA),
|
||||||
"yRel": float(-lead_msg.y[0]),
|
"yRel": float(-lead_msg.y[0]),
|
||||||
"vRel": float(lead_v_rel_pred),
|
"vRel": float(lead_msg.v[0] - model_v_ego),
|
||||||
"vLead": float(v_ego + lead_v_rel_pred),
|
"vLead": float(v_ego + (lead_msg.v[0] - model_v_ego)),
|
||||||
"vLeadK": float(v_ego + lead_v_rel_pred),
|
"vLeadK": float(v_ego + (lead_msg.v[0] - model_v_ego)),
|
||||||
"aLeadK": float(lead_msg.a[0]),
|
"aLeadK": blended_aLeadK,
|
||||||
"aLeadTau": 0.3,
|
"aLeadTau": 0.3,
|
||||||
"fcw": False,
|
"fcw": False,
|
||||||
"modelProb": float(lead_msg.prob),
|
"modelProb": float(lead_msg.prob),
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 131 B After Width: | Height: | Size: 402 KiB |
@@ -1,13 +1,18 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "boot",
|
"name": "boot",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/boot-5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f.img.xz",
|
"url": "https://www.dropbox.com/scl/fi/z8gcamb7n78xqb515kfgq/boot.img.xz?rlkey=r2zxothb3pz0q9rtqysr1zhwv&st=f0acze3w&dl=1",
|
||||||
"hash": "5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f",
|
"hash": "b997aae3f1c93de82449ef7f23f30ff482b0978f3d0ac08219366f9ce362ad7a",
|
||||||
"hash_raw": "5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f",
|
"hash_raw": "b997aae3f1c93de82449ef7f23f30ff482b0978f3d0ac08219366f9ce362ad7a",
|
||||||
"size": 16029696,
|
"size": 16029696,
|
||||||
"sparse": false,
|
"sparse": false,
|
||||||
"full_check": true,
|
"full_check": true,
|
||||||
"has_ab": true
|
"has_ab": true,
|
||||||
|
"alt": {
|
||||||
|
"hash": "5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f",
|
||||||
|
"url": "https://commadist.azureedge.net/agnosupdate/boot-5674ea6767e7198cf1e7def3de66a57061f001ed76d43dc4b4f84de545c53c6f.img.xz",
|
||||||
|
"size": 16029696
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "abl",
|
"name": "abl",
|
||||||
@@ -61,17 +66,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "system",
|
"name": "system",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/system-1badfe72851628d6cf9200a53a6151bb4e797b49c717141409fc57138eae388a.img.xz",
|
"url": "https://www.dropbox.com/scl/fi/n22f3eex1z52dbrhhxqry/system.img.xz?rlkey=yw4ult7s3sdm6b7d31hrm3zx8&st=of6m7zis&dl=1",
|
||||||
"hash": "328e90c62068222dfd98f71dd3f6251fcb962f082b49c6be66ab2699f5db6f4f",
|
"hash": "be1c6bb9ee5e06779087b1b81e09b6df61d942566b0f8d4539c452179c661782",
|
||||||
"hash_raw": "1badfe72851628d6cf9200a53a6151bb4e797b49c717141409fc57138eae388a",
|
"hash_raw": "a5f84e68d199466fda5c9aead760b90a4cd2d2ef9a418708b9794d95bb03ec5b",
|
||||||
"size": 10737418240,
|
"size": 10737418240,
|
||||||
"sparse": true,
|
"sparse": true,
|
||||||
"full_check": false,
|
"full_check": false,
|
||||||
"has_ab": true,
|
"has_ab": true,
|
||||||
"alt": {
|
"alt": {
|
||||||
"hash": "bc11d2148f29862ee1326aca2af1cf6bbf5fed831e3f8f6b8f7a0f110dfe8d26",
|
"hash": "328e90c62068222dfd98f71dd3f6251fcb962f082b49c6be66ab2699f5db6f4f",
|
||||||
"url": "https://commadist.azureedge.net/agnosupdate/system-skip-chunks-1badfe72851628d6cf9200a53a6151bb4e797b49c717141409fc57138eae388a.img.xz",
|
"url": "https://commadist.azureedge.net/agnosupdate/system-1badfe72851628d6cf9200a53a6151bb4e797b49c717141409fc57138eae388a.img.xz",
|
||||||
"size": 4548070000
|
"size": 10737418240
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -168,18 +168,24 @@ def extract_compressed_image(target_slot_number: int, partition: dict, cloudlog)
|
|||||||
last_p = p
|
last_p = p
|
||||||
print(f"Installing {partition['name']}: {p}", flush=True)
|
print(f"Installing {partition['name']}: {p}", flush=True)
|
||||||
|
|
||||||
if raw_hash.hexdigest().lower() != partition['hash_raw'].lower():
|
written_size = out.tell()
|
||||||
raise Exception(f"Raw hash mismatch '{raw_hash.hexdigest().lower()}'")
|
expected_size = partition['size']
|
||||||
|
actual_raw_hash = raw_hash.hexdigest().lower()
|
||||||
|
expected_raw_hash = partition['hash_raw'].lower()
|
||||||
|
actual_final_hash = downloader.sha256.hexdigest().lower()
|
||||||
|
expected_final_hash = partition['hash'].lower()
|
||||||
|
|
||||||
if downloader.sha256.hexdigest().lower() != partition['hash'].lower():
|
if actual_raw_hash != expected_raw_hash:
|
||||||
raise Exception("Uncompressed hash mismatch")
|
raise Exception(f"Raw hash mismatch: got {actual_raw_hash}, expected {expected_raw_hash}")
|
||||||
|
|
||||||
if out.tell() != partition['size']:
|
if actual_final_hash != expected_final_hash:
|
||||||
raise Exception("Uncompressed size mismatch")
|
raise Exception(f"Uncompressed hash mismatch: got {actual_final_hash}, expected {expected_final_hash}")
|
||||||
|
|
||||||
|
if written_size != expected_size:
|
||||||
|
raise Exception(f"Uncompressed size mismatch: wrote {written_size} bytes, expected {expected_size} bytes")
|
||||||
|
|
||||||
os.sync()
|
os.sync()
|
||||||
|
|
||||||
|
|
||||||
def extract_casync_image(target_slot_number: int, partition: dict, cloudlog):
|
def extract_casync_image(target_slot_number: int, partition: dict, cloudlog):
|
||||||
path = get_partition_path(target_slot_number, partition)
|
path = get_partition_path(target_slot_number, partition)
|
||||||
seed_path = path[:-1] + ('b' if path[-1] == 'a' else 'a')
|
seed_path = path[:-1] + ('b' if path[-1] == 'a' else 'a')
|
||||||
|
|||||||