mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-07-17 23:42:07 +08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 924eb1aa57 | |||
| 4faeedec57 | |||
| 638a92bffb | |||
| ad2fab062e | |||
| d5b59d2b19 | |||
| 079ce94cb4 | |||
| f7efd7c641 | |||
| 30907c3cf9 | |||
| a39bc65883 | |||
| 2cc3755760 | |||
| abf836a2b8 | |||
| 3c100e3d92 | |||
| cda3c90468 | |||
| 2c66b6bb75 | |||
| ee12e4b7b4 | |||
| a7751702b7 | |||
| eaa0b44f71 | |||
| 445b101a8b | |||
| 64cc311161 |
@@ -2,5 +2,4 @@ Wen
|
|||||||
REGIST
|
REGIST
|
||||||
PullRequest
|
PullRequest
|
||||||
cancelled
|
cancelled
|
||||||
indeces
|
|
||||||
FOF
|
FOF
|
||||||
|
|||||||
Generated
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
<tool name="uv Scons Build Debug" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
<tool name="uv Scons Build Debug" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
||||||
<exec>
|
<exec>
|
||||||
<option name="COMMAND" value="bash" />
|
<option name="COMMAND" value="bash" />
|
||||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --ccflags=\"-fno-inline\""" />
|
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --compile_db --ccflags=\"-fno-inline\""" />
|
||||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||||
</exec>
|
</exec>
|
||||||
</tool>
|
</tool>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<tool name="uv Scons Build Release" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
<tool name="uv Scons Build Release" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
|
||||||
<exec>
|
<exec>
|
||||||
<option name="COMMAND" value="bash" />
|
<option name="COMMAND" value="bash" />
|
||||||
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc)" " />
|
<option name="PARAMETERS" value="-c "source .venv/bin/activate && scons -u -j$(nproc) --compile_db" " />
|
||||||
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
|
||||||
</exec>
|
</exec>
|
||||||
</tool>
|
</tool>
|
||||||
|
|||||||
+10
-23
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
inline static std::unordered_map<std::string, uint32_t> keys = {
|
inline static std::unordered_map<std::string, uint32_t> keys = {
|
||||||
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
|
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
|
||||||
{"AdbEnabled", PERSISTENT | BACKUP},
|
{"AdbEnabled", PERSISTENT},
|
||||||
{"AlwaysOnDM", PERSISTENT | BACKUP},
|
{"AlwaysOnDM", PERSISTENT},
|
||||||
{"ApiCache_Device", PERSISTENT},
|
{"ApiCache_Device", PERSISTENT},
|
||||||
{"ApiCache_FirehoseStats", PERSISTENT},
|
{"ApiCache_FirehoseStats", PERSISTENT},
|
||||||
{"AssistNowToken", PERSISTENT},
|
{"AssistNowToken", PERSISTENT},
|
||||||
@@ -78,7 +78,7 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"LocationFilterInitialState", PERSISTENT},
|
{"LocationFilterInitialState", PERSISTENT},
|
||||||
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"LongitudinalPersonality", PERSISTENT | BACKUP},
|
{"LongitudinalPersonality", PERSISTENT | BACKUP},
|
||||||
{"NetworkMetered", PERSISTENT | BACKUP},
|
{"NetworkMetered", PERSISTENT},
|
||||||
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
|
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
|
||||||
@@ -124,29 +124,25 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
|
|
||||||
// --- sunnypilot params --- //
|
// --- sunnypilot params --- //
|
||||||
{"ApiCache_DriveStats", PERSISTENT},
|
{"ApiCache_DriveStats", PERSISTENT},
|
||||||
{"AutoLaneChangeBsmDelay", PERSISTENT | BACKUP},
|
{"AutoLaneChangeBsmDelay", PERSISTENT},
|
||||||
{"AutoLaneChangeTimer", PERSISTENT | BACKUP},
|
{"AutoLaneChangeTimer", PERSISTENT},
|
||||||
{"BlinkerMinLateralControlSpeed", PERSISTENT | BACKUP},
|
{"BlinkerMinLateralControlSpeed", PERSISTENT | BACKUP},
|
||||||
{"BlinkerPauseLateralControl", PERSISTENT | BACKUP},
|
{"BlinkerPauseLateralControl", PERSISTENT | BACKUP},
|
||||||
{"Brightness", PERSISTENT | BACKUP},
|
|
||||||
{"CarParamsSP", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
{"CarParamsSP", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"CarParamsSPCache", CLEAR_ON_MANAGER_START},
|
{"CarParamsSPCache", CLEAR_ON_MANAGER_START},
|
||||||
{"CarParamsSPPersistent", PERSISTENT},
|
{"CarParamsSPPersistent", PERSISTENT},
|
||||||
{"CarPlatformBundle", PERSISTENT | BACKUP},
|
{"CarPlatformBundle", PERSISTENT},
|
||||||
{"ChevronInfo", PERSISTENT | BACKUP},
|
|
||||||
{"CustomAccIncrementsEnabled", PERSISTENT | BACKUP},
|
{"CustomAccIncrementsEnabled", PERSISTENT | BACKUP},
|
||||||
{"CustomAccLongPressIncrement", PERSISTENT | BACKUP},
|
{"CustomAccLongPressIncrement", PERSISTENT | BACKUP},
|
||||||
{"CustomAccShortPressIncrement", PERSISTENT | BACKUP},
|
{"CustomAccShortPressIncrement", PERSISTENT | BACKUP},
|
||||||
{"DeviceBootMode", PERSISTENT | BACKUP},
|
{"DeviceBootMode", PERSISTENT | BACKUP},
|
||||||
{"EnableGithubRunner", PERSISTENT | BACKUP},
|
{"EnableGithubRunner", PERSISTENT | BACKUP},
|
||||||
{"InteractivityTimeout", PERSISTENT | BACKUP},
|
{"InteractivityTimeout", PERSISTENT | BACKUP},
|
||||||
{"IsDevelopmentBranch", CLEAR_ON_MANAGER_START},
|
|
||||||
{"MaxTimeOffroad", PERSISTENT | BACKUP},
|
{"MaxTimeOffroad", PERSISTENT | BACKUP},
|
||||||
|
{"Brightness", PERSISTENT | BACKUP},
|
||||||
{"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION},
|
{"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"OffroadMode", CLEAR_ON_MANAGER_START},
|
{"OffroadMode", CLEAR_ON_MANAGER_START},
|
||||||
{"QuickBootToggle", PERSISTENT | BACKUP},
|
|
||||||
{"QuietMode", PERSISTENT | BACKUP},
|
{"QuietMode", PERSISTENT | BACKUP},
|
||||||
{"ShowAdvancedControls", PERSISTENT | BACKUP},
|
|
||||||
|
|
||||||
// MADS params
|
// MADS params
|
||||||
{"Mads", PERSISTENT | BACKUP},
|
{"Mads", PERSISTENT | BACKUP},
|
||||||
@@ -155,8 +151,8 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"MadsUnifiedEngagementMode", PERSISTENT | BACKUP},
|
{"MadsUnifiedEngagementMode", PERSISTENT | BACKUP},
|
||||||
|
|
||||||
// Model Manager params
|
// Model Manager params
|
||||||
|
{"DynamicModeldOutputs", PERSISTENT | BACKUP},
|
||||||
{"ModelManager_ActiveBundle", PERSISTENT},
|
{"ModelManager_ActiveBundle", PERSISTENT},
|
||||||
{"ModelManager_ClearCache", CLEAR_ON_MANAGER_START},
|
|
||||||
{"ModelManager_DownloadIndex", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
{"ModelManager_DownloadIndex", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||||
{"ModelManager_LastSyncTime", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
{"ModelManager_LastSyncTime", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
{"ModelManager_ModelsCache", PERSISTENT | BACKUP},
|
{"ModelManager_ModelsCache", PERSISTENT | BACKUP},
|
||||||
@@ -178,9 +174,9 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"BackupManager_RestoreVersion", PERSISTENT},
|
{"BackupManager_RestoreVersion", PERSISTENT},
|
||||||
|
|
||||||
// sunnypilot car specific params
|
// sunnypilot car specific params
|
||||||
{"HyundaiLongitudinalTuning", PERSISTENT | BACKUP},
|
{"HyundaiLongitudinalTuning", PERSISTENT},
|
||||||
|
|
||||||
{"DynamicExperimentalControl", PERSISTENT | BACKUP},
|
{"DynamicExperimentalControl", PERSISTENT},
|
||||||
{"BlindSpot", PERSISTENT | BACKUP},
|
{"BlindSpot", PERSISTENT | BACKUP},
|
||||||
|
|
||||||
// model panel params
|
// model panel params
|
||||||
@@ -207,13 +203,4 @@ inline static std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"OsmStateTitle", PERSISTENT},
|
{"OsmStateTitle", PERSISTENT},
|
||||||
{"OsmWayTest", PERSISTENT},
|
{"OsmWayTest", PERSISTENT},
|
||||||
{"RoadName", CLEAR_ON_ONROAD_TRANSITION},
|
{"RoadName", CLEAR_ON_ONROAD_TRANSITION},
|
||||||
|
|
||||||
// Tuning keys
|
|
||||||
{"EnableHkgTuningAngleSmoothingFactor", PERSISTENT | BACKUP},
|
|
||||||
{"HkgTuningAngleMinTorqueReductionGain", PERSISTENT | BACKUP},
|
|
||||||
{"HkgTuningAngleMaxTorqueReductionGain", PERSISTENT | BACKUP},
|
|
||||||
{"HkgTuningAngleActiveTorqueReductionGain", PERSISTENT | BACKUP},
|
|
||||||
{"HkgTuningOverridingCycles", PERSISTENT | BACKUP},
|
|
||||||
{"HkgAngleLiveTuning", CLEAR_ON_MANAGER_START}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
Submodule opendbc_repo updated: 682c5f274d...b68fab9ea4
+2
-1
@@ -59,7 +59,7 @@ dependencies = [
|
|||||||
"future-fstrings",
|
"future-fstrings",
|
||||||
|
|
||||||
# joystickd
|
# joystickd
|
||||||
"pygame",
|
"inputs",
|
||||||
|
|
||||||
# these should be removed
|
# these should be removed
|
||||||
"psutil",
|
"psutil",
|
||||||
@@ -108,6 +108,7 @@ dev = [
|
|||||||
"opencv-python-headless",
|
"opencv-python-headless",
|
||||||
"parameterized >=0.8, <0.9",
|
"parameterized >=0.8, <0.9",
|
||||||
"pyautogui",
|
"pyautogui",
|
||||||
|
"pygame",
|
||||||
"pyopencl; platform_machine != 'aarch64'", # broken on arm64
|
"pyopencl; platform_machine != 'aarch64'", # broken on arm64
|
||||||
"pytools < 2024.1.11; platform_machine != 'aarch64'", # pyopencl use a broken version
|
"pytools < 2024.1.11; platform_machine != 'aarch64'", # pyopencl use a broken version
|
||||||
"pywinctl",
|
"pywinctl",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ cd $ROOT
|
|||||||
|
|
||||||
FAILED=0
|
FAILED=0
|
||||||
|
|
||||||
IGNORED_FILES="uv\.lock|docs\/CARS.md|LICENSE\.md|layouts\/.*\.xml"
|
IGNORED_FILES="uv\.lock|docs\/CARS.md|LICENSE\.md"
|
||||||
IGNORED_DIRS="^third_party.*|^msgq.*|^msgq_repo.*|^opendbc.*|^opendbc_repo.*|^cereal.*|^panda.*|^rednose.*|^rednose_repo.*|^tinygrad.*|^tinygrad_repo.*|^teleoprtc.*|^teleoprtc_repo.*"
|
IGNORED_DIRS="^third_party.*|^msgq.*|^msgq_repo.*|^opendbc.*|^opendbc_repo.*|^cereal.*|^panda.*|^rednose.*|^rednose_repo.*|^tinygrad.*|^tinygrad_repo.*|^teleoprtc.*|^teleoprtc_repo.*"
|
||||||
|
|
||||||
function run() {
|
function run() {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ from openpilot.selfdrive.controls.lib.drive_helpers import clip_curvature
|
|||||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
||||||
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
|
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
|
||||||
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD
|
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD
|
||||||
from openpilot.selfdrive.controls.lib.latcontrol_angle_torque import LatControlAngleTorque
|
|
||||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||||
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
||||||
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
|
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
|
||||||
@@ -59,9 +58,7 @@ class Controls(ControlsExt):
|
|||||||
self.LoC = LongControl(self.CP)
|
self.LoC = LongControl(self.CP)
|
||||||
self.VM = VehicleModel(self.CP)
|
self.VM = VehicleModel(self.CP)
|
||||||
self.LaC: LatControl
|
self.LaC: LatControl
|
||||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle and self.CP.lateralTuning.which() == 'torque':
|
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||||
self.LaC = LatControlAngleTorque(self.CP, self.CP_SP, self.CI)
|
|
||||||
elif self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
|
||||||
self.LaC = LatControlAngle(self.CP, self.CP_SP, self.CI)
|
self.LaC = LatControlAngle(self.CP, self.CP_SP, self.CI)
|
||||||
elif self.CP.lateralTuning.which() == 'pid':
|
elif self.CP.lateralTuning.which() == 'pid':
|
||||||
self.LaC = LatControlPID(self.CP, self.CP_SP, self.CI)
|
self.LaC = LatControlPID(self.CP, self.CP_SP, self.CI)
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
|
||||||
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle
|
|
||||||
|
|
||||||
|
|
||||||
class LatControlAngleTorque(LatControlTorque, LatControlAngle):
|
|
||||||
def __init__(self, CP, CP_SP, CI):
|
|
||||||
LatControlTorque.__init__(self, CP, CP_SP, CI)
|
|
||||||
LatControlAngle.__init__(self, CP, CP_SP, CI)
|
|
||||||
|
|
||||||
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
|
||||||
torque, _, _ = LatControlTorque.update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited)
|
|
||||||
_, angle, angle_log = LatControlAngle.update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited)
|
|
||||||
return torque, angle, angle_log
|
|
||||||
@@ -90,7 +90,7 @@ class ModelState:
|
|||||||
prev_desire: np.ndarray # for tracking the rising edge of the pulse
|
prev_desire: np.ndarray # for tracking the rising edge of the pulse
|
||||||
|
|
||||||
def __init__(self, context: CLContext):
|
def __init__(self, context: CLContext):
|
||||||
self.LAT_SMOOTH_SECONDS = LAT_SMOOTH_SECONDS
|
self.LAT_SMOOTH_SECONDS = 0.0
|
||||||
with open(VISION_METADATA_PATH, 'rb') as f:
|
with open(VISION_METADATA_PATH, 'rb') as f:
|
||||||
vision_metadata = pickle.load(f)
|
vision_metadata = pickle.load(f)
|
||||||
self.vision_input_shapes = vision_metadata['input_shapes']
|
self.vision_input_shapes = vision_metadata['input_shapes']
|
||||||
|
|||||||
@@ -45,6 +45,17 @@ DeveloperPanel::DeveloperPanel(SettingsWindow *parent) : ListWidget(parent) {
|
|||||||
});
|
});
|
||||||
addItem(experimentalLongitudinalToggle);
|
addItem(experimentalLongitudinalToggle);
|
||||||
|
|
||||||
|
enableGithubRunner = new ParamControl("EnableGithubRunner", tr("Enable GitHub runner service"), tr("Enables or disables the github runner service."), "");
|
||||||
|
addItem(enableGithubRunner);
|
||||||
|
|
||||||
|
// error log button
|
||||||
|
errorLogBtn = new ButtonControl(tr("Error Log"), tr("VIEW"), tr("View the error log for sunnypilot crashes."));
|
||||||
|
connect(errorLogBtn, &ButtonControl::clicked, [=]() {
|
||||||
|
std::string txt = util::read_file("/data/community/crashes/error.log");
|
||||||
|
ConfirmationDialog::rich(QString::fromStdString(txt), this);
|
||||||
|
});
|
||||||
|
addItem(errorLogBtn);
|
||||||
|
|
||||||
// Joystick and longitudinal maneuvers should be hidden on release branches
|
// Joystick and longitudinal maneuvers should be hidden on release branches
|
||||||
is_release = params.getBool("IsReleaseBranch");
|
is_release = params.getBool("IsReleaseBranch");
|
||||||
|
|
||||||
@@ -93,6 +104,8 @@ void DeveloperPanel::updateToggles(bool _offroad) {
|
|||||||
experimentalLongitudinalToggle->refresh();
|
experimentalLongitudinalToggle->refresh();
|
||||||
|
|
||||||
// Handle specific controls visibility for release branches
|
// Handle specific controls visibility for release branches
|
||||||
|
enableGithubRunner->setVisible(!is_release);
|
||||||
|
errorLogBtn->setVisible(!is_release);
|
||||||
joystickToggle->setVisible(!is_release);
|
joystickToggle->setVisible(!is_release);
|
||||||
|
|
||||||
offroad = _offroad;
|
offroad = _offroad;
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ private:
|
|||||||
Params params;
|
Params params;
|
||||||
ParamControl* adbToggle;
|
ParamControl* adbToggle;
|
||||||
ParamControl* joystickToggle;
|
ParamControl* joystickToggle;
|
||||||
|
ButtonControl* errorLogBtn;
|
||||||
ParamControl* longManeuverToggle;
|
ParamControl* longManeuverToggle;
|
||||||
ParamControl* experimentalLongitudinalToggle;
|
ParamControl* experimentalLongitudinalToggle;
|
||||||
|
ParamControl* enableGithubRunner;
|
||||||
bool is_release;
|
bool is_release;
|
||||||
bool offroad = false;
|
bool offroad = false;
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ void ModelRenderer::draw(QPainter &painter, const QRect &surface_rect) {
|
|||||||
drawLead(painter, lead_two, lead_vertices[1], surface_rect);
|
drawLead(painter, lead_two, lead_vertices[1], surface_rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawLeadStatus(painter, surface_rect.height(), surface_rect.width());
|
|
||||||
|
|
||||||
painter.restore();
|
painter.restore();
|
||||||
}
|
}
|
||||||
@@ -174,173 +173,6 @@ QColor ModelRenderer::blendColors(const QColor &start, const QColor &end, float
|
|||||||
(1 - t) * start.alphaF() + t * end.alphaF());
|
(1 - t) * start.alphaF() + t * end.alphaF());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ModelRenderer::drawLeadStatus(QPainter &painter, int height, int width) {
|
|
||||||
auto *s = uiState();
|
|
||||||
auto &sm = *(s->sm);
|
|
||||||
|
|
||||||
if (!sm.alive("radarState")) return;
|
|
||||||
|
|
||||||
const auto &radar_state = sm["radarState"].getRadarState();
|
|
||||||
const auto &lead_one = radar_state.getLeadOne();
|
|
||||||
const auto &lead_two = radar_state.getLeadTwo();
|
|
||||||
|
|
||||||
// Check if we have any active leads
|
|
||||||
bool has_lead_one = lead_one.getStatus();
|
|
||||||
bool has_lead_two = lead_two.getStatus();
|
|
||||||
|
|
||||||
if (!has_lead_one && !has_lead_two) {
|
|
||||||
// Fade out status display
|
|
||||||
lead_status_alpha = std::max(0.0f, lead_status_alpha - 0.05f);
|
|
||||||
if (lead_status_alpha <= 0.0f) return;
|
|
||||||
} else {
|
|
||||||
// Fade in status display
|
|
||||||
lead_status_alpha = std::min(1.0f, lead_status_alpha + 0.1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw status for each lead vehicle under its chevron
|
|
||||||
if (true) {
|
|
||||||
drawLeadStatusAtPosition(painter, lead_one, lead_vertices[0], height, width, "L1");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_lead_two && std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0) {
|
|
||||||
drawLeadStatusAtPosition(painter, lead_two, lead_vertices[1], height, width, "L2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelRenderer::drawLeadStatusAtPosition(QPainter &painter,
|
|
||||||
const cereal::RadarState::LeadData::Reader &lead_data,
|
|
||||||
const QPointF &chevron_pos,
|
|
||||||
int height, int width,
|
|
||||||
const QString &label) {
|
|
||||||
|
|
||||||
float d_rel = lead_data.getDRel();
|
|
||||||
float v_rel = lead_data.getVRel();
|
|
||||||
auto *s = uiState();
|
|
||||||
auto &sm = *(s->sm);
|
|
||||||
float v_ego = sm["carState"].getCarState().getVEgo();
|
|
||||||
|
|
||||||
int chevron_data = std::atoi(Params().get("ChevronInfo").c_str());
|
|
||||||
|
|
||||||
// Calculate chevron size (same logic as drawLead)
|
|
||||||
float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * 2.35;
|
|
||||||
|
|
||||||
QFont content_font = painter.font();
|
|
||||||
content_font.setPixelSize(35);
|
|
||||||
content_font.setBold(true);
|
|
||||||
painter.setFont(content_font);
|
|
||||||
|
|
||||||
QFontMetrics fm(content_font);
|
|
||||||
bool is_metric = s->scene.is_metric;
|
|
||||||
|
|
||||||
QStringList text_lines;
|
|
||||||
|
|
||||||
const int chevron_types = 3;
|
|
||||||
const int chevron_all = chevron_types + 1; // All metrics (value 4)
|
|
||||||
QStringList chevron_text[chevron_types];
|
|
||||||
int position;
|
|
||||||
float val;
|
|
||||||
|
|
||||||
// Distance display (chevron_data == 1 or all)
|
|
||||||
if (chevron_data == 1 || chevron_data == chevron_all) {
|
|
||||||
position = 0;
|
|
||||||
val = std::max(0.0f, d_rel);
|
|
||||||
QString distance_unit = is_metric ? "m" : "ft";
|
|
||||||
if (!is_metric) {
|
|
||||||
val *= 3.28084f; // Convert meters to feet
|
|
||||||
}
|
|
||||||
chevron_text[position].append(QString::number(val, 'f', 0) + " " + distance_unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Absolute velocity display (chevron_data == 2 or all)
|
|
||||||
if (chevron_data == 2 || chevron_data == chevron_all) {
|
|
||||||
position = (chevron_data == 2) ? 0 : 1;
|
|
||||||
val = std::max(0.0f, (v_rel + v_ego) * (is_metric ? static_cast<float>(MS_TO_KPH) : static_cast<float>(MS_TO_MPH)));
|
|
||||||
chevron_text[position].append(QString::number(val, 'f', 0) + " " + (is_metric ? "km/h" : "mph"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time-to-contact display (chevron_data == 3 or all)
|
|
||||||
if (chevron_data == 3 || chevron_data == chevron_all) {
|
|
||||||
position = (chevron_data == 3) ? 0 : 2;
|
|
||||||
val = (d_rel > 0 && v_ego > 0) ? std::max(0.0f, d_rel / v_ego) : 0.0f;
|
|
||||||
QString ttc_str = (val > 0 && val < 200) ? QString::number(val, 'f', 1) + "s" : "---";
|
|
||||||
chevron_text[position].append(ttc_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect all non-empty text lines
|
|
||||||
for (int i = 0; i < chevron_types; ++i) {
|
|
||||||
if (!chevron_text[i].isEmpty()) {
|
|
||||||
text_lines.append(chevron_text[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no text to display, return early
|
|
||||||
if (text_lines.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text box dimensions
|
|
||||||
float str_w = 150; // Width of text area
|
|
||||||
float str_h = 45; // Height per line
|
|
||||||
|
|
||||||
// Position text below chevron, centered horizontally
|
|
||||||
float text_x = chevron_pos.x() - str_w / 2;
|
|
||||||
float text_y = chevron_pos.y() + sz + 15;
|
|
||||||
|
|
||||||
// Clamp to screen bounds
|
|
||||||
text_x = std::clamp(text_x, 10.0f, (float)width - str_w - 10);
|
|
||||||
|
|
||||||
// Shadow offset
|
|
||||||
QPoint shadow_offset(2, 2);
|
|
||||||
|
|
||||||
// Draw each line of text with shadow
|
|
||||||
for (int i = 0; i < text_lines.size(); ++i) {
|
|
||||||
if (!text_lines[i].isEmpty()) {
|
|
||||||
QRect textRect(text_x, text_y + (i * str_h), str_w, str_h);
|
|
||||||
|
|
||||||
// Draw shadow
|
|
||||||
painter.setPen(QColor(0x0, 0x0, 0x0, (int)(200 * lead_status_alpha)));
|
|
||||||
painter.drawText(textRect.translated(shadow_offset.x(), shadow_offset.y()),
|
|
||||||
Qt::AlignBottom | Qt::AlignHCenter, text_lines[i]);
|
|
||||||
|
|
||||||
// Determine text color based on content and danger level
|
|
||||||
QColor text_color;
|
|
||||||
|
|
||||||
// Check if this is a distance line (contains 'm' or 'ft')
|
|
||||||
if (text_lines[i].contains("m") || text_lines[i].contains("ft")) {
|
|
||||||
if (d_rel < 20.0f) {
|
|
||||||
text_color = QColor(255, 80, 80, (int)(255 * lead_status_alpha)); // Red - danger
|
|
||||||
} else if (d_rel < 40.0f) {
|
|
||||||
text_color = QColor(255, 200, 80, (int)(255 * lead_status_alpha)); // Yellow - caution
|
|
||||||
} else {
|
|
||||||
text_color = QColor(80, 255, 120, (int)(255 * lead_status_alpha)); // Green - safe
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Enhanced color coding for time-to-contact
|
|
||||||
else if (text_lines[i].contains("s") && !text_lines[i].contains("---")) {
|
|
||||||
float ttc_val = text_lines[i].left(text_lines[i].length() - 1).toFloat();
|
|
||||||
if (ttc_val < 3.0f) {
|
|
||||||
text_color = QColor(255, 80, 80, (int)(255 * lead_status_alpha)); // Red - urgent
|
|
||||||
} else if (ttc_val < 6.0f) {
|
|
||||||
text_color = QColor(255, 200, 80, (int)(255 * lead_status_alpha)); // Yellow - caution
|
|
||||||
} else {
|
|
||||||
text_color = QColor(0xff, 0xff, 0xff, (int)(255 * lead_status_alpha)); // White - safe
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
text_color = QColor(0xff, 0xff, 0xff, (int)(255 * lead_status_alpha)); // White for other lines
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw main text
|
|
||||||
painter.setPen(text_color);
|
|
||||||
painter.drawText(textRect, Qt::AlignBottom | Qt::AlignHCenter, text_lines[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset pen
|
|
||||||
painter.setPen(Qt::NoPen);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelRenderer::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data,
|
void ModelRenderer::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data,
|
||||||
const QPointF &vd, const QRect &surface_rect) {
|
const QPointF &vd, const QRect &surface_rect) {
|
||||||
const float speedBuff = 10.;
|
const float speedBuff = 10.;
|
||||||
|
|||||||
@@ -34,12 +34,6 @@ protected:
|
|||||||
bool mapToScreen(float in_x, float in_y, float in_z, QPointF *out);
|
bool mapToScreen(float in_x, float in_y, float in_z, QPointF *out);
|
||||||
void mapLineToPolygon(const cereal::XYZTData::Reader &line, float y_off, float z_off,
|
void mapLineToPolygon(const cereal::XYZTData::Reader &line, float y_off, float z_off,
|
||||||
QPolygonF *pvd, int max_idx, bool allow_invert = true);
|
QPolygonF *pvd, int max_idx, bool allow_invert = true);
|
||||||
void drawLeadStatus(QPainter &painter, int height, int width);
|
|
||||||
void drawLeadStatusAtPosition(QPainter &painter,
|
|
||||||
const cereal::RadarState::LeadData::Reader &lead_data,
|
|
||||||
const QPointF &chevron_pos,
|
|
||||||
int height, int width,
|
|
||||||
const QString &label);
|
|
||||||
void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, const QRect &surface_rect);
|
void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, const QRect &surface_rect);
|
||||||
void update_leads(const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line);
|
void update_leads(const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line);
|
||||||
virtual void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead);
|
virtual void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead);
|
||||||
@@ -64,9 +58,4 @@ protected:
|
|||||||
QPointF lead_vertices[2] = {};
|
QPointF lead_vertices[2] = {};
|
||||||
Eigen::Matrix3f car_space_transform = Eigen::Matrix3f::Zero();
|
Eigen::Matrix3f car_space_transform = Eigen::Matrix3f::Zero();
|
||||||
QRectF clip_region;
|
QRectF clip_region;
|
||||||
|
|
||||||
float lead_status_alpha = 0.0f;
|
|
||||||
QPointF lead_status_pos;
|
|
||||||
QString lead_status_text;
|
|
||||||
QColor lead_status_color;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
#include <QScroller>
|
|
||||||
|
|
||||||
#include "system/hardware/hw.h"
|
#include "system/hardware/hw.h"
|
||||||
#include "selfdrive/ui/qt/util.h"
|
#include "selfdrive/ui/qt/util.h"
|
||||||
@@ -335,141 +334,3 @@ QString MultiOptionDialog::getSelection(const QString &prompt_text, const QStrin
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeOptionDialog::TreeOptionDialog(const QString &prompt_text, const QList<QPair<QString, QStringList>> &items,
|
|
||||||
const QString ¤t, QWidget *parent) : DialogBase(parent) {
|
|
||||||
QFrame *container = new QFrame(this);
|
|
||||||
container->setStyleSheet(R"(
|
|
||||||
QFrame { background-color: #1B1B1B; }
|
|
||||||
#confirm_btn[enabled="false"] { background-color: #2B2B2B; }
|
|
||||||
#confirm_btn:enabled { background-color: #465BEA; }
|
|
||||||
#confirm_btn:enabled:pressed { background-color: #3049F4; }
|
|
||||||
QTreeWidget {
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
QTreeWidget::item {
|
|
||||||
height: 135;
|
|
||||||
padding: 0px 50px;
|
|
||||||
margin: 5px;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 55px;
|
|
||||||
font-weight: 300;
|
|
||||||
border-radius: 10px;
|
|
||||||
background-color: #4F4F4F;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
QTreeWidget::item:selected {
|
|
||||||
background-color: #465BEA;
|
|
||||||
}
|
|
||||||
QTreeWidget::branch {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
)");
|
|
||||||
|
|
||||||
QVBoxLayout *main_layout = new QVBoxLayout(container);
|
|
||||||
main_layout->setContentsMargins(55, 50, 55, 50);
|
|
||||||
|
|
||||||
QLabel *title = new QLabel(prompt_text, this);
|
|
||||||
title->setStyleSheet("font-size: 70px; font-weight: 500;");
|
|
||||||
main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);
|
|
||||||
main_layout->addSpacing(25);
|
|
||||||
|
|
||||||
treeWidget = new QTreeWidget(this);
|
|
||||||
treeWidget->setHeaderHidden(true);
|
|
||||||
treeWidget->setIndentation(50);
|
|
||||||
treeWidget->setExpandsOnDoubleClick(false); // Disable double-click expansion
|
|
||||||
treeWidget->setAnimated(true);
|
|
||||||
treeWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
treeWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
treeWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
|
||||||
treeWidget->setDragEnabled(false);
|
|
||||||
treeWidget->setMouseTracking(true);
|
|
||||||
|
|
||||||
// Connect single-click to expand/collapse
|
|
||||||
QObject::connect(treeWidget, &QTreeWidget::itemClicked, [=](QTreeWidgetItem *item, int) {
|
|
||||||
if (item->childCount() > 0) {
|
|
||||||
item->setExpanded(!item->isExpanded());
|
|
||||||
treeWidget->scrollToItem(item->child(0), QAbstractItemView::EnsureVisible);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
QScroller::grabGesture(treeWidget->viewport(), QScroller::LeftMouseButtonGesture);
|
|
||||||
|
|
||||||
// Populate tree
|
|
||||||
QListIterator<QPair<QString, QStringList>> iter(items);
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
QPair currItem = iter.next();
|
|
||||||
if (currItem.first.isEmpty()) {
|
|
||||||
for (const QString &item : currItem.second) {
|
|
||||||
QTreeWidgetItem *topLevel = new QTreeWidgetItem();
|
|
||||||
topLevel->setText(0, item);
|
|
||||||
topLevel->setFlags(topLevel->flags() | Qt::ItemIsSelectable);
|
|
||||||
treeWidget->addTopLevelItem(topLevel);
|
|
||||||
if (item == current) {
|
|
||||||
topLevel->setSelected(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QTreeWidgetItem *folderItem = new QTreeWidgetItem(treeWidget);
|
|
||||||
folderItem->setIcon(0, QIcon(QPixmap("../assets/icons/menu.png")));
|
|
||||||
folderItem->setText(0, " " + currItem.first);
|
|
||||||
folderItem->setFlags(folderItem->flags() | Qt::ItemIsAutoTristate);
|
|
||||||
folderItem->setFlags(folderItem->flags() & ~Qt::ItemIsSelectable);
|
|
||||||
|
|
||||||
for (const QString &item : currItem.second)
|
|
||||||
{
|
|
||||||
QTreeWidgetItem *childItem = new QTreeWidgetItem(folderItem);
|
|
||||||
childItem->setText(0, item);
|
|
||||||
childItem->setFlags(childItem->flags() | Qt::ItemIsSelectable);
|
|
||||||
|
|
||||||
if (item == current) {
|
|
||||||
childItem->setSelected(true);
|
|
||||||
folderItem->setExpanded(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
confirm_btn = new QPushButton(tr("Select"));
|
|
||||||
confirm_btn->setObjectName("confirm_btn");
|
|
||||||
confirm_btn->setEnabled(false);
|
|
||||||
|
|
||||||
QObject::connect(treeWidget, &QTreeWidget::itemSelectionChanged, [=]() {
|
|
||||||
QList<QTreeWidgetItem*> selectedItems = treeWidget->selectedItems();
|
|
||||||
if (!selectedItems.isEmpty()) {
|
|
||||||
selection = selectedItems.first()->text(0);
|
|
||||||
confirm_btn->setEnabled(selection != current);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ScrollView *scroll_view = new ScrollView(treeWidget, this);
|
|
||||||
scroll_view->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
|
||||||
|
|
||||||
main_layout->addWidget(scroll_view);
|
|
||||||
main_layout->addSpacing(35);
|
|
||||||
|
|
||||||
// cancel + confirm buttons
|
|
||||||
QHBoxLayout *blayout = new QHBoxLayout;
|
|
||||||
main_layout->addLayout(blayout);
|
|
||||||
blayout->setSpacing(50);
|
|
||||||
|
|
||||||
QPushButton *cancel_btn = new QPushButton(tr("Cancel"));
|
|
||||||
QObject::connect(cancel_btn, &QPushButton::clicked, this, &ConfirmationDialog::reject);
|
|
||||||
QObject::connect(confirm_btn, &QPushButton::clicked, this, &ConfirmationDialog::accept);
|
|
||||||
blayout->addWidget(cancel_btn);
|
|
||||||
blayout->addWidget(confirm_btn);
|
|
||||||
|
|
||||||
QVBoxLayout *outer_layout = new QVBoxLayout(this);
|
|
||||||
outer_layout->setContentsMargins(50, 50, 50, 50);
|
|
||||||
outer_layout->addWidget(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TreeOptionDialog::getSelection(const QString &prompt_text, const QList<QPair<QString, QStringList>> &items,
|
|
||||||
const QString ¤t, QWidget *parent) {
|
|
||||||
TreeOptionDialog d(prompt_text, items, current, parent);
|
|
||||||
if (d.exec()) {
|
|
||||||
return d.selection;
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QTreeWidget>
|
|
||||||
|
|
||||||
#include "selfdrive/ui/qt/widgets/keyboard.h"
|
#include "selfdrive/ui/qt/widgets/keyboard.h"
|
||||||
|
|
||||||
@@ -70,16 +69,3 @@ public:
|
|||||||
static QString getSelection(const QString &prompt_text, const QStringList &l, const QString ¤t, QWidget *parent);
|
static QString getSelection(const QString &prompt_text, const QStringList &l, const QString ¤t, QWidget *parent);
|
||||||
QString selection;
|
QString selection;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TreeOptionDialog : public DialogBase {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit TreeOptionDialog(const QString &prompt_text, const QList<QPair<QString, QStringList>> &items, const QString ¤t, QWidget *parent = nullptr);
|
|
||||||
static QString getSelection(const QString &prompt_text, const QList<QPair<QString, QStringList>> &items, const QString ¤t, QWidget *parent = nullptr);
|
|
||||||
QString selection;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QTreeWidget *treeWidget;
|
|
||||||
QPushButton *confirm_btn;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ qt_src = [
|
|||||||
"sunnypilot/qt/home.cc",
|
"sunnypilot/qt/home.cc",
|
||||||
"sunnypilot/qt/offroad/exit_offroad_button.cc",
|
"sunnypilot/qt/offroad/exit_offroad_button.cc",
|
||||||
"sunnypilot/qt/offroad/offroad_home.cc",
|
"sunnypilot/qt/offroad/offroad_home.cc",
|
||||||
"sunnypilot/qt/offroad/settings/developer_panel.cc",
|
|
||||||
"sunnypilot/qt/offroad/settings/device_panel.cc",
|
"sunnypilot/qt/offroad/settings/device_panel.cc",
|
||||||
"sunnypilot/qt/offroad/settings/lateral_panel.cc",
|
"sunnypilot/qt/offroad/settings/lateral_panel.cc",
|
||||||
"sunnypilot/qt/offroad/settings/longitudinal_panel.cc",
|
"sunnypilot/qt/offroad/settings/longitudinal_panel.cc",
|
||||||
@@ -47,7 +46,6 @@ lateral_panel_qt_src = [
|
|||||||
"sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.cc",
|
"sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.cc",
|
||||||
"sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc",
|
"sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc",
|
||||||
"sunnypilot/qt/offroad/settings/lateral/mads_settings.cc",
|
"sunnypilot/qt/offroad/settings/lateral/mads_settings.cc",
|
||||||
"sunnypilot/qt/offroad/settings/lateral/angle_tuning_settings.cc",
|
|
||||||
"sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc",
|
"sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
|
||||||
*
|
|
||||||
* This file is part of sunnypilot and is licensed under the MIT License.
|
|
||||||
* See the LICENSE.md file in the root directory for more details.
|
|
||||||
*/
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h"
|
|
||||||
|
|
||||||
DeveloperPanelSP::DeveloperPanelSP(SettingsWindow *parent) : DeveloperPanel(parent) {
|
|
||||||
|
|
||||||
// Advanced Controls Toggle
|
|
||||||
showAdvancedControls = new ParamControlSP("ShowAdvancedControls", tr("Show Advanced Controls"), tr("Toggle visibility of advanced sunnypilot controls.\nThis only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state."), "");
|
|
||||||
addItem(showAdvancedControls);
|
|
||||||
|
|
||||||
QObject::connect(showAdvancedControls, &ParamControlSP::toggleFlipped, this, [=](bool) {
|
|
||||||
AbstractControlSP::UpdateAllAdvancedControls();
|
|
||||||
updateToggles(!uiState()->scene.started);
|
|
||||||
});
|
|
||||||
showAdvancedControls->showDescription();
|
|
||||||
|
|
||||||
// Github Runner Toggle
|
|
||||||
enableGithubRunner = new ParamControlSP("EnableGithubRunner", tr("Enable GitHub runner service"), tr("Enables or disables the github runner service."), "", this, true);
|
|
||||||
addItem(enableGithubRunner);
|
|
||||||
|
|
||||||
// Quickboot Mode Toggle
|
|
||||||
prebuiltToggle = new ParamControlSP("QuickBootToggle", tr("Enable Quickboot Mode"), tr(""), "", this, true);
|
|
||||||
addItem(prebuiltToggle);
|
|
||||||
|
|
||||||
QObject::connect(prebuiltToggle, &ParamControl::toggleFlipped, [=](bool state) {
|
|
||||||
QString prebuiltPath = "/data/openpilot/prebuilt";
|
|
||||||
state ? QFile(prebuiltPath).open(QIODevice::WriteOnly) : QFile::remove(prebuiltPath);
|
|
||||||
prebuiltToggle->refresh();
|
|
||||||
});
|
|
||||||
prebuiltToggle->setVisible(false);
|
|
||||||
|
|
||||||
// Error log button
|
|
||||||
errorLogBtn = new ButtonControlSP(tr("Error Log"), tr("VIEW"), tr("View the error log for sunnypilot crashes."));
|
|
||||||
connect(errorLogBtn, &ButtonControlSP::clicked, [=]() {
|
|
||||||
QFileInfo file("/data/community/crashes/error.log");
|
|
||||||
QString text;
|
|
||||||
if (file.exists()) {
|
|
||||||
text = "<b>" + file.lastModified().toString("dd-MMM-yyyy hh:mm:ss ").toUpper() + "</b><br><br>";
|
|
||||||
}
|
|
||||||
text += QString::fromStdString(util::read_file("/data/community/crashes/error.log"));
|
|
||||||
ConfirmationDialog::rich(text, this);
|
|
||||||
});
|
|
||||||
addItem(errorLogBtn);
|
|
||||||
|
|
||||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &DeveloperPanelSP::updateToggles);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeveloperPanelSP::updateToggles(bool offroad) {
|
|
||||||
bool is_release = params.getBool("IsReleaseBranch");
|
|
||||||
bool is_tested = params.getBool("IsTestedBranch");
|
|
||||||
bool is_development = params.getBool("IsDevelopmentBranch");
|
|
||||||
bool disable_updates = params.getBool("DisableUpdates");
|
|
||||||
|
|
||||||
prebuiltToggle->setVisible(!is_release && !is_tested && !is_development);
|
|
||||||
prebuiltToggle->setEnabled(disable_updates);
|
|
||||||
|
|
||||||
params.putBool("QuickBootToggle", QFile::exists("/data/openpilot/prebuilt"));
|
|
||||||
prebuiltToggle->refresh();
|
|
||||||
|
|
||||||
prebuiltToggle->setDescription(disable_updates
|
|
||||||
? tr("When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, "
|
|
||||||
"it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. "
|
|
||||||
"<br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b>")
|
|
||||||
: tr("Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first."));
|
|
||||||
|
|
||||||
enableGithubRunner->setVisible(!is_release);
|
|
||||||
errorLogBtn->setVisible(!is_release);
|
|
||||||
showAdvancedControls->setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeveloperPanelSP::showEvent(QShowEvent *event) {
|
|
||||||
DeveloperPanel::showEvent(event);
|
|
||||||
updateToggles(!uiState()->scene.started);
|
|
||||||
AbstractControlSP::UpdateAllAdvancedControls();
|
|
||||||
prebuiltToggle->showDescription();
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
|
||||||
*
|
|
||||||
* This file is part of sunnypilot and is licensed under the MIT License.
|
|
||||||
* See the LICENSE.md file in the root directory for more details.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <QFile>
|
|
||||||
#include <QFileInfo>
|
|
||||||
|
|
||||||
#include "selfdrive/ui/qt/offroad/developer_panel.h"
|
|
||||||
|
|
||||||
class DeveloperPanelSP : public DeveloperPanel {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit DeveloperPanelSP(SettingsWindow *parent);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ParamControlSP *enableGithubRunner;
|
|
||||||
ButtonControlSP *errorLogBtn;
|
|
||||||
ParamControlSP *prebuiltToggle;
|
|
||||||
Params params;
|
|
||||||
ParamControlSP *showAdvancedControls;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void updateToggles(bool offroad);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void showEvent(QShowEvent *event) override;
|
|
||||||
};
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
|
||||||
*
|
|
||||||
* This file is part of sunnypilot and is licensed under the MIT License.
|
|
||||||
* See the LICENSE.md file in the root directory for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/angle_tuning_settings.h"
|
|
||||||
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
|
||||||
|
|
||||||
AngleTunningSettings::AngleTunningSettings(QWidget *parent) : QWidget(parent) {
|
|
||||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
|
||||||
main_layout->setContentsMargins(50, 20, 50, 20);
|
|
||||||
main_layout->setSpacing(20);
|
|
||||||
|
|
||||||
// Back button
|
|
||||||
PanelBackButton *back = new PanelBackButton();
|
|
||||||
connect(back, &QPushButton::clicked, [=]() { emit backPress(); });
|
|
||||||
main_layout->addWidget(back, 0, Qt::AlignLeft);
|
|
||||||
|
|
||||||
auto *list = new ListWidgetSP(this, false);
|
|
||||||
|
|
||||||
main_layout->addWidget(new QWidget());
|
|
||||||
|
|
||||||
enableHkgAngleSmoothingFactor = new ExpandableToggleRow("EnableHkgTuningAngleSmoothingFactor", tr("HKG Angle Smoothing Factor"), tr("Applies EMA (Exponential Moving Average) to the desired angle steering and avoid overcorrections."), "../assets/offroad/icon_blank.png");
|
|
||||||
list->addItem(enableHkgAngleSmoothingFactor);
|
|
||||||
|
|
||||||
auto first_row = new QHBoxLayout();
|
|
||||||
hkgTuningOverridingCycles = new OptionControlSP("HkgTuningOverridingCycles", tr("Override Ramp-Down Cycles"), tr("Number of cycles to ramp down the current amount of torque on the steering wheel.<br/>A smaller value means a faster override by the user (less effort)"), "../assets/offroad/icon_blank.png", {10, 30}, 1);
|
|
||||||
connect(hkgTuningOverridingCycles, &OptionControlSP::updateLabels, hkgTuningOverridingCycles, [=]() {
|
|
||||||
this->updateToggles(offroad);
|
|
||||||
});
|
|
||||||
first_row->addWidget(hkgTuningOverridingCycles);
|
|
||||||
|
|
||||||
hkgAngleMinTorque = new OptionControlSP("HkgTuningAngleMinTorqueReductionGain", tr("Override Steering Effort"), tr("Sets the steering effort percentage used when the driver is overriding lateral control.<br/>Higher values increase resistance and make the wheel feel stiffer."), "../assets/offroad/icon_blank.png", {5, 60}, 1);
|
|
||||||
connect(hkgAngleMinTorque, &OptionControlSP::updateLabels, hkgAngleMinTorque, [=]() {
|
|
||||||
this->updateToggles(offroad);
|
|
||||||
});
|
|
||||||
first_row->addWidget(hkgAngleMinTorque);
|
|
||||||
list->addItem(first_row);
|
|
||||||
|
|
||||||
auto second_row = new QHBoxLayout();
|
|
||||||
hkgAngleActiveTorque = new OptionControlSP("HkgTuningAngleActiveTorqueReductionGain", tr("Min Active Torque"), tr("Torque applied when lateral control is active but the vehicle is not turning.<br/>Used to maintain lane centering on straight paths when no user input is detected."), "../assets/offroad/icon_blank.png", {10, 100}, 1);
|
|
||||||
connect(hkgAngleActiveTorque, &OptionControlSP::updateLabels, hkgAngleActiveTorque, [=]() {
|
|
||||||
this->updateToggles(offroad);
|
|
||||||
});
|
|
||||||
second_row->addWidget(hkgAngleActiveTorque);
|
|
||||||
|
|
||||||
hkgAngleMaxTorque = new OptionControlSP("HkgTuningAngleMaxTorqueReductionGain", tr("Max Torque Allowance"), tr("Sets the maximum torque reduction percentage the controller can apply during normal lateral control.<br/>"), "../assets/offroad/icon_blank.png", {10, 100}, 1);
|
|
||||||
connect(hkgAngleMaxTorque, &OptionControlSP::updateLabels, hkgAngleMaxTorque, [=]() {
|
|
||||||
this->updateToggles(offroad);
|
|
||||||
});
|
|
||||||
second_row->addWidget(hkgAngleMaxTorque);
|
|
||||||
list->addItem(second_row);
|
|
||||||
|
|
||||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &AngleTunningSettings::updateToggles);
|
|
||||||
|
|
||||||
main_layout->addWidget(new ScrollViewSP(list, this));
|
|
||||||
|
|
||||||
auto *warning = new QLabel(tr("Reboot required for settings to apply; Tap on each setting to see more details."));
|
|
||||||
warning->setStyleSheet("font-size: 30px; font-weight: 500; font-family: 'Noto Color Emoji'; color: orange;");
|
|
||||||
main_layout->addWidget(warning, 0, Qt::AlignCenter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AngleTunningSettings::showEvent(QShowEvent *event) {
|
|
||||||
updateToggles(offroad);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AngleTunningSettings::updateToggles(bool _offroad) {
|
|
||||||
auto HkgAngleSmoothingFactorValue = params.getBool("EnableHkgTuningAngleSmoothingFactor");
|
|
||||||
enableHkgAngleSmoothingFactor->toggleFlipped(HkgAngleSmoothingFactorValue);
|
|
||||||
|
|
||||||
auto HkgAngleMinTorqueValue = QString::fromStdString(params.get("HkgTuningAngleMinTorqueReductionGain")).toInt();
|
|
||||||
hkgAngleMinTorque->setLabel(QString::number(HkgAngleMinTorqueValue)+"%");
|
|
||||||
|
|
||||||
auto HkgAngleActiveTorqueValue = QString::fromStdString(params.get("HkgTuningAngleActiveTorqueReductionGain")).toInt();
|
|
||||||
hkgAngleActiveTorque->setLabel(QString::number(HkgAngleActiveTorqueValue)+"%");
|
|
||||||
|
|
||||||
auto HkgAngleMaxTorqueValue = QString::fromStdString(params.get("HkgTuningAngleMaxTorqueReductionGain")).toInt();
|
|
||||||
hkgAngleMaxTorque->setLabel(QString::number(HkgAngleMaxTorqueValue)+"%");
|
|
||||||
|
|
||||||
auto HkgTuningOverridingCyclesValue = QString::fromStdString(params.get("HkgTuningOverridingCycles")).toInt();
|
|
||||||
hkgTuningOverridingCycles->setLabel(QString::number(HkgTuningOverridingCyclesValue));
|
|
||||||
|
|
||||||
offroad = _offroad;
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
|
||||||
*
|
|
||||||
* This file is part of sunnypilot and is licensed under the MIT License.
|
|
||||||
* See the LICENSE.md file in the root directory for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "selfdrive/ui/qt/util.h"
|
|
||||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h"
|
|
||||||
|
|
||||||
class AngleTunningSettings : public QWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AngleTunningSettings(QWidget *parent = nullptr);
|
|
||||||
|
|
||||||
void showEvent(QShowEvent *event) override;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void backPress();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void updateToggles(bool _offroad);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Params params;
|
|
||||||
bool offroad;
|
|
||||||
|
|
||||||
ExpandableToggleRow* enableHkgAngleSmoothingFactor;
|
|
||||||
OptionControlSP* hkgAngleMinTorque;
|
|
||||||
OptionControlSP* hkgAngleActiveTorque;
|
|
||||||
OptionControlSP* hkgAngleMaxTorque;
|
|
||||||
OptionControlSP* hkgTuningOverridingCycles;
|
|
||||||
ParamControlSP* hkgAngleLiveTuning;
|
|
||||||
};
|
|
||||||
@@ -89,36 +89,6 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
|
|||||||
nnlcToggle->updateToggle();
|
nnlcToggle->updateToggle();
|
||||||
});
|
});
|
||||||
|
|
||||||
#pragma region hkg angle tuning
|
|
||||||
list->addItem(vertical_space());
|
|
||||||
list->addItem(horizontal_line());
|
|
||||||
list->addItem(vertical_space());
|
|
||||||
|
|
||||||
// HKG Angle Tuning
|
|
||||||
// angleTuningToggle = new ParamControl(
|
|
||||||
// "AngleTuning",
|
|
||||||
// tr("Modular Assistive Driving System (MADS)"),
|
|
||||||
// tr("Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement."),
|
|
||||||
// "");
|
|
||||||
// angleTuningToggle->setConfirmation(true, false);
|
|
||||||
// list->addItem(angleTuningToggle);
|
|
||||||
|
|
||||||
angleTuningSettingsButton = new PushButtonSP(tr("Customize ANGLE Tuning"));
|
|
||||||
angleTuningSettingsButton->setObjectName("angle_btn");
|
|
||||||
connect(angleTuningSettingsButton, &QPushButton::clicked, [=]() {
|
|
||||||
sunnypilotScroller->setLastScrollPosition();
|
|
||||||
main_layout->setCurrentWidget(angleTuningWidget);
|
|
||||||
});
|
|
||||||
// QObject::connect(angleTuningToggle, &ToggleControl::toggleFlipped, angleTuningSettingsButton, &PushButtonSP::setEnabled);
|
|
||||||
|
|
||||||
angleTuningWidget = new AngleTunningSettings(this);
|
|
||||||
connect(angleTuningWidget, &AngleTunningSettings::backPress, [=]() {
|
|
||||||
sunnypilotScroller->restoreScrollPosition();
|
|
||||||
main_layout->setCurrentWidget(sunnypilotScreen);
|
|
||||||
});
|
|
||||||
list->addItem(angleTuningSettingsButton);
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
toggleOffroadOnly = {
|
toggleOffroadOnly = {
|
||||||
madsToggle, nnlcToggle,
|
madsToggle, nnlcToggle,
|
||||||
};
|
};
|
||||||
@@ -129,7 +99,6 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
|
|||||||
|
|
||||||
main_layout->addWidget(sunnypilotScreen);
|
main_layout->addWidget(sunnypilotScreen);
|
||||||
main_layout->addWidget(madsWidget);
|
main_layout->addWidget(madsWidget);
|
||||||
main_layout->addWidget(angleTuningWidget);
|
|
||||||
main_layout->addWidget(laneChangeWidget);
|
main_layout->addWidget(laneChangeWidget);
|
||||||
|
|
||||||
setStyleSheet(R"(
|
setStyleSheet(R"(
|
||||||
@@ -180,7 +149,6 @@ void LateralPanel::updateToggles(bool _offroad) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
madsSettingsButton->setEnabled(madsToggle->isToggled());
|
madsSettingsButton->setEnabled(madsToggle->isToggled());
|
||||||
// angleTuningSettingsButton->setEnabled(angleTuningToggle->isToggled());
|
|
||||||
|
|
||||||
blinkerPauseLateralSettings->refresh();
|
blinkerPauseLateralSettings->refresh();
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/angle_tuning_settings.h"
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h"
|
||||||
#include "selfdrive/ui/qt/util.h"
|
#include "selfdrive/ui/qt/util.h"
|
||||||
@@ -40,11 +39,8 @@ private:
|
|||||||
bool offroad;
|
bool offroad;
|
||||||
|
|
||||||
ParamControl *madsToggle;
|
ParamControl *madsToggle;
|
||||||
// ParamControl *angleTuningToggle;
|
|
||||||
PushButtonSP *madsSettingsButton;
|
PushButtonSP *madsSettingsButton;
|
||||||
PushButtonSP *angleTuningSettingsButton;
|
|
||||||
MadsSettings *madsWidget = nullptr;
|
MadsSettings *madsWidget = nullptr;
|
||||||
AngleTunningSettings *angleTuningWidget = nullptr;
|
|
||||||
PushButtonSP *laneChangeSettingsButton;
|
PushButtonSP *laneChangeSettingsButton;
|
||||||
LaneChangeSettings *laneChangeWidget = nullptr;
|
LaneChangeSettings *laneChangeWidget = nullptr;
|
||||||
NeuralNetworkLateralControl *nnlcToggle = nullptr;
|
NeuralNetworkLateralControl *nnlcToggle = nullptr;
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QtConcurrent/QtConcurrent>
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
#include "common/model.h"
|
#include "common/model.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h"
|
||||||
@@ -68,11 +66,6 @@ ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) {
|
|||||||
connect(uiStateSP(), &UIStateSP::uiUpdate, this, &ModelsPanel::updateLabels);
|
connect(uiStateSP(), &UIStateSP::uiUpdate, this, &ModelsPanel::updateLabels);
|
||||||
list->addItem(currentModelLblBtn);
|
list->addItem(currentModelLblBtn);
|
||||||
|
|
||||||
clearModelCacheBtn = new ButtonControlSP(tr("Clear Model Cache"), tr("CLEAR"), "", this);
|
|
||||||
connect(clearModelCacheBtn, &ButtonControlSP::clicked, this, &ModelsPanel::clearModelCache);
|
|
||||||
|
|
||||||
list->addItem(clearModelCacheBtn);
|
|
||||||
|
|
||||||
// Create progress bars for downloads
|
// Create progress bars for downloads
|
||||||
supercomboProgressBar = createProgressBar(this);
|
supercomboProgressBar = createProgressBar(this);
|
||||||
QString supercomboType = tr("Driving Model");
|
QString supercomboType = tr("Driving Model");
|
||||||
@@ -96,6 +89,14 @@ ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) {
|
|||||||
|
|
||||||
list->addItem(horizontal_line());
|
list->addItem(horizontal_line());
|
||||||
|
|
||||||
|
// Dynamic Modeld Outputs toggle
|
||||||
|
dynamicModeldOutputs = new ParamControlSP("DynamicModeldOutputs", tr("Allow Dynamic Model Outputs"),
|
||||||
|
tr("Enable this to allow potentially smoother Gas and Brake controls on all models produced "
|
||||||
|
"after September, 2024."),
|
||||||
|
"../assets/offroad/icon_shell.png");
|
||||||
|
dynamicModeldOutputs->showDescription();
|
||||||
|
list->addItem(dynamicModeldOutputs);
|
||||||
|
|
||||||
// LiveDelay toggle
|
// LiveDelay toggle
|
||||||
lagd_toggle_control = new ParamControlSP("LagdToggle", tr("Live Learning Steer Delay"), "", "../assets/offroad/icon_shell.png");
|
lagd_toggle_control = new ParamControlSP("LagdToggle", tr("Live Learning Steer Delay"), "", "../assets/offroad/icon_shell.png");
|
||||||
lagd_toggle_control->showDescription();
|
lagd_toggle_control->showDescription();
|
||||||
@@ -105,7 +106,7 @@ ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) {
|
|||||||
delay_control = new OptionControlSP("LagdToggledelay", tr("Adjust Software Delay"),
|
delay_control = new OptionControlSP("LagdToggledelay", tr("Adjust Software Delay"),
|
||||||
tr("Adjust the software delay when Live Learning Steer Delay is toggled off."
|
tr("Adjust the software delay when Live Learning Steer Delay is toggled off."
|
||||||
"\nThe default software delay value is 0.2"),
|
"\nThe default software delay value is 0.2"),
|
||||||
"", {5, 30}, 1, false, nullptr, true, true);
|
"", {10, 30}, 1, false, nullptr, true);
|
||||||
|
|
||||||
connect(delay_control, &OptionControlSP::updateLabels, [=]() {
|
connect(delay_control, &OptionControlSP::updateLabels, [=]() {
|
||||||
float value = QString::fromStdString(params.get("LagdToggledelay")).toFloat();
|
float value = QString::fromStdString(params.get("LagdToggledelay")).toFloat();
|
||||||
@@ -251,73 +252,28 @@ void ModelsPanel::handleCurrentModelLblBtnClicked() {
|
|||||||
currentModelLblBtn->setEnabled(false);
|
currentModelLblBtn->setEnabled(false);
|
||||||
currentModelLblBtn->setValue(tr("Fetching models..."));
|
currentModelLblBtn->setValue(tr("Fetching models..."));
|
||||||
|
|
||||||
struct ModelEntry {
|
// Create mapping of bundle indices to display names
|
||||||
QString folder;
|
QMap<uint32_t, QString> index_to_bundle;
|
||||||
QString displayName;
|
|
||||||
int index;
|
|
||||||
};
|
|
||||||
QList<ModelEntry> sortedModels;
|
|
||||||
QSet<QString> modelFolders;
|
|
||||||
const auto bundles = model_manager.getAvailableBundles();
|
const auto bundles = model_manager.getAvailableBundles();
|
||||||
|
for (const auto &bundle: bundles) {
|
||||||
for (const auto &bundle : bundles) {
|
index_to_bundle.insert(bundle.getIndex(), QString::fromStdString(bundle.getDisplayName()));
|
||||||
auto overrides = bundle.getOverrides();
|
|
||||||
QString gen;
|
|
||||||
for (const auto &override : overrides) {
|
|
||||||
if (override.getKey() == "folder") {
|
|
||||||
gen = QString::fromStdString(override.getValue().cStr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modelFolders.insert(gen);
|
|
||||||
sortedModels.append(ModelEntry{
|
|
||||||
gen,
|
|
||||||
QString::fromStdString(bundle.getDisplayName()),
|
|
||||||
static_cast<int>(bundle.getIndex())
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(sortedModels.begin(), sortedModels.end(),
|
// Sort bundles by index in descending order
|
||||||
[](const ModelEntry &a, const ModelEntry &b) {
|
QStringList bundleNames;
|
||||||
return a.index > b.index;
|
// Add "Default" as the first option
|
||||||
});
|
bundleNames.append(DEFAULT_MODEL);
|
||||||
|
|
||||||
// Create a list of folder-maxIndex pairs for sorting
|
auto indices = index_to_bundle.keys();
|
||||||
QList<QPair<QString, int>> folderMaxIndices;
|
std::sort(indices.begin(), indices.end(), std::greater<uint32_t>());
|
||||||
for (const auto &folder : modelFolders) {
|
for (const auto &index: indices) {
|
||||||
int maxIndex = -1;
|
bundleNames.append(index_to_bundle[index]);
|
||||||
for (const auto &model : sortedModels) {
|
|
||||||
if (model.folder == folder) {
|
|
||||||
maxIndex = std::max(maxIndex, model.index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
folderMaxIndices.append(qMakePair(folder, maxIndex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort folders by their highest model index
|
|
||||||
std::sort(folderMaxIndices.begin(), folderMaxIndices.end(),
|
|
||||||
[](const QPair<QString, int> &a, const QPair<QString, int> &b) {
|
|
||||||
return a.second > b.second;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create the final items list using sorted folders
|
|
||||||
QList<QPair<QString, QStringList>> items;
|
|
||||||
for (const auto &folderPair : folderMaxIndices) {
|
|
||||||
QStringList folderModels;
|
|
||||||
for (const auto &model : sortedModels) {
|
|
||||||
if (model.folder == folderPair.first) {
|
|
||||||
folderModels.append(model.displayName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
items.append(qMakePair(folderPair.first, folderModels));
|
|
||||||
}
|
|
||||||
|
|
||||||
items.insert(0, qMakePair(QString(""), QStringList{DEFAULT_MODEL}));
|
|
||||||
|
|
||||||
currentModelLblBtn->setValue(GetActiveModelInternalName());
|
currentModelLblBtn->setValue(GetActiveModelInternalName());
|
||||||
|
|
||||||
const QString selectedBundleName = TreeOptionDialog::getSelection(
|
const QString selectedBundleName = MultiOptionDialog::getSelection(
|
||||||
tr("Select a Model"), items, GetActiveModelName(), this);
|
tr("Select a Model"), bundleNames, GetActiveModelName(), this);
|
||||||
|
|
||||||
if (selectedBundleName.isEmpty() || !canContinueOnMeteredDialog()) {
|
if (selectedBundleName.isEmpty() || !canContinueOnMeteredDialog()) {
|
||||||
return;
|
return;
|
||||||
@@ -356,6 +312,7 @@ void ModelsPanel::updateLabels() {
|
|||||||
handleBundleDownloadProgress();
|
handleBundleDownloadProgress();
|
||||||
currentModelLblBtn->setEnabled(!is_onroad && !isDownloading());
|
currentModelLblBtn->setEnabled(!is_onroad && !isDownloading());
|
||||||
currentModelLblBtn->setValue(GetActiveModelInternalName());
|
currentModelLblBtn->setValue(GetActiveModelInternalName());
|
||||||
|
dynamicModeldOutputs->showDescription();
|
||||||
|
|
||||||
// Update lagdToggle description with current value
|
// Update lagdToggle description with current value
|
||||||
QString desc = tr("Enable this for the car to learn and adapt its steering response time. "
|
QString desc = tr("Enable this for the car to learn and adapt its steering response time. "
|
||||||
@@ -374,8 +331,6 @@ void ModelsPanel::updateLabels() {
|
|||||||
delay_control->setLabel(QString::number(value, 'f', 2) + "s");
|
delay_control->setLabel(QString::number(value, 'f', 2) + "s");
|
||||||
delay_control->showDescription();
|
delay_control->showDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
clearModelCacheBtn->setValue(QString::number(calculateCacheSize(), 'f', 2) + " MB");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -396,32 +351,3 @@ void ModelsPanel::showResetParamsDialog() {
|
|||||||
params.remove("LiveTorqueParameters");
|
params.remove("LiveTorqueParameters");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelsPanel::clearModelCache() {
|
|
||||||
QString confirmMsg = tr("This will delete ALL downloaded models from the cache"
|
|
||||||
"<br/><u>except the currently active model</u>."
|
|
||||||
"<br/><br/>Are you sure you want to continue?");
|
|
||||||
QString content("<body><h2 style=\"text-align: center;\">" + tr("Driving Model Selector") + "</h2><br>"
|
|
||||||
"<p style=\"text-align: center; margin: 0 128px; font-size: 50px;\">" + confirmMsg + "</p></body>");
|
|
||||||
if (showConfirmationDialog(
|
|
||||||
content,
|
|
||||||
tr("Clear Cache"))) {
|
|
||||||
params.putBool("ModelManager_ClearCache", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double ModelsPanel::calculateCacheSize() {
|
|
||||||
QFuture<qint64> future_ModelCacheSize = QtConcurrent::run([=]() {
|
|
||||||
|
|
||||||
QDir model_dir(QString::fromStdString(Path::model_root()));
|
|
||||||
QFileInfoList model_files = model_dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
|
|
||||||
qint64 totalSize = 0;
|
|
||||||
for (const QFileInfo &model_file : model_files) {
|
|
||||||
if (model_file.isFile()) {
|
|
||||||
totalSize += model_file.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return totalSize;
|
|
||||||
});
|
|
||||||
return static_cast<double>(future_ModelCacheSize) / (1024.0 * 1024.0);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -41,8 +41,6 @@ private:
|
|||||||
cereal::ModelManagerSP::Reader model_manager;
|
cereal::ModelManagerSP::Reader model_manager;
|
||||||
cereal::ModelManagerSP::DownloadStatus download_status{};
|
cereal::ModelManagerSP::DownloadStatus download_status{};
|
||||||
cereal::ModelManagerSP::DownloadStatus prev_download_status{};
|
cereal::ModelManagerSP::DownloadStatus prev_download_status{};
|
||||||
void clearModelCache();
|
|
||||||
double calculateCacheSize();
|
|
||||||
|
|
||||||
bool canContinueOnMeteredDialog() {
|
bool canContinueOnMeteredDialog() {
|
||||||
if (!is_metered) return true;
|
if (!is_metered) return true;
|
||||||
@@ -66,6 +64,7 @@ private:
|
|||||||
bool is_onroad = false;
|
bool is_onroad = false;
|
||||||
|
|
||||||
ButtonControlSP *currentModelLblBtn;
|
ButtonControlSP *currentModelLblBtn;
|
||||||
|
ParamControlSP *dynamicModeldOutputs;
|
||||||
ParamControlSP *lagd_toggle_control;
|
ParamControlSP *lagd_toggle_control;
|
||||||
OptionControlSP *delay_control;
|
OptionControlSP *delay_control;
|
||||||
QProgressBar *supercomboProgressBar;
|
QProgressBar *supercomboProgressBar;
|
||||||
@@ -77,6 +76,5 @@ private:
|
|||||||
QProgressBar *policyProgressBar;
|
QProgressBar *policyProgressBar;
|
||||||
QFrame *policyFrame;
|
QFrame *policyFrame;
|
||||||
Params params;
|
Params params;
|
||||||
ButtonControlSP *clearModelCacheBtn;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||||
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||||
|
#include "selfdrive/ui/qt/offroad/developer_panel.h"
|
||||||
#include "selfdrive/ui/qt/offroad/firehose.h"
|
#include "selfdrive/ui/qt/offroad/firehose.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/network/networking.h"
|
#include "selfdrive/ui/sunnypilot/qt/network/networking.h"
|
||||||
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h"
|
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h"
|
||||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h"
|
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h"
|
||||||
@@ -91,7 +91,7 @@ SettingsWindowSP::SettingsWindowSP(QWidget *parent) : SettingsWindow(parent) {
|
|||||||
PanelInfo(" " + tr("Trips"), new TripsPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_trips.png"),
|
PanelInfo(" " + tr("Trips"), new TripsPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_trips.png"),
|
||||||
PanelInfo(" " + tr("Vehicle"), new VehiclePanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_vehicle.png"),
|
PanelInfo(" " + tr("Vehicle"), new VehiclePanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_vehicle.png"),
|
||||||
PanelInfo(" " + tr("Firehose"), new FirehosePanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_firehose.svg"),
|
PanelInfo(" " + tr("Firehose"), new FirehosePanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_firehose.svg"),
|
||||||
PanelInfo(" " + tr("Developer"), new DeveloperPanelSP(this), "../assets/icons/shell.png"),
|
PanelInfo(" " + tr("Developer"), new DeveloperPanel(this), "../assets/icons/shell.png"),
|
||||||
};
|
};
|
||||||
|
|
||||||
nav_btns = new QButtonGroup(this);
|
nav_btns = new QButtonGroup(this);
|
||||||
|
|||||||
@@ -18,18 +18,6 @@ SoftwarePanelSP::SoftwarePanelSP(QWidget *parent) : SoftwarePanel(parent) {
|
|||||||
searchBranches(d.text());
|
searchBranches(d.text());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Disable Updates toggle
|
|
||||||
disableUpdatesToggle = new ParamControl("DisableUpdates",
|
|
||||||
tr("Disable Updates"),
|
|
||||||
tr("When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b>"),
|
|
||||||
"../assets/icons/icon_warning.png",
|
|
||||||
this, true);
|
|
||||||
disableUpdatesToggle->showDescription();
|
|
||||||
addItem(disableUpdatesToggle);
|
|
||||||
connect(disableUpdatesToggle, &ParamControl::toggleFlipped, this, &SoftwarePanelSP::handleDisableUpdatesToggled);
|
|
||||||
connect(uiState(), &UIState::offroadTransition, this, &SoftwarePanelSP::updateDisableUpdatesToggle);
|
|
||||||
updateDisableUpdatesToggle(!uiState()->scene.started);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,27 +49,3 @@ void SoftwarePanelSP::searchBranches(const QString &query) {
|
|||||||
checkForUpdates();
|
checkForUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwarePanelSP::handleDisableUpdatesToggled(bool state) {
|
|
||||||
if (ConfirmationDialog::confirm(tr("%1 updates requires a reboot.<br>Reboot now?")
|
|
||||||
.arg(state ? "Disabling" : "Enabling"), tr("Reboot"), this)) {
|
|
||||||
params.putBool("DoReboot", true);
|
|
||||||
} else {
|
|
||||||
params.putBool("DisableUpdates", !state);
|
|
||||||
disableUpdatesToggle->refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftwarePanelSP::updateDisableUpdatesToggle(bool offroad) {
|
|
||||||
bool enabled = offroad;
|
|
||||||
disableUpdatesToggle->setEnabled(enabled);
|
|
||||||
disableUpdatesToggle->setDescription(enabled
|
|
||||||
? tr("When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b>")
|
|
||||||
: tr("Please enable always offroad mode or turn off vehicle to adjust these toggles"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftwarePanelSP::showEvent(QShowEvent *event) {
|
|
||||||
SoftwarePanel::showEvent(event);
|
|
||||||
updateDisableUpdatesToggle(!uiState()->scene.started);
|
|
||||||
disableUpdatesToggle->showDescription();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,10 +19,4 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void searchBranches(const QString &query);
|
void searchBranches(const QString &query);
|
||||||
ParamControl *disableUpdatesToggle = nullptr;
|
|
||||||
void handleDisableUpdatesToggled(bool state);
|
|
||||||
private slots:
|
|
||||||
void updateDisableUpdatesToggle(bool offroad);
|
|
||||||
protected:
|
|
||||||
void showEvent(QShowEvent *event) override;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
|
|||||||
connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) {
|
connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) {
|
||||||
paramsRefresh();
|
paramsRefresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
main_layout = new QStackedLayout(this);
|
main_layout = new QStackedLayout(this);
|
||||||
ListWidgetSP *list = new ListWidgetSP(this, false);
|
ListWidgetSP *list = new ListWidgetSP(this, false);
|
||||||
|
|
||||||
@@ -30,7 +30,6 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add regular toggles first
|
|
||||||
for (auto &[param, title, desc, icon, needs_restart] : toggle_defs) {
|
for (auto &[param, title, desc, icon, needs_restart] : toggle_defs) {
|
||||||
auto toggle = new ParamControlSP(param, title, desc, icon, this);
|
auto toggle = new ParamControlSP(param, title, desc, icon, this);
|
||||||
|
|
||||||
@@ -54,20 +53,9 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
|
|||||||
param_watcher->addParam(param);
|
param_watcher->addParam(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visuals: Display Metrics below Chevron
|
|
||||||
std::vector<QString> chevron_info_settings_texts{tr("Off"), tr("Distance"), tr("Speed"), tr("Time"), tr("All")};
|
|
||||||
chevron_info_settings = new ButtonParamControlSP(
|
|
||||||
"ChevronInfo", tr("Display Metrics Below Chevron"), tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control)."),
|
|
||||||
"",
|
|
||||||
chevron_info_settings_texts,
|
|
||||||
200);
|
|
||||||
chevron_info_settings->showDescription();
|
|
||||||
list->addItem(chevron_info_settings);
|
|
||||||
param_watcher->addParam("ChevronInfo");
|
|
||||||
|
|
||||||
sunnypilotScroller = new ScrollViewSP(list, this);
|
sunnypilotScroller = new ScrollViewSP(list, this);
|
||||||
vlayout->addWidget(sunnypilotScroller);
|
vlayout->addWidget(sunnypilotScroller);
|
||||||
|
|
||||||
main_layout->addWidget(sunnypilotScreen);
|
main_layout->addWidget(sunnypilotScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,8 +67,4 @@ void VisualsPanel::paramsRefresh() {
|
|||||||
for (auto toggle : toggles) {
|
for (auto toggle : toggles) {
|
||||||
toggle.second->refresh();
|
toggle.second->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chevron_info_settings) {
|
|
||||||
chevron_info_settings->refresh();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,5 +27,4 @@ protected:
|
|||||||
Params params;
|
Params params;
|
||||||
std::map<std::string, ParamControlSP*> toggles;
|
std::map<std::string, ParamControlSP*> toggles;
|
||||||
ParamWatcher * param_watcher;
|
ParamWatcher * param_watcher;
|
||||||
ButtonParamControlSP *chevron_info_settings;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,24 +30,9 @@ QFrame *vertical_space(int height, QWidget *parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AbstractControlSP
|
// AbstractControlSP
|
||||||
std::vector<AbstractControlSP*> AbstractControlSP::advanced_controls_;
|
|
||||||
AbstractControlSP::~AbstractControlSP() { UnregisterAdvancedControl(this); }
|
|
||||||
|
|
||||||
void AbstractControlSP::RegisterAdvancedControl(AbstractControlSP *ctrl) { advanced_controls_.push_back(ctrl); }
|
AbstractControlSP::AbstractControlSP(const QString &title, const QString &desc, const QString &icon, QWidget *parent)
|
||||||
|
: AbstractControl(title, desc, icon, parent) {
|
||||||
void AbstractControlSP::UnregisterAdvancedControl(AbstractControlSP *ctrl) {
|
|
||||||
advanced_controls_.erase(std::remove(advanced_controls_.begin(), advanced_controls_.end(), ctrl), advanced_controls_.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbstractControlSP::UpdateAllAdvancedControls() {
|
|
||||||
bool visibility = Params().getBool("ShowAdvancedControls");
|
|
||||||
advanced_controls_.erase(std::remove(advanced_controls_.begin(), advanced_controls_.end(), nullptr), advanced_controls_.end());
|
|
||||||
for (auto *ctrl : advanced_controls_) ctrl->setVisible(visibility);
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractControlSP::AbstractControlSP(const QString &title, const QString &desc, const QString &icon, QWidget *parent, bool advancedControl)
|
|
||||||
: AbstractControl(title, desc, icon, parent), isAdvancedControl(advancedControl) {
|
|
||||||
if (isAdvancedControl) RegisterAdvancedControl(this);
|
|
||||||
|
|
||||||
main_layout = new QVBoxLayout(this);
|
main_layout = new QVBoxLayout(this);
|
||||||
main_layout->setMargin(0);
|
main_layout->setMargin(0);
|
||||||
@@ -97,8 +82,8 @@ void AbstractControlSP::hideEvent(QHideEvent *e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractControlSP_SELECTOR::AbstractControlSP_SELECTOR(const QString &title, const QString &desc, const QString &icon, QWidget *parent, bool advancedControl)
|
AbstractControlSP_SELECTOR::AbstractControlSP_SELECTOR(const QString &title, const QString &desc, const QString &icon, QWidget *parent)
|
||||||
: AbstractControlSP(title, desc, icon, parent, advancedControl) {
|
: AbstractControlSP(title, desc, icon, parent) {
|
||||||
|
|
||||||
if (title_label != nullptr) {
|
if (title_label != nullptr) {
|
||||||
delete title_label;
|
delete title_label;
|
||||||
@@ -184,8 +169,8 @@ void AbstractControlSP_SELECTOR::hideEvent(QHideEvent *e) {
|
|||||||
|
|
||||||
// controls
|
// controls
|
||||||
|
|
||||||
ButtonControlSP::ButtonControlSP(const QString &title, const QString &text, const QString &desc, QWidget *parent, bool advancedControl)
|
ButtonControlSP::ButtonControlSP(const QString &title, const QString &text, const QString &desc, QWidget *parent)
|
||||||
: AbstractControlSP(title, desc, "", parent, advancedControl) {
|
: AbstractControlSP(title, desc, "", parent) {
|
||||||
|
|
||||||
btn.setText(text);
|
btn.setText(text);
|
||||||
btn.setStyleSheet(R"(
|
btn.setStyleSheet(R"(
|
||||||
@@ -240,8 +225,8 @@ void ElidedLabelSP::paintEvent(QPaintEvent *event) {
|
|||||||
|
|
||||||
// ParamControlSP
|
// ParamControlSP
|
||||||
|
|
||||||
ParamControlSP::ParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent, bool advancedControl)
|
ParamControlSP::ParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent)
|
||||||
: ToggleControlSP(title, desc, icon, false, parent, advancedControl){
|
: ToggleControlSP(title, desc, icon, false, parent) {
|
||||||
|
|
||||||
key = param.toStdString();
|
key = param.toStdString();
|
||||||
QObject::connect(this, &ParamControlSP::toggleFlipped, this, &ParamControlSP::toggleClicked);
|
QObject::connect(this, &ParamControlSP::toggleFlipped, this, &ParamControlSP::toggleClicked);
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ class AbstractControlSP : public AbstractControl {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~AbstractControlSP();
|
|
||||||
void setDescription(const QString &desc) override {
|
void setDescription(const QString &desc) override {
|
||||||
if (description) description->setText(desc);
|
if (description) description->setText(desc);
|
||||||
}
|
}
|
||||||
@@ -82,30 +81,13 @@ public slots:
|
|||||||
description->setVisible(true);
|
description->setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setVisible(bool visible) override {
|
|
||||||
bool _visible = visible;
|
|
||||||
if (isAdvancedControl && !params.getBool("ShowAdvancedControls")) {
|
|
||||||
_visible = false;
|
|
||||||
}
|
|
||||||
AbstractControl::setVisible(_visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RegisterAdvancedControl(AbstractControlSP *ctrl);
|
|
||||||
static void UnregisterAdvancedControl(AbstractControlSP *ctrl);
|
|
||||||
static void UpdateAllAdvancedControls();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AbstractControlSP(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr, bool advancedControl = false);
|
AbstractControlSP(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr);
|
||||||
void hideEvent(QHideEvent *e) override;
|
void hideEvent(QHideEvent *e) override;
|
||||||
|
|
||||||
QVBoxLayout *main_layout;
|
QVBoxLayout *main_layout;
|
||||||
ElidedLabelSP *value;
|
ElidedLabelSP *value;
|
||||||
QLabel *description = nullptr;
|
QLabel *description = nullptr;
|
||||||
bool isAdvancedControl;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Params params;
|
|
||||||
static std::vector<AbstractControlSP*> advanced_controls_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// AbstractControlSP_SELECTOR
|
// AbstractControlSP_SELECTOR
|
||||||
@@ -115,7 +97,7 @@ class AbstractControlSP_SELECTOR : public AbstractControlSP {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSpacerItem *spacingItem = new QSpacerItem(44, 44, QSizePolicy::Minimum, QSizePolicy::Fixed);
|
QSpacerItem *spacingItem = new QSpacerItem(44, 44, QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||||
AbstractControlSP_SELECTOR(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr, bool advancedControl = false);
|
AbstractControlSP_SELECTOR(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr);
|
||||||
void hideEvent(QHideEvent *e) override;
|
void hideEvent(QHideEvent *e) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -141,7 +123,7 @@ class ButtonControlSP : public AbstractControlSP {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ButtonControlSP(const QString &title, const QString &text, const QString &desc = "", QWidget *parent = nullptr, bool advancedControl = false);
|
ButtonControlSP(const QString &title, const QString &text, const QString &desc = "", QWidget *parent = nullptr);
|
||||||
inline void setText(const QString &text) { btn.setText(text); }
|
inline void setText(const QString &text) { btn.setText(text); }
|
||||||
inline QString text() const { return btn.text(); }
|
inline QString text() const { return btn.text(); }
|
||||||
inline void click() { btn.click(); }
|
inline void click() { btn.click(); }
|
||||||
@@ -160,7 +142,7 @@ class ToggleControlSP : public AbstractControlSP {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ToggleControlSP(const QString &title, const QString &desc = "", const QString &icon = "", const bool state = false, QWidget *parent = nullptr, bool advancedControl = false) : AbstractControlSP(title, desc, icon, parent, advancedControl) {
|
ToggleControlSP(const QString &title, const QString &desc = "", const QString &icon = "", const bool state = false, QWidget *parent = nullptr) : AbstractControlSP(title, desc, icon, parent) {
|
||||||
// space between toggle and title
|
// space between toggle and title
|
||||||
icon_label = new QLabel(this);
|
icon_label = new QLabel(this);
|
||||||
hlayout->addWidget(icon_label);
|
hlayout->addWidget(icon_label);
|
||||||
@@ -191,7 +173,7 @@ class ParamControlSP : public ToggleControlSP {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr, bool advancedControl = false);
|
ParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr);
|
||||||
void setConfirmation(bool _confirm, bool _store_confirm) {
|
void setConfirmation(bool _confirm, bool _store_confirm) {
|
||||||
confirm = _confirm;
|
confirm = _confirm;
|
||||||
store_confirm = _store_confirm;
|
store_confirm = _store_confirm;
|
||||||
@@ -237,7 +219,7 @@ class MultiButtonControlSP : public AbstractControlSP_SELECTOR {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
MultiButtonControlSP(const QString &title, const QString &desc, const QString &icon,
|
MultiButtonControlSP(const QString &title, const QString &desc, const QString &icon,
|
||||||
const std::vector<QString> &button_texts, const int minimum_button_width = 225, const bool inline_layout = false, bool advancedControl = false) : AbstractControlSP_SELECTOR(title, desc, icon, nullptr, advancedControl), button_texts(button_texts), is_inline_layout(inline_layout) {
|
const std::vector<QString> &button_texts, const int minimum_button_width = 225, const bool inline_layout = false) : AbstractControlSP_SELECTOR(title, desc, icon), button_texts(button_texts), is_inline_layout(inline_layout) {
|
||||||
const QString style = R"(
|
const QString style = R"(
|
||||||
QPushButton {
|
QPushButton {
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
@@ -389,8 +371,8 @@ class ButtonParamControlSP : public MultiButtonControlSP {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ButtonParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
ButtonParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||||
const std::vector<QString> &button_texts, const int minimum_button_width = 225, const bool inline_layout = false, bool advancedControl = false) : MultiButtonControlSP(title, desc, icon,
|
const std::vector<QString> &button_texts, const int minimum_button_width = 225, const bool inline_layout = false) : MultiButtonControlSP(title, desc, icon,
|
||||||
button_texts, minimum_button_width, inline_layout, advancedControl) {
|
button_texts, minimum_button_width, inline_layout) {
|
||||||
key = param.toStdString();
|
key = param.toStdString();
|
||||||
int value = atoi(params.get(key).c_str());
|
int value = atoi(params.get(key).c_str());
|
||||||
|
|
||||||
@@ -517,7 +499,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
OptionControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
OptionControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||||
const MinMaxValue &range, const int per_value_change = 1, const bool inline_layout = false,
|
const MinMaxValue &range, const int per_value_change = 1, const bool inline_layout = false,
|
||||||
const QMap<QString, QString> *valMap = nullptr, bool scale_float = false, bool advancedControl = false) : AbstractControlSP_SELECTOR(title, desc, icon, nullptr, advancedControl), _title(title), valueMap(valMap), is_inline_layout(inline_layout), use_float_scaling(scale_float) {
|
const QMap<QString, QString> *valMap = nullptr, bool scale_float = false) : AbstractControlSP_SELECTOR(title, desc, icon, nullptr), _title(title), valueMap(valMap), is_inline_layout(inline_layout), use_float_scaling(scale_float) {
|
||||||
const QString style = R"(
|
const QString style = R"(
|
||||||
QPushButton {
|
QPushButton {
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
|||||||
fill_xyzt(orientation_rate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
|
fill_xyzt(orientation_rate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
|
||||||
|
|
||||||
# temporal pose
|
# temporal pose
|
||||||
temporal_pose = modelV2.temporalPoseDEPRECATED
|
temporal_pose = modelV2.temporalPose
|
||||||
temporal_pose.trans = net_output_data['plan'][0,0,Plan.VELOCITY].tolist()
|
temporal_pose.trans = net_output_data['plan'][0,0,Plan.VELOCITY].tolist()
|
||||||
temporal_pose.transStd = net_output_data['plan_stds'][0,0,Plan.VELOCITY].tolist()
|
temporal_pose.transStd = net_output_data['plan_stds'][0,0,Plan.VELOCITY].tolist()
|
||||||
temporal_pose.rot = net_output_data['plan'][0,0,Plan.ORIENTATION_RATE].tolist()
|
temporal_pose.rot = net_output_data['plan'][0,0,Plan.ORIENTATION_RATE].tolist()
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ 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.temporalPoseDEPRECATED
|
temporal_pose = modelV2.temporalPose
|
||||||
if 'sim_pose' in net_output_data:
|
if 'sim_pose' in net_output_data:
|
||||||
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()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
from openpilot.common.params import Params
|
||||||
from openpilot.sunnypilot.models.split_model_constants import SplitModelConstants
|
from openpilot.sunnypilot.models.split_model_constants import SplitModelConstants
|
||||||
from openpilot.sunnypilot.models.helpers import get_active_bundle
|
from openpilot.sunnypilot.models.helpers import get_active_bundle
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ def softmax(x, axis=-1):
|
|||||||
class Parser:
|
class Parser:
|
||||||
def __init__(self, ignore_missing=False):
|
def __init__(self, ignore_missing=False):
|
||||||
self.ignore_missing = ignore_missing
|
self.ignore_missing = ignore_missing
|
||||||
|
self._params = Params()
|
||||||
model_bundle = get_active_bundle()
|
model_bundle = get_active_bundle()
|
||||||
self.generation = model_bundle.generation if model_bundle is not None else None
|
self.generation = model_bundle.generation if model_bundle is not None else None
|
||||||
|
|
||||||
@@ -91,28 +93,29 @@ class Parser:
|
|||||||
outs[name] = pred_mu_final.reshape(final_shape)
|
outs[name] = pred_mu_final.reshape(final_shape)
|
||||||
outs[name + '_stds'] = pred_std_final.reshape(final_shape)
|
outs[name + '_stds'] = pred_std_final.reshape(final_shape)
|
||||||
|
|
||||||
def _parse_plan_mhp(self, outs):
|
|
||||||
self.parse_mdn('plan', outs, in_N=SplitModelConstants.PLAN_MHP_N, out_N=SplitModelConstants.PLAN_MHP_SELECTION,
|
|
||||||
out_shape=(SplitModelConstants.IDX_N,SplitModelConstants.PLAN_WIDTH))
|
|
||||||
|
|
||||||
def parse_dynamic_outputs(self, outs: dict[str, np.ndarray]) -> None:
|
def parse_dynamic_outputs(self, outs: dict[str, np.ndarray]) -> None:
|
||||||
if 'lead' in outs:
|
if self._params.get_bool("DynamicModeldOutputs") or (self.generation >= 12):
|
||||||
if self.generation >= 12 and \
|
if 'lead' in outs:
|
||||||
outs['lead'].shape[1] == 2 * SplitModelConstants.LEAD_MHP_SELECTION * SplitModelConstants.LEAD_TRAJ_LEN * SplitModelConstants.LEAD_WIDTH:
|
if outs['lead'].shape[1] == 2 * SplitModelConstants.LEAD_MHP_SELECTION *SplitModelConstants.LEAD_TRAJ_LEN * SplitModelConstants.LEAD_WIDTH:
|
||||||
self.parse_mdn('lead', outs, in_N=0, out_N=0,
|
self.parse_mdn('lead', outs, in_N=0, out_N=0,
|
||||||
out_shape=(SplitModelConstants.LEAD_MHP_SELECTION, SplitModelConstants.LEAD_TRAJ_LEN, SplitModelConstants.LEAD_WIDTH))
|
out_shape=(SplitModelConstants.LEAD_MHP_SELECTION, SplitModelConstants.LEAD_TRAJ_LEN,SplitModelConstants.LEAD_WIDTH))
|
||||||
else:
|
else:
|
||||||
|
self.parse_mdn('lead', outs, in_N=SplitModelConstants.LEAD_MHP_N, out_N=SplitModelConstants.LEAD_MHP_SELECTION,
|
||||||
|
out_shape=(SplitModelConstants.LEAD_TRAJ_LEN,SplitModelConstants.LEAD_WIDTH))
|
||||||
|
if 'plan' in outs:
|
||||||
|
if outs['plan'].shape[1] > 2 * SplitModelConstants.PLAN_WIDTH * SplitModelConstants.IDX_N:
|
||||||
|
self.parse_mdn('plan', outs, in_N=SplitModelConstants.PLAN_MHP_N, out_N=SplitModelConstants.PLAN_MHP_SELECTION,
|
||||||
|
out_shape=(SplitModelConstants.IDX_N,SplitModelConstants.PLAN_WIDTH))
|
||||||
|
else:
|
||||||
|
self.parse_mdn('plan', outs, in_N=0, out_N=0,
|
||||||
|
out_shape=(SplitModelConstants.IDX_N,SplitModelConstants.PLAN_WIDTH))
|
||||||
|
else:
|
||||||
|
if 'lead' in outs:
|
||||||
self.parse_mdn('lead', outs, in_N=SplitModelConstants.LEAD_MHP_N, out_N=SplitModelConstants.LEAD_MHP_SELECTION,
|
self.parse_mdn('lead', outs, in_N=SplitModelConstants.LEAD_MHP_N, out_N=SplitModelConstants.LEAD_MHP_SELECTION,
|
||||||
out_shape=(SplitModelConstants.LEAD_TRAJ_LEN, SplitModelConstants.LEAD_WIDTH))
|
out_shape=(SplitModelConstants.LEAD_TRAJ_LEN,SplitModelConstants.LEAD_WIDTH))
|
||||||
if 'plan' in outs:
|
if 'plan' in outs:
|
||||||
if self.generation >= 12 and \
|
self.parse_mdn('plan', outs, in_N=SplitModelConstants.PLAN_MHP_N, out_N=SplitModelConstants.PLAN_MHP_SELECTION,
|
||||||
outs['plan'].shape[1] > 2 * SplitModelConstants.PLAN_WIDTH * SplitModelConstants.IDX_N:
|
out_shape=(SplitModelConstants.IDX_N,SplitModelConstants.PLAN_WIDTH))
|
||||||
self._parse_plan_mhp(outs)
|
|
||||||
elif self.generation >= 12:
|
|
||||||
self.parse_mdn('plan', outs, in_N=0, out_N=0,
|
|
||||||
out_shape=(SplitModelConstants.IDX_N, SplitModelConstants.PLAN_WIDTH))
|
|
||||||
else:
|
|
||||||
self._parse_plan_mhp(outs)
|
|
||||||
|
|
||||||
def split_outputs(self, outs: dict[str, np.ndarray]) -> None:
|
def split_outputs(self, outs: dict[str, np.ndarray]) -> None:
|
||||||
if 'desired_curvature' in outs:
|
if 'desired_curvature' in outs:
|
||||||
|
|||||||
@@ -178,10 +178,6 @@ class ModelManagerSP:
|
|||||||
finally:
|
finally:
|
||||||
self.params.put("ModelManager_DownloadIndex", "")
|
self.params.put("ModelManager_DownloadIndex", "")
|
||||||
|
|
||||||
if self.params.get("ModelManager_ClearCache", block=False, encoding="utf-8"):
|
|
||||||
self.clear_model_cache()
|
|
||||||
self.params.remove("ModelManager_ClearCache")
|
|
||||||
|
|
||||||
self._report_status()
|
self._report_status()
|
||||||
rk.keep_time()
|
rk.keep_time()
|
||||||
|
|
||||||
@@ -189,31 +185,6 @@ class ModelManagerSP:
|
|||||||
cloudlog.exception(f"Error in main thread: {str(e)}")
|
cloudlog.exception(f"Error in main thread: {str(e)}")
|
||||||
rk.keep_time()
|
rk.keep_time()
|
||||||
|
|
||||||
def clear_model_cache(self) -> None:
|
|
||||||
"""
|
|
||||||
Clears the model cache directory of all files except those in the active model bundle.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Get list of files used by active model bundle
|
|
||||||
active_files = []
|
|
||||||
if self.active_bundle is not None: # When the default model is active
|
|
||||||
for model in self.active_bundle.models:
|
|
||||||
if hasattr(model, 'artifact') and model.artifact.fileName:
|
|
||||||
active_files.append(model.artifact.fileName)
|
|
||||||
if hasattr(model, 'metadata') and model.metadata.fileName:
|
|
||||||
active_files.append(model.metadata.fileName)
|
|
||||||
|
|
||||||
# Remove all files except active ones
|
|
||||||
model_dir = Paths.model_root()
|
|
||||||
try:
|
|
||||||
for filename in os.listdir(model_dir):
|
|
||||||
if filename not in active_files:
|
|
||||||
file_path = os.path.join(model_dir, filename)
|
|
||||||
if os.path.isfile(file_path):
|
|
||||||
os.remove(file_path)
|
|
||||||
cloudlog.info("Model cache cleared, keeping active model files")
|
|
||||||
except Exception as e:
|
|
||||||
cloudlog.exception(f"Error clearing model cache: {str(e)}")
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
ModelManagerSP().main_thread()
|
ModelManagerSP().main_thread()
|
||||||
|
|||||||
Submodule sunnypilot/neural_network_data updated: 03cac2d30e...b59ab483c8
@@ -16,12 +16,12 @@ DecState = custom.LongitudinalPlanSP.DynamicExperimentalControl.DynamicExperimen
|
|||||||
class LongitudinalPlannerSP:
|
class LongitudinalPlannerSP:
|
||||||
def __init__(self, CP: structs.CarParams, mpc):
|
def __init__(self, CP: structs.CarParams, mpc):
|
||||||
self.dec = DynamicExperimentalController(CP, mpc)
|
self.dec = DynamicExperimentalController(CP, mpc)
|
||||||
self.generation = int(model_bundle.generation) if (model_bundle := get_active_bundle()) else None
|
model_bundle = get_active_bundle()
|
||||||
|
self.generation = model_bundle.generation if model_bundle is not None else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mlsim(self) -> bool:
|
def mlsim(self) -> bool:
|
||||||
# If we don't have a generation set, we assume it's default model. Which as of today are mlsim.
|
return bool(self.generation is not None and self.generation >= 11)
|
||||||
return bool(self.generation is None or self.generation >= 11)
|
|
||||||
|
|
||||||
def get_mpc_mode(self) -> str | None:
|
def get_mpc_mode(self) -> str | None:
|
||||||
if not self.dec.active():
|
if not self.dec.active():
|
||||||
|
|||||||
@@ -55,8 +55,4 @@ namespace Path {
|
|||||||
return "/dev/shm";
|
return "/dev/shm";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string model_root() {
|
|
||||||
return Hardware::PC() ? Path::comma_home() + "/media/0/models" : "/data/media/0/models";
|
|
||||||
}
|
|
||||||
} // namespace Path
|
} // namespace Path
|
||||||
|
|||||||
@@ -50,14 +50,12 @@ def manager_init() -> None:
|
|||||||
("BlindSpot", "0"),
|
("BlindSpot", "0"),
|
||||||
("BlinkerMinLateralControlSpeed", "20"), # MPH or km/h
|
("BlinkerMinLateralControlSpeed", "20"), # MPH or km/h
|
||||||
("BlinkerPauseLateralControl", "0"),
|
("BlinkerPauseLateralControl", "0"),
|
||||||
("Brightness", "0"),
|
|
||||||
("ChevronInfo", "4"),
|
|
||||||
("CustomAccIncrementsEnabled", "0"),
|
("CustomAccIncrementsEnabled", "0"),
|
||||||
("CustomAccLongPressIncrement", "5"),
|
("CustomAccLongPressIncrement", "5"),
|
||||||
("CustomAccShortPressIncrement", "1"),
|
("CustomAccShortPressIncrement", "1"),
|
||||||
("DeviceBootMode", "0"),
|
("DeviceBootMode", "0"),
|
||||||
("DisableUpdates", "0"),
|
|
||||||
("DynamicExperimentalControl", "0"),
|
("DynamicExperimentalControl", "0"),
|
||||||
|
("DynamicModeldOutputs", "0"),
|
||||||
("HyundaiLongitudinalTuning", "0"),
|
("HyundaiLongitudinalTuning", "0"),
|
||||||
("InteractivityTimeout", "0"),
|
("InteractivityTimeout", "0"),
|
||||||
("LagdToggle", "1"),
|
("LagdToggle", "1"),
|
||||||
@@ -68,18 +66,11 @@ def manager_init() -> None:
|
|||||||
("MadsUnifiedEngagementMode", "1"),
|
("MadsUnifiedEngagementMode", "1"),
|
||||||
("MapdVersion", f"{VERSION}"),
|
("MapdVersion", f"{VERSION}"),
|
||||||
("MaxTimeOffroad", "1800"),
|
("MaxTimeOffroad", "1800"),
|
||||||
|
("Brightness", "0"),
|
||||||
("ModelManager_LastSyncTime", "0"),
|
("ModelManager_LastSyncTime", "0"),
|
||||||
("ModelManager_ModelsCache", ""),
|
("ModelManager_ModelsCache", ""),
|
||||||
("NeuralNetworkLateralControl", "0"),
|
("NeuralNetworkLateralControl", "0"),
|
||||||
("QuickBootToggle", "0"),
|
|
||||||
("QuietMode", "0"),
|
("QuietMode", "0"),
|
||||||
("ShowAdvancedControls", "0" if build_metadata.tested_channel else "1"),
|
|
||||||
("EnableHkgTuningAngleSmoothingFactor", "1"),
|
|
||||||
("HkgTuningAngleMinTorqueReductionGain", "10"),
|
|
||||||
("HkgTuningAngleActiveTorqueReductionGain", "60"),
|
|
||||||
("HkgTuningAngleMaxTorqueReductionGain", "100"),
|
|
||||||
("HkgTuningOverridingCycles", "17"),
|
|
||||||
("HkgAngleLiveTuning", "0"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# device boot mode
|
# device boot mode
|
||||||
@@ -111,7 +102,6 @@ def manager_init() -> None:
|
|||||||
params.put("GitCommitDate", build_metadata.openpilot.git_commit_date)
|
params.put("GitCommitDate", build_metadata.openpilot.git_commit_date)
|
||||||
params.put("GitBranch", build_metadata.channel)
|
params.put("GitBranch", build_metadata.channel)
|
||||||
params.put("GitRemote", build_metadata.openpilot.git_origin)
|
params.put("GitRemote", build_metadata.openpilot.git_origin)
|
||||||
params.put_bool("IsDevelopmentBranch", build_metadata.development_channel)
|
|
||||||
params.put_bool("IsTestedBranch", build_metadata.tested_channel)
|
params.put_bool("IsTestedBranch", build_metadata.tested_channel)
|
||||||
params.put_bool("IsReleaseBranch", build_metadata.release_channel)
|
params.put_bool("IsReleaseBranch", build_metadata.release_channel)
|
||||||
params.put("HardwareSerial", serial)
|
params.put("HardwareSerial", serial)
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ procs = [
|
|||||||
|
|
||||||
PythonProcess("sensord", "system.sensord.sensord", only_onroad, enabled=not PC),
|
PythonProcess("sensord", "system.sensord.sensord", only_onroad, enabled=not PC),
|
||||||
NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(5 if not PC else None)),
|
NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(5 if not PC else None)),
|
||||||
PythonProcess("soundd", "selfdrive.ui.soundd", and_(only_onroad, not_joystick)),
|
PythonProcess("soundd", "selfdrive.ui.soundd", only_onroad),
|
||||||
PythonProcess("locationd", "selfdrive.locationd.locationd", only_onroad),
|
PythonProcess("locationd", "selfdrive.locationd.locationd", only_onroad),
|
||||||
NativeProcess("_pandad", "selfdrive/pandad", ["./pandad"], always_run, enabled=False),
|
NativeProcess("_pandad", "selfdrive/pandad", ["./pandad"], always_run, enabled=False),
|
||||||
PythonProcess("calibrationd", "selfdrive.locationd.calibrationd", only_onroad),
|
PythonProcess("calibrationd", "selfdrive.locationd.calibrationd", only_onroad),
|
||||||
|
|||||||
+1
-5
@@ -117,13 +117,9 @@ class BuildMetadata:
|
|||||||
def master_channel(self) -> bool:
|
def master_channel(self) -> bool:
|
||||||
return self.channel in MASTER_SP_BRANCHES
|
return self.channel in MASTER_SP_BRANCHES
|
||||||
|
|
||||||
@property
|
|
||||||
def development_channel(self) -> bool:
|
|
||||||
return self.channel.startswith("dev-") or self.channel.endswith("-prebuilt")
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def channel_type(self) -> str:
|
def channel_type(self) -> str:
|
||||||
if self.development_channel:
|
if self.channel.startswith("dev-"):
|
||||||
return "development"
|
return "development"
|
||||||
elif self.channel.startswith("staging-"):
|
elif self.channel.startswith("staging-"):
|
||||||
return "staging"
|
return "staging"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,6 @@
|
|||||||
With joystick_control, you can connect your laptop to your comma device over the network and debug controls using a joystick or keyboard.
|
With joystick_control, you can connect your laptop to your comma device over the network and debug controls using a joystick or keyboard.
|
||||||
joystick_control uses [inputs](https://pypi.org/project/inputs) which supports many common gamepads and joysticks.
|
joystick_control uses [inputs](https://pypi.org/project/inputs) which supports many common gamepads and joysticks.
|
||||||
|
|
||||||
## Note
|
|
||||||
You might need to install [xow](https://github.com/medusalix/xow) to use the Xbox One controller on comma device.
|
|
||||||
Even though **xone** is recommended on the xow page, **xow** is the one that works with the comma device.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
The car must be off, and openpilot must be offroad before starting `joystick_control`.
|
The car must be off, and openpilot must be offroad before starting `joystick_control`.
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ import os
|
|||||||
import argparse
|
import argparse
|
||||||
import threading
|
import threading
|
||||||
import numpy as np
|
import numpy as np
|
||||||
try:
|
from inputs import UnpluggedError, get_gamepad
|
||||||
import pygame as pg
|
|
||||||
except ImportError:
|
|
||||||
print("pygame is not installed. Please install it with 'uv pip install pygame'")
|
|
||||||
|
|
||||||
from cereal import messaging
|
from cereal import messaging
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
@@ -14,10 +11,7 @@ from openpilot.common.realtime import Ratekeeper
|
|||||||
from openpilot.system.hardware import HARDWARE
|
from openpilot.system.hardware import HARDWARE
|
||||||
from openpilot.tools.lib.kbhit import KBHit
|
from openpilot.tools.lib.kbhit import KBHit
|
||||||
|
|
||||||
# Set SDL environment variable to avoid using a video driver for headless operation
|
EXPO = 0.4
|
||||||
os.environ["SDL_VIDEODRIVER"] = "dummy"
|
|
||||||
|
|
||||||
EXPO = 0.4 # Exponential factor for joystick response curve
|
|
||||||
|
|
||||||
|
|
||||||
class Keyboard:
|
class Keyboard:
|
||||||
@@ -46,122 +40,60 @@ class Keyboard:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class PyGameJoystick:
|
class Joystick:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Initialize pygame and joystick subsystem
|
# This class supports a PlayStation 5 DualSense controller on the comma 3X
|
||||||
pg.init()
|
# TODO: find a way to get this from API or detect gamepad/PC, perhaps "inputs" doesn't support it
|
||||||
if not pg.joystick.get_init():
|
self.cancel_button = 'BTN_NORTH' # BTN_NORTH=X/triangle
|
||||||
pg.joystick.init()
|
|
||||||
|
|
||||||
# Find connected joysticks
|
|
||||||
joystick_count = pg.joystick.get_count()
|
|
||||||
if joystick_count == 0:
|
|
||||||
print("No joysticks found. Please connect a controller.")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Initialize the first joystick
|
|
||||||
self.joystick = pg.joystick.Joystick(0)
|
|
||||||
self.joystick.init()
|
|
||||||
|
|
||||||
print(f"Using joystick: {self.joystick.get_name()}")
|
|
||||||
print(f"Number of axes: {self.joystick.get_numaxes()}")
|
|
||||||
print(f"Number of buttons: {self.joystick.get_numbuttons()}")
|
|
||||||
print(f"Number of hats: {self.joystick.get_numhats()}")
|
|
||||||
|
|
||||||
# This supports PlayStation and Xbox controllers on different platforms
|
|
||||||
if HARDWARE.get_device_type() == 'pc':
|
if HARDWARE.get_device_type() == 'pc':
|
||||||
# Xbox mapping on PC
|
accel_axis = 'ABS_Z'
|
||||||
self.accel_axis = 5 # Right trigger
|
steer_axis = 'ABS_RX'
|
||||||
self.brake_axis = 4 # Left trigger
|
# TODO: once the longcontrol API is finalized, we can replace this with outputting gas/brake and steering
|
||||||
self.steer_axis = 0 # Left stick horizontal
|
self.flip_map = {'ABS_RZ': accel_axis}
|
||||||
self.cancel_button = 3 # Y/Triangle button
|
|
||||||
else:
|
else:
|
||||||
# PlayStation mapping on comma device
|
accel_axis = 'ABS_RX'
|
||||||
self.accel_axis = 5 # R2
|
steer_axis = 'ABS_Z'
|
||||||
self.brake_axis = 4 # L2
|
self.flip_map = {'ABS_RY': accel_axis}
|
||||||
self.steer_axis = 0 # Left stick horizontal
|
|
||||||
self.cancel_button = 3 # Triangle button
|
|
||||||
|
|
||||||
# Configure for adaptive mappings based on detected controller
|
self.min_axis_value = {accel_axis: 0., steer_axis: 0.}
|
||||||
controller_name = self.joystick.get_name().lower()
|
self.max_axis_value = {accel_axis: 255., steer_axis: 255.}
|
||||||
if "xbox" in controller_name:
|
self.axes_values = {accel_axis: 0., steer_axis: 0.}
|
||||||
print("Xbox controller detected, using Xbox mappings")
|
self.axes_order = [accel_axis, steer_axis]
|
||||||
self.accel_axis = 5 # Right trigger (RT)
|
|
||||||
self.brake_axis = 4 # Left trigger (LT)
|
|
||||||
self.cancel_button = 3 # Y button
|
|
||||||
elif "playstation" in controller_name or "dual" in controller_name:
|
|
||||||
print("PlayStation controller detected, using PlayStation mappings")
|
|
||||||
self.accel_axis = 5 # R2
|
|
||||||
self.brake_axis = 4 # L2
|
|
||||||
self.cancel_button = 3 # Triangle
|
|
||||||
|
|
||||||
# Initialize values
|
|
||||||
self.axes_values = {'gb': 0., 'steer': 0.} # Maintain same keys as Keyboard class
|
|
||||||
self.axes_order = ['gb', 'steer'] # Match expected format
|
|
||||||
self.cancel = False
|
self.cancel = False
|
||||||
self.deadzone = 0.03 # 3% deadzone for noisy joysticks
|
|
||||||
|
|
||||||
# Process events once to clear the event queue
|
|
||||||
pg.event.pump()
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
# Process pygame events
|
|
||||||
try:
|
try:
|
||||||
for event in pg.event.get():
|
joystick_event = get_gamepad()[0]
|
||||||
if event.type == pg.JOYDEVICEREMOVED:
|
except (OSError, UnpluggedError):
|
||||||
if event.instance_id == self.joystick.get_instance_id():
|
self.axes_values = dict.fromkeys(self.axes_values, 0.)
|
||||||
print("Joystick disconnected!")
|
|
||||||
self.axes_values = {'gb': 0., 'steer': 0.}
|
|
||||||
return False
|
|
||||||
|
|
||||||
elif event.type == pg.JOYBUTTONDOWN:
|
|
||||||
if event.button == self.cancel_button:
|
|
||||||
self.cancel = True
|
|
||||||
|
|
||||||
elif event.type == pg.JOYBUTTONUP:
|
|
||||||
if event.button == self.cancel_button:
|
|
||||||
self.cancel = False
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error processing events: {e}")
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Read current joystick state directly
|
event = (joystick_event.code, joystick_event.state)
|
||||||
try:
|
|
||||||
if not self.joystick.get_init():
|
|
||||||
print("Joystick not initialized")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Read steering (left stick horizontal)
|
# flip left trigger to negative accel
|
||||||
steer_raw = self.joystick.get_axis(self.steer_axis) * -1
|
if event[0] in self.flip_map:
|
||||||
steer = steer_raw if abs(steer_raw) > self.deadzone else 0.0
|
event = (self.flip_map[event[0]], -event[1])
|
||||||
|
|
||||||
# Read gas (right trigger)
|
if event[0] == self.cancel_button:
|
||||||
accel_raw = self.joystick.get_axis(self.accel_axis)
|
if event[1] == 1:
|
||||||
# Convert from [-1, 1] to [0, 1] range (triggers often start at -1 when not pressed)
|
self.cancel = True
|
||||||
accel = (accel_raw + 1) / 2 if self.accel_axis in [4, 5] else accel_raw
|
elif event[1] == 0: # state 0 is falling edge
|
||||||
accel = accel if accel > self.deadzone else 0.0
|
self.cancel = False
|
||||||
|
elif event[0] in self.axes_values:
|
||||||
|
self.max_axis_value[event[0]] = max(event[1], self.max_axis_value[event[0]])
|
||||||
|
self.min_axis_value[event[0]] = min(event[1], self.min_axis_value[event[0]])
|
||||||
|
|
||||||
# Read brake (left trigger)
|
norm = -float(np.interp(event[1], [self.min_axis_value[event[0]], self.max_axis_value[event[0]]], [-1., 1.]))
|
||||||
brake_raw = self.joystick.get_axis(self.brake_axis)
|
norm = norm if abs(norm) > 0.03 else 0. # center can be noisy, deadzone of 3%
|
||||||
# Convert from [-1, 1] to [0, 1] range (triggers often start at -1 when not pressed)
|
self.axes_values[event[0]] = EXPO * norm ** 3 + (1 - EXPO) * norm # less action near center for fine control
|
||||||
brake = (brake_raw + 1) / 2 if self.brake_axis in [4, 5] else brake_raw
|
else:
|
||||||
brake = brake if brake > self.deadzone else 0.0
|
|
||||||
|
|
||||||
# Apply expo for steering
|
|
||||||
self.axes_values['steer'] = EXPO * steer**3 + (1 - EXPO) * steer # Apply expo for fine control
|
|
||||||
|
|
||||||
# Calculate combined gas/brake value for output [-1, 1] where negative is brake
|
|
||||||
self.axes_values['gb'] = accel - brake
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error reading joystick: {e}")
|
|
||||||
self.axes_values = {'gb': 0., 'steer': 0.}
|
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def send_thread(joystick):
|
def send_thread(joystick):
|
||||||
pm = messaging.PubMaster(['testJoystick'])
|
pm = messaging.PubMaster(['testJoystick'])
|
||||||
|
|
||||||
rk = Ratekeeper(100, print_delay_threshold=None)
|
rk = Ratekeeper(100, print_delay_threshold=None)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -173,6 +105,7 @@ def send_thread(joystick):
|
|||||||
joystick_msg.testJoystick.axes = [joystick.axes_values[ax] for ax in joystick.axes_order]
|
joystick_msg.testJoystick.axes = [joystick.axes_values[ax] for ax in joystick.axes_order]
|
||||||
|
|
||||||
pm.send('testJoystick', joystick_msg)
|
pm.send('testJoystick', joystick_msg)
|
||||||
|
|
||||||
rk.keep_time()
|
rk.keep_time()
|
||||||
|
|
||||||
|
|
||||||
@@ -184,12 +117,13 @@ def joystick_control_thread(joystick):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
joystick_control_thread(PyGameJoystick())
|
joystick_control_thread(Joystick())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser(description='Publishes events from your joystick to control your car.\n' +
|
parser = argparse.ArgumentParser(description='Publishes events from your joystick to control your car.\n' +
|
||||||
'openpilot must be offroad before starting joystick_control. This tool supports ' +
|
'openpilot must be offroad before starting joystick_control. This tool supports ' +
|
||||||
'PlayStation and Xbox controllers on various platforms.',
|
'a PlayStation 5 DualSense controller on the comma 3X.',
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
parser.add_argument('--keyboard', action='store_true', help='Use your keyboard instead of a joystick')
|
parser.add_argument('--keyboard', action='store_true', help='Use your keyboard instead of a joystick')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
@@ -205,12 +139,9 @@ if __name__ == '__main__':
|
|||||||
print('Buttons')
|
print('Buttons')
|
||||||
print('- `R`: Resets axes')
|
print('- `R`: Resets axes')
|
||||||
print('- `C`: Cancel cruise control')
|
print('- `C`: Cancel cruise control')
|
||||||
joystick_control_thread(Keyboard())
|
|
||||||
else:
|
else:
|
||||||
print('Using pygame joystick')
|
print('Using joystick, make sure to run cereal/messaging/bridge on your device if running over the network!')
|
||||||
print('Standard controller mapping:')
|
print('If not running on a comma device, the mapping may need to be adjusted.')
|
||||||
print('- Left stick: Steering')
|
|
||||||
print('- Right trigger (R2): Gas')
|
joystick = Keyboard() if args.keyboard else Joystick()
|
||||||
print('- Left trigger (L2): Brake')
|
joystick_control_thread(joystick)
|
||||||
print('- Triangle/Y button: Cancel')
|
|
||||||
joystick_control_thread(PyGameJoystick())
|
|
||||||
|
|||||||
@@ -19,24 +19,18 @@ def joystickd_thread():
|
|||||||
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
|
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
|
||||||
VM = VehicleModel(CP)
|
VM = VehicleModel(CP)
|
||||||
|
|
||||||
sm = messaging.SubMaster(['carState', 'onroadEvents', 'liveParameters', 'selfdriveState', 'testJoystick', 'selfdriveStateSP'], frequency=1. / DT_CTRL)
|
sm = messaging.SubMaster(['carState', 'onroadEvents', 'liveParameters', 'selfdriveState', 'testJoystick'], frequency=1. / DT_CTRL)
|
||||||
pm = messaging.PubMaster(['carControl', 'controlsState'])
|
pm = messaging.PubMaster(['carControl', 'controlsState'])
|
||||||
|
|
||||||
rk = Ratekeeper(100, print_delay_threshold=None)
|
rk = Ratekeeper(100, print_delay_threshold=None)
|
||||||
while 1:
|
while 1:
|
||||||
sm.update(0)
|
sm.update(0)
|
||||||
ss_sp = sm['selfdriveStateSP']
|
|
||||||
_lat_active = False
|
|
||||||
if ss_sp.mads.available:
|
|
||||||
_lat_active = ss_sp.mads.active
|
|
||||||
else:
|
|
||||||
_lat_active = sm['selfdriveState'].active
|
|
||||||
|
|
||||||
cc_msg = messaging.new_message('carControl')
|
cc_msg = messaging.new_message('carControl')
|
||||||
cc_msg.valid = True
|
cc_msg.valid = True
|
||||||
CC = cc_msg.carControl
|
CC = cc_msg.carControl
|
||||||
CC.enabled = sm['selfdriveState'].enabled
|
CC.enabled = sm['selfdriveState'].enabled
|
||||||
CC.latActive = _lat_active and not sm['carState'].steerFaultTemporary and not sm['carState'].steerFaultPermanent
|
CC.latActive = sm['selfdriveState'].active and not sm['carState'].steerFaultTemporary and not sm['carState'].steerFaultPermanent
|
||||||
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in sm['onroadEvents']) and CP.openpilotLongitudinalControl
|
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in sm['onroadEvents']) and CP.openpilotLongitudinalControl
|
||||||
CC.cruiseControl.cancel = sm['carState'].cruiseState.enabled and (not CC.enabled or not CP.pcmCruise)
|
CC.cruiseControl.cancel = sm['carState'].cruiseState.enabled and (not CC.enabled or not CP.pcmCruise)
|
||||||
CC.hudControl.leadDistanceBars = 2
|
CC.hudControl.leadDistanceBars = 2
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<root>
|
|
||||||
<tabbed_widget parent="main_window" name="Main Window">
|
|
||||||
<Tab tab_name="actuator data" containers="1">
|
|
||||||
<Container>
|
|
||||||
<DockSplitter sizes="0.25;0.25;0.25;0.25" count="4" orientation="-">
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-1.050000" top="1.050000" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#17becf" name="/carControl/actuators/torque"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-385.132391" top="536.899115" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#1f77b4" name="/carControl/actuators/steeringAngleDeg"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-0.364800" top="14.956815" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#ff7f0e" name="/carState/vEgoRaw"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-0.208517" top="0.149191" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#f14cc1" name="/carControl/actuators/curvature"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
</DockSplitter>
|
|
||||||
</Container>
|
|
||||||
</Tab>
|
|
||||||
<Tab tab_name="steering messages (CAN)" containers="1">
|
|
||||||
<Container>
|
|
||||||
<DockSplitter sizes="0.200218;0.200218;0.199129;0.200218;0.200218" count="5" orientation="-">
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-189.000000" top="189.000000" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#1ac938" name="/can/2/LKAS_ALT/LKAS_ANGLE_CMD"/>
|
|
||||||
<curve color="#9467bd" name="/can/128/LKAS_ALT/LKAS_ANGLE_CMD"/>
|
|
||||||
<curve color="#ff0e1c" name="/can/192/LKAS_ALT/LKAS_ANGLE_CMD"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-6.200000" top="254.200000" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#f14cc1" name="/can/128/LKAS_ALT/LKAS_ANGLE_MAX_TORQUE"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-0.025000" top="1.025000" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#d62728" name="/carState/steeringPressed"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="460.325000" top="1874.675000" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#1f77b4" name="/pandaStates/0/safetyTxBlocked"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-0.025000" top="1.025000" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#f14cc1" name="/can/1/CCNC_0x161/DAW_ICON"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
</DockSplitter>
|
|
||||||
</Container>
|
|
||||||
</Tab>
|
|
||||||
<Tab tab_name="Understanding Torque" containers="1">
|
|
||||||
<Container>
|
|
||||||
<DockSplitter sizes="0.5;0.5" count="2" orientation="-">
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-6.175000" top="253.175000" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#1f77b4" name="/can/1/LFA_ALT/LKAS_ANGLE_MAX_TORQUE"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" style="Lines" mode="TimeSeries">
|
|
||||||
<range bottom="-41.182501" top="42.082498" right="590.696728" left="429.901019"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#1ac938" name="/carState/steeringTorqueEps"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
</DockSplitter>
|
|
||||||
</Container>
|
|
||||||
</Tab>
|
|
||||||
<currentTabIndex index="1"/>
|
|
||||||
</tabbed_widget>
|
|
||||||
<use_relative_time_offset enabled="1"/>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<Plugins>
|
|
||||||
<plugin ID="DataLoad CSV">
|
|
||||||
<default time_axis="" delimiter="0"/>
|
|
||||||
</plugin>
|
|
||||||
<plugin ID="DataLoad MCAP"/>
|
|
||||||
<plugin ID="DataLoad Rlog"/>
|
|
||||||
<plugin ID="DataLoad ULog"/>
|
|
||||||
<plugin ID="Cereal Subscriber"/>
|
|
||||||
<plugin ID="UDP Server"/>
|
|
||||||
<plugin ID="WebSocket Server"/>
|
|
||||||
<plugin ID="ZMQ Subscriber"/>
|
|
||||||
<plugin ID="Fast Fourier Transform"/>
|
|
||||||
<plugin ID="Quaternion to RPY"/>
|
|
||||||
<plugin ID="Reactive Script Editor">
|
|
||||||
<library code="--[[ Helper function to create a series from arrays

 new_series: a series previously created with ScatterXY.new(name)
 prefix: prefix of the timeseries, before the index of the array
 suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.
 suffix_Y: suffix to complete the name of the series containing the Y value
 timestamp: usually the tracker_time variable
 
 Example:
 
 Assuming we have multiple series in the form:
 
 /trajectory/node.{X}/position/x
 /trajectory/node.{X}/position/y
 
 where {N} is the index of the array (integer). We can create a reactive series from the array with:
 
 new_series = ScatterXY.new("my_trajectory") 
 CreateSeriesFromArray( new_series, "/trajectory/node", "position/x", "position/y", tracker_time );
--]]

function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )
 
 --- clear previous values
 new_series:clear()
 
 --- Append points to new_series
 index = 0
 while(true) do

 x = index;
 -- if not nil, get the X coordinate from a series
 if suffix_X ~= nil then 
 series_x = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_X) )
 if series_x == nil then break end
 x = series_x:atTime(timestamp)	 
 end
 
 series_y = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_Y) )
 if series_y == nil then break end 
 y = series_y:atTime(timestamp)
 
 new_series:push_back(x,y)
 index = index+1
 end
end

--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]

function GetSeriesNamesByPrefix(prefix)
 -- GetSeriesNames(9 is a built-in function
 all_names = GetSeriesNames()
 filtered_names = {}
 for i, name in ipairs(all_names) do
 -- check the prefix
 if name:find(prefix, 1, #prefix) then
 table.insert(filtered_names, name);
 end
 end
 return filtered_names
end

--[[ Modify an existing series, applying offsets to all their X and Y values

 series: an existing timeseries, obtained with TimeseriesView.find(name)
 delta_x: offset to apply to each x value
 delta_y: offset to apply to each y value 
 
--]]

function ApplyOffsetInPlace(series, delta_x, delta_y)
 -- use C++ indeces, not Lua indeces
 for index=0, series:size()-1 do
 x,y = series:at(index)
 series:set(index, x + delta_x, y + delta_y)
 end
end
"/>
|
|
||||||
<scripts/>
|
|
||||||
</plugin>
|
|
||||||
<plugin ID="CSV Exporter"/>
|
|
||||||
</Plugins>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<customMathEquations/>
|
|
||||||
<snippets/>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
</root>
|
|
||||||
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<root>
|
|
||||||
<tabbed_widget parent="main_window" name="Main Window">
|
|
||||||
<Tab tab_name="actuator data" containers="1">
|
|
||||||
<Container>
|
|
||||||
<DockSplitter orientation="-" sizes="0.25;0.25;0.25;0.25" count="4">
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-1.050000" top="1.050000" right="722.420439" left="0.000000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#17becf" name="/carControl/actuators/torque"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-453.043646" top="538.555487" right="722.420439" left="0.000000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#1f77b4" name="/carControl/actuators/steeringAngleDeg"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-0.647461" top="26.545898" right="722.420439" left="0.000000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#ff7f0e" name="/carState/vEgoRaw"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-0.209157" top="0.175448" right="722.420439" left="0.000000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#f14cc1" name="/carControl/actuators/curvature"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
</DockSplitter>
|
|
||||||
</Container>
|
|
||||||
</Tab>
|
|
||||||
<Tab tab_name="steering messages (CAN)" containers="1">
|
|
||||||
<Container>
|
|
||||||
<DockSplitter orientation="-" sizes="0.200218;0.200218;0.199129;0.200218;0.200218" count="5">
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-189.000000" top="189.000000" right="723.115449" left="6.371879"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#b6ff00" name="/can/128/LKAS_ALT/LKAS_ANGLE_CMD"/>
|
|
||||||
<curve color="#00fab2" name="/can/0/LKAS_ALT/LKAS_ANGLE_CMD"/>
|
|
||||||
<curve color="#d62728" name="/can/192/LKAS_ALT/LKAS_ANGLE_CMD"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-6.250000" top="256.250000" right="722.420439" left="6.497277"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#00ffe8" name="/can/128/LKAS_ALT/LKAS_ANGLE_MAX_TORQUE"/>
|
|
||||||
<curve color="#e5fd00" name="/can/0/LKAS_ALT/LKAS_ANGLE_MAX_TORQUE"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-4.399729" top="4.056632" right="722.420439" left="0.000000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#ff7f0e" name="IMU_LatAccelVal_ms^2_roll_compensated"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-0.025000" top="1.025000" right="722.420439" left="0.000000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#d62728" name="/carState/steeringPressed"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-0.025000" top="1.025000" right="722.420439" left="0.000000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#f14cc1" name="/can/1/CCNC_0x161/DAW_ICON"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
</DockSplitter>
|
|
||||||
</Container>
|
|
||||||
</Tab>
|
|
||||||
<Tab tab_name="Understanding Torque" containers="1">
|
|
||||||
<Container>
|
|
||||||
<DockSplitter orientation="-" sizes="0.5;0.5" count="2">
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-6.250000" top="256.250000" right="722.420439" left="0.000000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#1f77b4" name="/can/1/LFA_ALT/LKAS_ANGLE_MAX_TORQUE"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot style="Lines" mode="TimeSeries" flip_x="false" flip_y="false">
|
|
||||||
<range bottom="-42.062501" top="78.162503" right="722.420439" left="0.000000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#1ac938" name="/carState/steeringTorqueEps"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
</DockSplitter>
|
|
||||||
</Container>
|
|
||||||
</Tab>
|
|
||||||
<currentTabIndex index="1"/>
|
|
||||||
</tabbed_widget>
|
|
||||||
<use_relative_time_offset enabled="1"/>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<Plugins>
|
|
||||||
<plugin ID="DataLoad CSV">
|
|
||||||
<default delimiter="0" time_axis=""/>
|
|
||||||
</plugin>
|
|
||||||
<plugin ID="DataLoad MCAP"/>
|
|
||||||
<plugin ID="DataLoad Rlog"/>
|
|
||||||
<plugin ID="DataLoad ULog"/>
|
|
||||||
<plugin ID="Cereal Subscriber"/>
|
|
||||||
<plugin ID="UDP Server"/>
|
|
||||||
<plugin ID="WebSocket Server"/>
|
|
||||||
<plugin ID="ZMQ Subscriber"/>
|
|
||||||
<plugin ID="Fast Fourier Transform"/>
|
|
||||||
<plugin ID="Quaternion to RPY"/>
|
|
||||||
<plugin ID="Reactive Script Editor">
|
|
||||||
<library code="--[[ Helper function to create a series from arrays

 new_series: a series previously created with ScatterXY.new(name)
 prefix: prefix of the timeseries, before the index of the array
 suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.
 suffix_Y: suffix to complete the name of the series containing the Y value
 timestamp: usually the tracker_time variable
 
 Example:
 
 Assuming we have multiple series in the form:
 
 /trajectory/node.{X}/position/x
 /trajectory/node.{X}/position/y
 
 where {N} is the index of the array (integer). We can create a reactive series from the array with:
 
 new_series = ScatterXY.new("my_trajectory") 
 CreateSeriesFromArray( new_series, "/trajectory/node", "position/x", "position/y", tracker_time );
--]]

function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )
 
 --- clear previous values
 new_series:clear()
 
 --- Append points to new_series
 index = 0
 while(true) do

 x = index;
 -- if not nil, get the X coordinate from a series
 if suffix_X ~= nil then 
 series_x = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_X) )
 if series_x == nil then break end
 x = series_x:atTime(timestamp)	 
 end
 
 series_y = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_Y) )
 if series_y == nil then break end 
 y = series_y:atTime(timestamp)
 
 new_series:push_back(x,y)
 index = index+1
 end
end

--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]

function GetSeriesNamesByPrefix(prefix)
 -- GetSeriesNames(9 is a built-in function
 all_names = GetSeriesNames()
 filtered_names = {}
 for i, name in ipairs(all_names) do
 -- check the prefix
 if name:find(prefix, 1, #prefix) then
 table.insert(filtered_names, name);
 end
 end
 return filtered_names
end

--[[ Modify an existing series, applying offsets to all their X and Y values

 series: an existing timeseries, obtained with TimeseriesView.find(name)
 delta_x: offset to apply to each x value
 delta_y: offset to apply to each y value 
 
--]]

function ApplyOffsetInPlace(series, delta_x, delta_y)
 -- use C++ indeces, not Lua indeces
 for index=0, series:size()-1 do
 x,y = series:at(index)
 series:set(index, x + delta_x, y + delta_y)
 end
end
"/>
|
|
||||||
<scripts/>
|
|
||||||
</plugin>
|
|
||||||
<plugin ID="CSV Exporter"/>
|
|
||||||
</Plugins>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<customMathEquations>
|
|
||||||
<snippet name="Desired lateral accel (roll compensated)">
|
|
||||||
<global></global>
|
|
||||||
<function>return (value * v1 ^ 2) - (v2 * 9.81)</function>
|
|
||||||
<linked_source>/controlsState/desiredCurvature</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/vEgo</v1>
|
|
||||||
<v2>/liveParameters/roll</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="Actual lateral accel (roll compensated)">
|
|
||||||
<global></global>
|
|
||||||
<function>return (value * v1 ^ 2) - (v2 * 9.81)</function>
|
|
||||||
<linked_source>/controlsState/curvature</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/vEgo</v1>
|
|
||||||
<v2>/liveParameters/roll</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="IMU_LatAccelVal_ms^2_roll_compensated">
|
|
||||||
<global></global>
|
|
||||||
<function>if (v1 == 0 and v2 == 1) then
|
|
||||||
return (value * -9.8) - (v3 * 9.81)
|
|
||||||
end
|
|
||||||
--return 0
|
|
||||||
return (value * -9.8) - (v3 * 9.81)</function>
|
|
||||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/steeringPressed</v1>
|
|
||||||
<v2>/carControl/latActive</v2>
|
|
||||||
<v3>/liveParameters/roll</v3>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="IMU_LatAccelVal_Ms^3">
|
|
||||||
<global></global>
|
|
||||||
<function>return value * -9.8</function>
|
|
||||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/steeringPressed</v1>
|
|
||||||
<v2>/carControl/latActive</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="IMU_LatAccelVal_Ms^2">
|
|
||||||
<global></global>
|
|
||||||
<function>if (v1 == 0 and v2 == 1) then
|
|
||||||
return value * -9.8
|
|
||||||
end
|
|
||||||
return 0</function>
|
|
||||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/steeringPressed</v1>
|
|
||||||
<v2>/carControl/latActive</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="roll compensated lateral acceleration">
|
|
||||||
<global></global>
|
|
||||||
<function>if (v3 == 0 and v4 == 1) then
|
|
||||||
return (value * v1 ^ 2) - (v2 * 9.81)
|
|
||||||
end
|
|
||||||
return 0</function>
|
|
||||||
<linked_source>/controlsState/curvature</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/vEgo</v1>
|
|
||||||
<v2>/liveParameters/roll</v2>
|
|
||||||
<v3>/carState/steeringPressed</v3>
|
|
||||||
<v4>/carControl/latActive</v4>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="IMU_LatAccelVal_ms^2">
|
|
||||||
<global></global>
|
|
||||||
<function>return value * -9.8</function>
|
|
||||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/steeringPressed</v1>
|
|
||||||
<v2>/carControl/latActive</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
</customMathEquations>
|
|
||||||
<snippets/>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
</root>
|
|
||||||
|
|
||||||
@@ -1,281 +0,0 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<root>
|
|
||||||
<tabbed_widget name="Main Window" parent="main_window">
|
|
||||||
<Tab containers="1" tab_name="tab1">
|
|
||||||
<Container>
|
|
||||||
<DockSplitter sizes="0.500397;0.499603" count="2" orientation="-">
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" mode="TimeSeries" style="Lines">
|
|
||||||
<range top="256.250000" left="0.000000" right="421.102293" bottom="-6.250000"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#1ac938" name="/can/1/LFA_ALT/LKAS_ANGLE_MAX_TORQUE"/>
|
|
||||||
<curve color="#17becf" name="max torque(calc)">
|
|
||||||
<transform name="Moving Average" alias="max torque(calc)[Moving Average]">
|
|
||||||
<options compensate_offset="true" value="10"/>
|
|
||||||
</transform>
|
|
||||||
</curve>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" flip_y="false" mode="TimeSeries" style="Lines">
|
|
||||||
<range top="2.776497" left="0.000000" right="421.102293" bottom="-2.918548"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve color="#f14cc1" name="desired lat accel"/>
|
|
||||||
<curve color="#888888" name="zero"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
</DockSplitter>
|
|
||||||
</Container>
|
|
||||||
</Tab>
|
|
||||||
<currentTabIndex index="0"/>
|
|
||||||
</tabbed_widget>
|
|
||||||
<use_relative_time_offset enabled="1"/>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<Plugins>
|
|
||||||
<plugin ID="DataLoad CSV">
|
|
||||||
<default time_axis="" delimiter="0"/>
|
|
||||||
</plugin>
|
|
||||||
<plugin ID="DataLoad MCAP"/>
|
|
||||||
<plugin ID="DataLoad Rlog"/>
|
|
||||||
<plugin ID="DataLoad ULog"/>
|
|
||||||
<plugin ID="Cereal Subscriber"/>
|
|
||||||
<plugin ID="UDP Server"/>
|
|
||||||
<plugin ID="WebSocket Server"/>
|
|
||||||
<plugin ID="ZMQ Subscriber"/>
|
|
||||||
<plugin ID="Fast Fourier Transform"/>
|
|
||||||
<plugin ID="Quaternion to RPY"/>
|
|
||||||
<plugin ID="Reactive Script Editor">
|
|
||||||
<library code="--[[ Helper function to create a series from arrays

 new_series: a series previously created with ScatterXY.new(name)
 prefix: prefix of the timeseries, before the index of the array
 suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.
 suffix_Y: suffix to complete the name of the series containing the Y value
 timestamp: usually the tracker_time variable
 
 Example:
 
 Assuming we have multiple series in the form:
 
 /trajectory/node.{X}/position/x
 /trajectory/node.{X}/position/y
 
 where {N} is the index of the array (integer). We can create a reactive series from the array with:
 
 new_series = ScatterXY.new("my_trajectory") 
 CreateSeriesFromArray( new_series, "/trajectory/node", "position/x", "position/y", tracker_time );
--]]

function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )
 
 --- clear previous values
 new_series:clear()
 
 --- Append points to new_series
 index = 0
 while(true) do

 x = index;
 -- if not nil, get the X coordinate from a series
 if suffix_X ~= nil then 
 series_x = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_X) )
 if series_x == nil then break end
 x = series_x:atTime(timestamp)	 
 end
 
 series_y = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_Y) )
 if series_y == nil then break end 
 y = series_y:atTime(timestamp)
 
 new_series:push_back(x,y)
 index = index+1
 end
end

--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]

function GetSeriesNamesByPrefix(prefix)
 -- GetSeriesNames(9 is a built-in function
 all_names = GetSeriesNames()
 filtered_names = {}
 for i, name in ipairs(all_names) do
 -- check the prefix
 if name:find(prefix, 1, #prefix) then
 table.insert(filtered_names, name);
 end
 end
 return filtered_names
end

--[[ Modify an existing series, applying offsets to all their X and Y values

 series: an existing timeseries, obtained with TimeseriesView.find(name)
 delta_x: offset to apply to each x value
 delta_y: offset to apply to each y value 
 
--]]

function ApplyOffsetInPlace(series, delta_x, delta_y)
 -- use C++ indeces, not Lua indeces
 for index=0, series:size()-1 do
 x,y = series:at(index)
 series:set(index, x + delta_x, y + delta_y)
 end
end
"/>
|
|
||||||
<scripts/>
|
|
||||||
</plugin>
|
|
||||||
<plugin ID="CSV Exporter"/>
|
|
||||||
</Plugins>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<previouslyLoaded_Datafiles>
|
|
||||||
<fileInfo prefix="" filename="../tmpa_e8kwpj.rlog">
|
|
||||||
<selected_datasources value=""/>
|
|
||||||
</fileInfo>
|
|
||||||
</previouslyLoaded_Datafiles>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<customMathEquations>
|
|
||||||
<snippet name="zero">
|
|
||||||
<global>min=0
|
|
||||||
max=250
|
|
||||||
max_from_speed=96
|
|
||||||
|
|
||||||
rate_lim = 500
|
|
||||||
|
|
||||||
la_deadzone = 0.38
|
|
||||||
|
|
||||||
k1=200
|
|
||||||
k2=20
|
|
||||||
k3=1.0
|
|
||||||
k4=1
|
|
||||||
k5=10
|
|
||||||
|
|
||||||
old = 0
|
|
||||||
|
|
||||||
function sign(number)
|
|
||||||
return number > 0 and 1 or (number == 0 and 0 or -1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function apply_rate_limit(old, new, limit)
|
|
||||||
return math.min(math.max(new, old - limit), old + limit)
|
|
||||||
end
|
|
||||||
|
|
||||||
function apply_deadzone(val, deadzone)
|
|
||||||
if math.abs(val) <= deadzone then
|
|
||||||
return 0.0
|
|
||||||
elseif val < 0.0 then
|
|
||||||
return val + deadzone
|
|
||||||
else
|
|
||||||
return val - deadzone
|
|
||||||
end
|
|
||||||
end</global>
|
|
||||||
<function>return 0</function>
|
|
||||||
<linked_source>/carState/aEgo</linked_source>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="max torque lj adj">
|
|
||||||
<global>min=0
|
|
||||||
max=250
|
|
||||||
max_from_speed=96
|
|
||||||
|
|
||||||
k1=200
|
|
||||||
k2=30
|
|
||||||
k3=1
|
|
||||||
k4=1
|
|
||||||
k5=10
|
|
||||||
|
|
||||||
function sign(number)
|
|
||||||
return number > 0 and 1 or (number == 0 and 0 or -1)
|
|
||||||
end</global>
|
|
||||||
<function>return 250 - value * 20</function>
|
|
||||||
<linked_source>desired lateral jark</linked_source>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="ang_cmd rate">
|
|
||||||
<global>firstX = 0
|
|
||||||
firstY = 0
|
|
||||||
is_first = true
|
|
||||||
secondX = 0
|
|
||||||
secondY = 0
|
|
||||||
is_second = false</global>
|
|
||||||
<function>-- Wait for initial values
|
|
||||||
if (is_first) then
|
|
||||||
is_first = false
|
|
||||||
is_second = true
|
|
||||||
firstX = time
|
|
||||||
firstY = value
|
|
||||||
end
|
|
||||||
|
|
||||||
if (is_second) then
|
|
||||||
is_second = false
|
|
||||||
secondX = time
|
|
||||||
secondY = value
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Central derivative: dy/dx ~= f(x+delta_x)-f(x-delta_x)/(2*delta_x)
|
|
||||||
dx = time - firstX
|
|
||||||
dy = value - firstY
|
|
||||||
-- Increment
|
|
||||||
firstX = secondX
|
|
||||||
firstY = secondY
|
|
||||||
secondX = time
|
|
||||||
secondY = value
|
|
||||||
|
|
||||||
return dy/dx</function>
|
|
||||||
<linked_source>/can/1/LFA_ALT/LKAS_ANGLE_CMD</linked_source>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="max torque(calc)">
|
|
||||||
<global>min=0
|
|
||||||
max=250
|
|
||||||
max_from_speed=96
|
|
||||||
|
|
||||||
rate_lim = 500
|
|
||||||
|
|
||||||
la_deadzone = 0.38
|
|
||||||
|
|
||||||
k1=200
|
|
||||||
k2=20
|
|
||||||
k3=1.0
|
|
||||||
k4=1
|
|
||||||
k5=10
|
|
||||||
|
|
||||||
old = 0
|
|
||||||
|
|
||||||
function sign(number)
|
|
||||||
return number > 0 and 1 or (number == 0 and 0 or -1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function apply_rate_limit(old, new, limit)
|
|
||||||
return math.min(math.max(new, old - limit), old + limit)
|
|
||||||
end
|
|
||||||
|
|
||||||
function apply_deadzone(val, deadzone)
|
|
||||||
if math.abs(val) <= deadzone then
|
|
||||||
return 0.0
|
|
||||||
elseif val < 0.0 then
|
|
||||||
return val + deadzone
|
|
||||||
else
|
|
||||||
return val - deadzone
|
|
||||||
end
|
|
||||||
end</global>
|
|
||||||
<function>la = apply_deadzone(v2, la_deadzone)
|
|
||||||
lj = v3
|
|
||||||
|
|
||||||
if la == 0.0 then
|
|
||||||
lj = 0.0
|
|
||||||
end
|
|
||||||
|
|
||||||
fla = math.min(math.abs(k1 * la)^k3, max)
|
|
||||||
flj = math.min(math.abs(k2 * lj)^k4, max)
|
|
||||||
|
|
||||||
out = fla
|
|
||||||
|
|
||||||
flv = math.min(max_from_speed, k5 * v4)
|
|
||||||
|
|
||||||
out = out + flv
|
|
||||||
|
|
||||||
out = math.max(math.min(out, max), min)
|
|
||||||
|
|
||||||
if sign(la) == sign(lj) then
|
|
||||||
out = out - flj
|
|
||||||
else
|
|
||||||
out = out + flj
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
if v5 == 1.0 then
|
|
||||||
out = 0.0
|
|
||||||
end
|
|
||||||
|
|
||||||
out = math.max(math.min(out, max), min)
|
|
||||||
out = apply_rate_limit(old, out, rate_lim)
|
|
||||||
old = out
|
|
||||||
|
|
||||||
return out</function>
|
|
||||||
<linked_source>/can/1/LFA_ALT/LKAS_ANGLE_CMD</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>ang_cmd rate</v1>
|
|
||||||
<v2>desired lat accel</v2>
|
|
||||||
<v3>desired lateral jark</v3>
|
|
||||||
<v4>/carState/vEgo</v4>
|
|
||||||
<v5>/can/1/LFA_ALT/LKAS_ANGLE_ACTIVE</v5>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="desired lateral jark">
|
|
||||||
<global>firstX = 0
|
|
||||||
firstY = 0
|
|
||||||
is_first = true
|
|
||||||
secondX = 0
|
|
||||||
secondY = 0
|
|
||||||
is_second = false</global>
|
|
||||||
<function>-- Wait for initial values
|
|
||||||
if (is_first) then
|
|
||||||
is_first = false
|
|
||||||
is_second = true
|
|
||||||
firstX = time
|
|
||||||
firstY = value
|
|
||||||
end
|
|
||||||
|
|
||||||
if (is_second) then
|
|
||||||
is_second = false
|
|
||||||
secondX = time
|
|
||||||
secondY = value
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Central derivative: dy/dx ~= f(x+delta_x)-f(x-delta_x)/(2*delta_x)
|
|
||||||
dx = time - firstX
|
|
||||||
dy = value - firstY
|
|
||||||
-- Increment
|
|
||||||
firstX = secondX
|
|
||||||
firstY = secondY
|
|
||||||
secondX = time
|
|
||||||
secondY = value
|
|
||||||
|
|
||||||
return dy/dx</function>
|
|
||||||
<linked_source>desired lat accel</linked_source>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="abs(des la accel)">
|
|
||||||
<global></global>
|
|
||||||
<function>return math.abs(value)</function>
|
|
||||||
<linked_source>desired lat accel</linked_source>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="desired lat accel">
|
|
||||||
<global></global>
|
|
||||||
<function>return value * v1^2</function>
|
|
||||||
<linked_source>/controlsState/desiredCurvature</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/vEgo</v1>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="abs(ang_cmd)">
|
|
||||||
<global></global>
|
|
||||||
<function>return math.abs(value)</function>
|
|
||||||
<linked_source>/can/1/LFA_ALT/LKAS_ANGLE_CMD</linked_source>
|
|
||||||
</snippet>
|
|
||||||
</customMathEquations>
|
|
||||||
<snippets/>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
</root>
|
|
||||||
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
|
||||||
<root>
|
|
||||||
<tabbed_widget parent="main_window" name="Main Window">
|
|
||||||
<Tab tab_name="tab1" containers="1">
|
|
||||||
<Container>
|
|
||||||
<DockSplitter sizes="0.25;0.25;0.25;0.25" count="4" orientation="-">
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
|
||||||
<range bottom="-3.582051" right="1431.113121" top="5.314632" left="5.322399"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve name="Actual lateral accel (roll compensated)" color="#1ac938"/>
|
|
||||||
<curve name="Desired lateral accel (roll compensated)" color="#ff7f0e"/>
|
|
||||||
<curve name="IMU_LatAccelVal_ms^2" color="#f14cc1"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
|
||||||
<range bottom="-3.741271" right="1431.113121" top="3.756006" left="5.322399"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve name="roll compensated lateral acceleration" color="#ff7f0e"/>
|
|
||||||
<curve name="IMU_LatAccelVal_Ms^2" color="#1ac938"/>
|
|
||||||
<curve name="IMU_LatAccelVal_ms^2_roll_compensated" color="#9467bd"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
|
||||||
<range bottom="-0.025000" right="1431.113121" top="1.025000" left="5.322399"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve name="/carState/steeringPressed" color="#0097ff"/>
|
|
||||||
<curve name="/carOutput/actuatorsOutput/torque" color="#d62728"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
|
||||||
<range bottom="-1.660728" right="1431.113121" top="67.942958" left="5.322399"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve name="/carState/vEgo" color="#f14cc1">
|
|
||||||
<transform name="Scale/Offset" alias="/carState/vEgo[Scale/Offset]">
|
|
||||||
<options value_scale="2.23694" time_offset="0" value_offset="0"/>
|
|
||||||
</transform>
|
|
||||||
</curve>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
</DockSplitter>
|
|
||||||
</Container>
|
|
||||||
</Tab>
|
|
||||||
<Tab tab_name="tab2" containers="1">
|
|
||||||
<Container>
|
|
||||||
<DockSplitter sizes="0.5;0.5" count="2" orientation="-">
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
|
||||||
<range bottom="30595.900000" right="1431.113121" top="34884.100000" left="5.322399"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve name="/can/1/IMU_01_10ms/IMU_RollRtVal" color="#17becf"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
<DockArea name="...">
|
|
||||||
<plot flip_x="false" style="Lines" flip_y="false" mode="TimeSeries">
|
|
||||||
<range bottom="-0.058795" right="1431.113121" top="0.072448" left="5.322399"/>
|
|
||||||
<limitY/>
|
|
||||||
<curve name="/liveParameters/roll" color="#bcbd22"/>
|
|
||||||
</plot>
|
|
||||||
</DockArea>
|
|
||||||
</DockSplitter>
|
|
||||||
</Container>
|
|
||||||
</Tab>
|
|
||||||
<currentTabIndex index="1"/>
|
|
||||||
</tabbed_widget>
|
|
||||||
<use_relative_time_offset enabled="1"/>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<Plugins>
|
|
||||||
<plugin ID="DataLoad CSV">
|
|
||||||
<default time_axis="" delimiter="0"/>
|
|
||||||
</plugin>
|
|
||||||
<plugin ID="DataLoad MCAP"/>
|
|
||||||
<plugin ID="DataLoad Rlog"/>
|
|
||||||
<plugin ID="DataLoad ULog"/>
|
|
||||||
<plugin ID="Cereal Subscriber"/>
|
|
||||||
<plugin ID="UDP Server"/>
|
|
||||||
<plugin ID="WebSocket Server"/>
|
|
||||||
<plugin ID="ZMQ Subscriber"/>
|
|
||||||
<plugin ID="Fast Fourier Transform"/>
|
|
||||||
<plugin ID="Quaternion to RPY"/>
|
|
||||||
<plugin ID="Reactive Script Editor">
|
|
||||||
<library code="--[[ Helper function to create a series from arrays

 new_series: a series previously created with ScatterXY.new(name)
 prefix: prefix of the timeseries, before the index of the array
 suffix_X: suffix to complete the name of the series containing the X value. If [nil], use the index of the array.
 suffix_Y: suffix to complete the name of the series containing the Y value
 timestamp: usually the tracker_time variable
 
 Example:
 
 Assuming we have multiple series in the form:
 
 /trajectory/node.{X}/position/x
 /trajectory/node.{X}/position/y
 
 where {N} is the index of the array (integer). We can create a reactive series from the array with:
 
 new_series = ScatterXY.new("my_trajectory") 
 CreateSeriesFromArray( new_series, "/trajectory/node", "position/x", "position/y", tracker_time );
--]]

function CreateSeriesFromArray( new_series, prefix, suffix_X, suffix_Y, timestamp )
 
 --- clear previous values
 new_series:clear()
 
 --- Append points to new_series
 index = 0
 while(true) do

 x = index;
 -- if not nil, get the X coordinate from a series
 if suffix_X ~= nil then 
 series_x = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_X) )
 if series_x == nil then break end
 x = series_x:atTime(timestamp)	 
 end
 
 series_y = TimeseriesView.find( string.format( "%s.%d/%s", prefix, index, suffix_Y) )
 if series_y == nil then break end 
 y = series_y:atTime(timestamp)
 
 new_series:push_back(x,y)
 index = index+1
 end
end

--[[ Similar to the built-in function GetSeriesNames(), but select only the names with a give prefix. --]]

function GetSeriesNamesByPrefix(prefix)
 -- GetSeriesNames(9 is a built-in function
 all_names = GetSeriesNames()
 filtered_names = {}
 for i, name in ipairs(all_names) do
 -- check the prefix
 if name:find(prefix, 1, #prefix) then
 table.insert(filtered_names, name);
 end
 end
 return filtered_names
end

--[[ Modify an existing series, applying offsets to all their X and Y values

 series: an existing timeseries, obtained with TimeseriesView.find(name)
 delta_x: offset to apply to each x value
 delta_y: offset to apply to each y value 
 
--]]

function ApplyOffsetInPlace(series, delta_x, delta_y)
 -- use C++ indeces, not Lua indeces
 for index=0, series:size()-1 do
 x,y = series:at(index)
 series:set(index, x + delta_x, y + delta_y)
 end
end
"/>
|
|
||||||
<scripts/>
|
|
||||||
</plugin>
|
|
||||||
<plugin ID="CSV Exporter"/>
|
|
||||||
</Plugins>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
<customMathEquations>
|
|
||||||
<snippet name="IMU_LatAccelVal_ms^2">
|
|
||||||
<global></global>
|
|
||||||
<function>return value * -9.8</function>
|
|
||||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/steeringPressed</v1>
|
|
||||||
<v2>/carControl/latActive</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="roll compensated lateral acceleration">
|
|
||||||
<global></global>
|
|
||||||
<function>if (v3 == 0 and v4 == 1) then
|
|
||||||
return (value * v1 ^ 2) - (v2 * 9.81)
|
|
||||||
end
|
|
||||||
return 0</function>
|
|
||||||
<linked_source>/controlsState/curvature</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/vEgo</v1>
|
|
||||||
<v2>/liveParameters/roll</v2>
|
|
||||||
<v3>/carState/steeringPressed</v3>
|
|
||||||
<v4>/carControl/latActive</v4>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="IMU_LatAccelVal_Ms^2">
|
|
||||||
<global></global>
|
|
||||||
<function>if (v1 == 0 and v2 == 1) then
|
|
||||||
return value * -9.8
|
|
||||||
end
|
|
||||||
return 0</function>
|
|
||||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/steeringPressed</v1>
|
|
||||||
<v2>/carControl/latActive</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="IMU_LatAccelVal_Ms^3">
|
|
||||||
<global></global>
|
|
||||||
<function>return value * -9.8</function>
|
|
||||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/steeringPressed</v1>
|
|
||||||
<v2>/carControl/latActive</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="IMU_LatAccelVal_ms^2_roll_compensated">
|
|
||||||
<global></global>
|
|
||||||
<function>
|
|
||||||
|
|
||||||
if (v1 == 0 and v2 == 1) then
|
|
||||||
return (value * -9.8) - (v3 * 9.81)
|
|
||||||
end
|
|
||||||
return 0</function>
|
|
||||||
<linked_source>/can/1/IMU_01_10ms/IMU_LatAccelVal</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/steeringPressed</v1>
|
|
||||||
<v2>/carControl/latActive</v2>
|
|
||||||
<v3>/liveParameters/roll</v3>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="Actual lateral accel (roll compensated)">
|
|
||||||
<global></global>
|
|
||||||
<function>return (value * v1 ^ 2) - (v2 * 9.81)</function>
|
|
||||||
<linked_source>/controlsState/curvature</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/vEgo</v1>
|
|
||||||
<v2>/liveParameters/roll</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
<snippet name="Desired lateral accel (roll compensated)">
|
|
||||||
<global></global>
|
|
||||||
<function>return (value * v1 ^ 2) - (v2 * 9.81)</function>
|
|
||||||
<linked_source>/controlsState/desiredCurvature</linked_source>
|
|
||||||
<additional_sources>
|
|
||||||
<v1>/carState/vEgo</v1>
|
|
||||||
<v2>/liveParameters/roll</v2>
|
|
||||||
</additional_sources>
|
|
||||||
</snippet>
|
|
||||||
</customMathEquations>
|
|
||||||
<snippets/>
|
|
||||||
<!-- - - - - - - - - - - - - - - -->
|
|
||||||
</root>
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user