November 1st, 2025 Update
1
.github/update_date
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
2025-11-01
|
||||||
22
.github/workflows/schedule_update.yaml
vendored
@ -9,6 +9,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
BRANCH: FrogPilot-Staging
|
BRANCH: FrogPilot-Staging
|
||||||
|
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
schedule-update:
|
schedule-update:
|
||||||
@ -22,6 +23,7 @@ jobs:
|
|||||||
- name: Checkout ${{ env.BRANCH }}
|
- name: Checkout ${{ env.BRANCH }}
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
|
persist-credentials: false
|
||||||
ref: ${{ env.BRANCH }}
|
ref: ${{ env.BRANCH }}
|
||||||
fetch-depth: 3
|
fetch-depth: 3
|
||||||
|
|
||||||
@ -42,16 +44,30 @@ jobs:
|
|||||||
echo "COMMITTER_DATE=$COMMITTER_DATE" >> $GITHUB_ENV
|
echo "COMMITTER_DATE=$COMMITTER_DATE" >> $GITHUB_ENV
|
||||||
echo "TARGET_COMMIT=$TARGET_COMMIT" >> $GITHUB_ENV
|
echo "TARGET_COMMIT=$TARGET_COMMIT" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Create Fixup Commit for ${{ env.TARGET_COMMIT }}
|
- name: Create Fixup Commit if Changes Exist
|
||||||
run: git commit --fixup="${{ env.TARGET_COMMIT }}"
|
id: fixup_commit
|
||||||
|
run: |
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
echo "No changes to commit."
|
||||||
|
echo "has_changes=false" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "Changes found, creating fixup commit."
|
||||||
|
git commit --fixup="${{ env.TARGET_COMMIT }}"
|
||||||
|
echo "has_changes=true" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Autosquash Fixup into Target Commit
|
- name: Autosquash Fixup into Target Commit
|
||||||
|
if: steps.fixup_commit.outputs.has_changes == 'true'
|
||||||
run: |
|
run: |
|
||||||
GIT_SEQUENCE_EDITOR=: git rebase --autosquash -i HEAD~3
|
GIT_SEQUENCE_EDITOR=: git rebase --autosquash -i HEAD~3
|
||||||
|
|
||||||
- name: Restore Timestamps on Final Two Commits
|
- name: Restore Timestamps on Final Two Commits
|
||||||
|
if: steps.fixup_commit.outputs.has_changes == 'true'
|
||||||
run: |
|
run: |
|
||||||
git rebase --exec "GIT_COMMITTER_DATE='${{ env.COMMITTER_DATE }}' git commit --amend --no-edit --date='${{ env.AUTHOR_DATE }}'" HEAD~2
|
git rebase --exec "GIT_COMMITTER_DATE='${{ env.COMMITTER_DATE }}' git commit --amend --no-edit --date='${{ env.AUTHOR_DATE }}'" HEAD~2
|
||||||
|
|
||||||
- name: Push Updated ${{ env.BRANCH }} Branch
|
- name: Push Updated ${{ env.BRANCH }} Branch
|
||||||
run: git push origin "${{ env.BRANCH }}" --force-with-lease
|
if: steps.fixup_commit.outputs.has_changes == 'true'
|
||||||
|
run: |
|
||||||
|
git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}
|
||||||
|
git push origin "${{ env.BRANCH }}" --force-with-lease
|
||||||
|
|||||||
4
.github/workflows/update_pr_branch.yaml
vendored
@ -3,12 +3,12 @@ name: Update MAKE-PRS-HERE
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- FrogPilot-Staging
|
- FrogPilot-Testing
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||||
|
|
||||||
SOURCE_BRANCH: FrogPilot-Staging
|
SOURCE_BRANCH: FrogPilot-Testing
|
||||||
TARGET_BRANCH: MAKE-PRS-HERE
|
TARGET_BRANCH: MAKE-PRS-HERE
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@ -530,14 +530,14 @@ struct CarParams {
|
|||||||
|
|
||||||
struct LateralTorqueTuning {
|
struct LateralTorqueTuning {
|
||||||
useSteeringAngle @0 :Bool;
|
useSteeringAngle @0 :Bool;
|
||||||
kp @1 :Float32;
|
|
||||||
ki @2 :Float32;
|
|
||||||
kd @8 : Float32;
|
|
||||||
friction @3 :Float32;
|
friction @3 :Float32;
|
||||||
kf @4 :Float32;
|
|
||||||
steeringAngleDeadzoneDeg @5 :Float32;
|
steeringAngleDeadzoneDeg @5 :Float32;
|
||||||
latAccelFactor @6 :Float32;
|
latAccelFactor @6 :Float32;
|
||||||
latAccelOffset @7 :Float32;
|
latAccelOffset @7 :Float32;
|
||||||
|
kpDEPRECATED @1 :Float32;
|
||||||
|
kiDEPRECATED @2 :Float32;
|
||||||
|
kfDEPRECATED @4 :Float32;
|
||||||
|
kdDEPRECATED @8 : Float32;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LongitudinalPIDTuning {
|
struct LongitudinalPIDTuning {
|
||||||
@ -545,7 +545,7 @@ struct CarParams {
|
|||||||
kpV @1 :List(Float32);
|
kpV @1 :List(Float32);
|
||||||
kiBP @2 :List(Float32);
|
kiBP @2 :List(Float32);
|
||||||
kiV @3 :List(Float32);
|
kiV @3 :List(Float32);
|
||||||
kf @6 :Float32;
|
kfDEPRECATED @6 :Float32;
|
||||||
deadzoneBP @4 :List(Float32);
|
deadzoneBP @4 :List(Float32);
|
||||||
deadzoneV @5 :List(Float32);
|
deadzoneV @5 :List(Float32);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -216,6 +216,8 @@ struct FrogPilotPlan @0xa1680744031fdb2d {
|
|||||||
trackingLead @32 :Bool;
|
trackingLead @32 :Bool;
|
||||||
unconfirmedSlcSpeedLimit @33 :Float32;
|
unconfirmedSlcSpeedLimit @33 :Float32;
|
||||||
vCruise @34 :Float32;
|
vCruise @34 :Float32;
|
||||||
|
weatherDaytime @35 :Bool;
|
||||||
|
weatherId @36 :Int16;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FrogPilotRadarState @0xcb9fd56c7057593a {
|
struct FrogPilotRadarState @0xcb9fd56c7057593a {
|
||||||
|
|||||||
@ -795,6 +795,8 @@ struct ControlsState @0x97ff69c53601abf1 {
|
|||||||
saturated @7 :Bool;
|
saturated @7 :Bool;
|
||||||
actualLateralAccel @9 :Float32;
|
actualLateralAccel @9 :Float32;
|
||||||
desiredLateralAccel @10 :Float32;
|
desiredLateralAccel @10 :Float32;
|
||||||
|
desiredLateralJerk @11 :Float32;
|
||||||
|
version @12 :Int32;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LateralLQRState {
|
struct LateralLQRState {
|
||||||
|
|||||||
@ -268,6 +268,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"CESpeed", PERSISTENT},
|
{"CESpeed", PERSISTENT},
|
||||||
{"CESpeedLead", PERSISTENT},
|
{"CESpeedLead", PERSISTENT},
|
||||||
{"CEStatus", CLEAR_ON_OFFROAD_TRANSITION},
|
{"CEStatus", CLEAR_ON_OFFROAD_TRANSITION},
|
||||||
|
{"CEStopLights", PERSISTENT},
|
||||||
{"CEStoppedLead", PERSISTENT},
|
{"CEStoppedLead", PERSISTENT},
|
||||||
{"ClusterOffset", PERSISTENT},
|
{"ClusterOffset", PERSISTENT},
|
||||||
{"ColorToDownload", CLEAR_ON_MANAGER_START},
|
{"ColorToDownload", CLEAR_ON_MANAGER_START},
|
||||||
@ -356,10 +357,22 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"HideSpeedLimit", PERSISTENT},
|
{"HideSpeedLimit", PERSISTENT},
|
||||||
{"HigherBitrate", PERSISTENT},
|
{"HigherBitrate", PERSISTENT},
|
||||||
{"HolidayThemes", PERSISTENT},
|
{"HolidayThemes", PERSISTENT},
|
||||||
|
{"HondaAltTune", PERSISTENT},
|
||||||
|
{"HondaLowSpeedPedal", PERSISTENT},
|
||||||
|
{"HondaMaxBrake", PERSISTENT},
|
||||||
{"HumanAcceleration", PERSISTENT},
|
{"HumanAcceleration", PERSISTENT},
|
||||||
{"HumanFollowing", PERSISTENT},
|
{"HumanFollowing", PERSISTENT},
|
||||||
|
{"HumanLaneChanges", PERSISTENT},
|
||||||
{"IconToDownload", CLEAR_ON_MANAGER_START},
|
{"IconToDownload", CLEAR_ON_MANAGER_START},
|
||||||
{"IncreasedStoppedDistance", PERSISTENT},
|
{"IncreasedStoppedDistance", PERSISTENT},
|
||||||
|
{"IncreaseFollowingLowVisibility", PERSISTENT},
|
||||||
|
{"IncreaseFollowingRain", PERSISTENT},
|
||||||
|
{"IncreaseFollowingRainStorm", PERSISTENT},
|
||||||
|
{"IncreaseFollowingSnow", PERSISTENT},
|
||||||
|
{"IncreasedStoppedDistanceLowVisibility", PERSISTENT},
|
||||||
|
{"IncreasedStoppedDistanceRain", PERSISTENT},
|
||||||
|
{"IncreasedStoppedDistanceRainStorm", PERSISTENT},
|
||||||
|
{"IncreasedStoppedDistanceSnow", PERSISTENT},
|
||||||
{"IncreaseThermalLimits", PERSISTENT},
|
{"IncreaseThermalLimits", PERSISTENT},
|
||||||
{"IssueReported", CLEAR_ON_MANAGER_START},
|
{"IssueReported", CLEAR_ON_MANAGER_START},
|
||||||
{"KonikDongleId", PERSISTENT},
|
{"KonikDongleId", PERSISTENT},
|
||||||
@ -447,6 +460,14 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"RainbowPath", PERSISTENT},
|
{"RainbowPath", PERSISTENT},
|
||||||
{"RandomEvents", PERSISTENT},
|
{"RandomEvents", PERSISTENT},
|
||||||
{"RandomThemes", PERSISTENT},
|
{"RandomThemes", PERSISTENT},
|
||||||
|
{"ReduceAccelerationLowVisibility", PERSISTENT},
|
||||||
|
{"ReduceAccelerationRain", PERSISTENT},
|
||||||
|
{"ReduceAccelerationRainStorm", PERSISTENT},
|
||||||
|
{"ReduceAccelerationSnow", PERSISTENT},
|
||||||
|
{"ReduceLateralAccelerationLowVisibility", PERSISTENT},
|
||||||
|
{"ReduceLateralAccelerationRain", PERSISTENT},
|
||||||
|
{"ReduceLateralAccelerationRainStorm", PERSISTENT},
|
||||||
|
{"ReduceLateralAccelerationSnow", PERSISTENT},
|
||||||
{"RefuseVolume", PERSISTENT},
|
{"RefuseVolume", PERSISTENT},
|
||||||
{"RelaxedFollow", PERSISTENT},
|
{"RelaxedFollow", PERSISTENT},
|
||||||
{"RelaxedJerkAcceleration", PERSISTENT},
|
{"RelaxedJerkAcceleration", PERSISTENT},
|
||||||
@ -536,6 +557,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"StoppingDecelRate", PERSISTENT},
|
{"StoppingDecelRate", PERSISTENT},
|
||||||
{"StoppingDecelRateStock", PERSISTENT},
|
{"StoppingDecelRateStock", PERSISTENT},
|
||||||
{"StoppedTimer", PERSISTENT},
|
{"StoppedTimer", PERSISTENT},
|
||||||
|
{"SubaruSNG", PERSISTENT},
|
||||||
{"TacoTune", PERSISTENT},
|
{"TacoTune", PERSISTENT},
|
||||||
{"TacoTuneHacks", PERSISTENT},
|
{"TacoTuneHacks", PERSISTENT},
|
||||||
{"TestAlert", CLEAR_ON_MANAGER_START},
|
{"TestAlert", CLEAR_ON_MANAGER_START},
|
||||||
@ -543,7 +565,6 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"ThemeDownloadProgress", CLEAR_ON_MANAGER_START},
|
{"ThemeDownloadProgress", CLEAR_ON_MANAGER_START},
|
||||||
{"ThemesDownloaded", PERSISTENT},
|
{"ThemesDownloaded", PERSISTENT},
|
||||||
{"TinygradUpdateAvailable", PERSISTENT},
|
{"TinygradUpdateAvailable", PERSISTENT},
|
||||||
{"TogglesUpdated", PERSISTENT},
|
|
||||||
{"ToyotaDoors", PERSISTENT},
|
{"ToyotaDoors", PERSISTENT},
|
||||||
{"TrafficFollow", PERSISTENT},
|
{"TrafficFollow", PERSISTENT},
|
||||||
{"TrafficJerkAcceleration", PERSISTENT},
|
{"TrafficJerkAcceleration", PERSISTENT},
|
||||||
@ -558,6 +579,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"UnlimitedLength", PERSISTENT},
|
{"UnlimitedLength", PERSISTENT},
|
||||||
{"UnlockDoors", PERSISTENT},
|
{"UnlockDoors", PERSISTENT},
|
||||||
{"Updated", PERSISTENT},
|
{"Updated", PERSISTENT},
|
||||||
|
{"UpdatedToggles", PERSISTENT},
|
||||||
{"UpdateSpeedLimits", CLEAR_ON_MANAGER_START},
|
{"UpdateSpeedLimits", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdateSpeedLimitsStatus", CLEAR_ON_MANAGER_START},
|
{"UpdateSpeedLimitsStatus", CLEAR_ON_MANAGER_START},
|
||||||
{"UpdateTinygrad", CLEAR_ON_MANAGER_START},
|
{"UpdateTinygrad", CLEAR_ON_MANAGER_START},
|
||||||
@ -574,6 +596,8 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"VoltSNG", PERSISTENT},
|
{"VoltSNG", PERSISTENT},
|
||||||
{"WarningImmediateVolume", PERSISTENT},
|
{"WarningImmediateVolume", PERSISTENT},
|
||||||
{"WarningSoftVolume", PERSISTENT},
|
{"WarningSoftVolume", PERSISTENT},
|
||||||
|
{"WeatherPresets", PERSISTENT},
|
||||||
|
{"WeatherToken", PERSISTENT | DONT_LOG},
|
||||||
{"WheelIcon", PERSISTENT},
|
{"WheelIcon", PERSISTENT},
|
||||||
{"WheelSpeed", PERSISTENT},
|
{"WheelSpeed", PERSISTENT},
|
||||||
{"WheelToDownload", CLEAR_ON_MANAGER_START},
|
{"WheelToDownload", CLEAR_ON_MANAGER_START},
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 630 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 52 KiB |
@ -12,7 +12,10 @@ from urllib.parse import quote_plus
|
|||||||
from openpilot.common.basedir import BASEDIR
|
from openpilot.common.basedir import BASEDIR
|
||||||
from openpilot.frogpilot.assets.download_functions import GITLAB_URL, download_file, get_remote_file_size, get_repository_url, handle_error, handle_request_error, verify_download
|
from openpilot.frogpilot.assets.download_functions import GITLAB_URL, download_file, get_remote_file_size, get_repository_url, handle_error, handle_request_error, verify_download
|
||||||
from openpilot.frogpilot.common.frogpilot_utilities import delete_file, extract_tar, load_json_file, update_json_file
|
from openpilot.frogpilot.common.frogpilot_utilities import delete_file, extract_tar, load_json_file, update_json_file
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import DEFAULT_MODEL, MODELS_PATH, RESOURCES_REPO, TINYGRAD_FILES, params, params_default, params_memory, update_frogpilot_toggles
|
from openpilot.frogpilot.common.frogpilot_variables import (
|
||||||
|
DEFAULT_MODEL, DEFAULT_MODEL_NAME, DEFAULT_MODEL_VERSION, MODELS_PATH, RESOURCES_REPO, TINYGRAD_FILES,
|
||||||
|
params, params_default, params_memory, update_frogpilot_toggles
|
||||||
|
)
|
||||||
|
|
||||||
VERSION = "v16"
|
VERSION = "v16"
|
||||||
VERSION_PATH = MODELS_PATH / "model_version"
|
VERSION_PATH = MODELS_PATH / "model_version"
|
||||||
@ -528,3 +531,13 @@ class ModelManager:
|
|||||||
|
|
||||||
VERSION_PATH.write_text(VERSION)
|
VERSION_PATH.write_text(VERSION)
|
||||||
print(f"Updated {VERSION_PATH} to {VERSION}")
|
print(f"Updated {VERSION_PATH} to {VERSION}")
|
||||||
|
|
||||||
|
if len(self.available_models) != len(self.available_model_names) or len(self.available_models) != len(self.model_versions):
|
||||||
|
print("Model lists are out of sync. Resetting parameters...")
|
||||||
|
self.available_models = DEFAULT_MODEL
|
||||||
|
self.available_model_names = DEFAULT_MODEL_NAME
|
||||||
|
self.model_versions = DEFAULT_MODEL_VERSION
|
||||||
|
|
||||||
|
params.put("AvailableModels", self.available_models)
|
||||||
|
params.put("AvailableModelNames", self.available_model_names)
|
||||||
|
params.put("ModelVersions", self.model_versions)
|
||||||
|
|||||||
1
frogpilot/assets/nnff_models/CHEVROLET_BOLT_EUV.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"input_std":[[9.281861],[1.8477924],[0.7977224],[0.047467366],[1.7969038],[1.8168812],[1.8351218],[1.785757],[1.7335743],[1.6658221],[1.5893887],[0.047346078],[0.0473731],[0.047383286],[0.047291175],[0.047300573],[0.04712479],[0.046799928]],"model_test_loss":0.027355343103408813,"input_size":18,"current_date_and_time":"2023-08-05_05-11-44","input_mean":[[21.655252],[-0.07694559],[-0.006081294],[-0.007598456],[-0.07309746],[-0.075890236],[-0.07804942],[-0.076106496],[-0.07184982],[-0.06528668],[-0.060404416],[-0.0077262702],[-0.0077046235],[-0.0076850485],[-0.007687444],[-0.007708868],[-0.0077959923],[-0.008017422]],"input_vars":["v_ego","lateral_accel","lateral_jerk","roll","lateral_accel_m03","lateral_accel_m02","lateral_accel_m01","lateral_accel_p03","lateral_accel_p06","lateral_accel_p10","lateral_accel_p15","roll_m03","roll_m02","roll_m01","roll_p03","roll_p06","roll_p10","roll_p15"],"output_size":1,"layers":[{"dense_1_b":[[-0.35776415],[-0.126288],[0.007988413],[0.03850029],[-0.056796823],[0.0072075897],[0.17376427]],"dense_1_W":[[0.010538558,6.7293744,-0.007391298,-1.035045,-0.47446147,1.0940393,0.08225446,-0.5795131,0.573115,1.82923,-0.16999252,0.8818023,0.03560901,-0.9470653,-1.042151,1.1532398,1.9009485,-1.2265956],[0.009010456,-1.3618345,0.039026346,0.22943486,-0.6669799,-0.768271,-0.16828564,-0.13406865,0.19760236,-0.18953702,-0.019137766,0.1468623,0.26367718,0.4732375,0.73679143,0.62450147,0.30198866,-0.93340015],[-0.044318866,2.2138615,9.620889,-0.66480356,-0.06849887,-0.038568456,-0.30580127,-0.088089585,0.31187677,0.5968372,-1.1462088,0.13234706,0.29166338,-0.69978577,-0.01790655,-0.097928315,-0.56950736,0.7560642],[1.3758256,0.8700429,-0.24295154,0.20832618,-0.7735097,1.0379355,-0.60753095,-0.5457418,-1.0892137,-0.6708325,0.24982774,0.09251328,0.08596103,-0.58034134,-0.3046114,-0.19754426,0.006461508,0.5989185],[0.06314328,-2.492993,-0.28200585,0.49902886,0.8513198,-0.5704965,1.0960953,-0.08426956,-0.76074624,0.10669376,0.02775254,-0.42194095,-0.34657434,-0.10863868,0.17019278,0.0963825,-0.10169116,0.21243806],[0.007984091,-1.9276509,-0.0013926353,0.04057924,1.4438432,1.3440262,-2.506722,1.700801,0.72410774,0.13471895,-0.18753268,0.7303607,0.018133093,-0.71643597,0.07050904,-0.30161944,0.085108586,0.061202843],[0.9413167,-0.9954305,-0.19510143,-0.4711845,-0.12398665,-0.45175523,1.0616771,0.28550953,-0.55543137,-0.21576759,-0.2364377,-0.012782618,-0.050565187,0.257694,-0.20975965,0.00022543047,-0.08760746,0.4983852]],"activation":"σ"},{"dense_2_W":[[-0.71804935,0.017023304,-0.099854074,-0.3262651,-0.402829,-0.12073083,0.13537839],[-0.44002575,-0.1071093,-0.58886194,-0.17319413,-0.21134079,0.23135148,0.0006880979],[-0.55711204,-0.8693639,-0.6443761,-0.7382846,0.18980889,-0.6082511,-0.63103676],[0.11338112,-0.5327033,0.2856197,0.32239884,-0.72682667,0.5302305,-0.45094746],[-0.35197002,-0.14440043,-0.025249843,-0.48697743,0.3340018,-0.25992322,0.0050561456],[0.34757507,0.15670523,-0.14263277,0.50704384,-0.020171141,0.6408679,-0.3074123],[0.40258837,-0.59363264,0.35948923,-0.060853776,-0.0072541097,0.89743376,-0.49789146],[-0.63476,0.29580453,0.1689314,-0.5061521,0.24901053,-0.23218995,0.57968193],[-0.66173035,0.50861925,-0.5845035,-0.6602214,0.8341883,-0.31437424,0.8046359],[0.038493533,0.15464582,-0.04848341,-0.57820857,-0.25891733,-0.47527292,0.21441916],[-0.15464531,-0.07454202,-0.8215851,-0.12614948,-0.5924209,0.00017916794,0.24154592],[0.6091424,-0.112086505,0.1144111,-0.31035227,-0.9237534,0.041003596,-0.3542808],[0.2989792,-0.23780549,0.116059326,-0.6056522,0.5499526,-0.9001413,0.5200723]],"activation":"σ","dense_2_b":[[-0.2638964],[-0.24607328],[-0.15493082],[-0.0071187904],[-0.23515384],[-0.09098133],[-0.034066215],[0.03609036],[-0.03842933],[-0.042302527],[-0.2439947],[-0.16342077],[-0.01030317]]},{"dense_3_W":[[0.45771673,-0.2084603,0.3570187,0.35835707,0.13684571,-0.582958,0.29889587,0.43543494,0.11841301,-0.26185623,-0.4988437,0.5752996,-0.28057483],[-0.19594137,0.050280698,-0.29057446,-0.2829161,-0.16987291,-0.21278952,-0.59946907,0.21295123,0.7040468,0.53549695,-0.52553934,-0.19560973,0.6233473],[-0.19091003,0.08669418,-0.5792192,0.57799137,-0.36263424,0.6037143,0.27898273,-0.30951327,-0.3572644,0.46720102,-0.5403428,0.32415462,-0.60570025]],"activation":"identity","dense_3_b":[[-0.0047377176],[0.023170695],[-0.021546118]]},{"dense_4_W":[[-0.12453941,-1.006034,0.96776205]],"dense_4_b":[[-0.02351544]],"activation":"identity"}]}
|
||||||
1
frogpilot/assets/nnff_models/KIA_NIRO_PHEV_2022.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"input_std":[[8.716972],[1.5770903],[0.76125735],[0.035141002],[1.6173459],[1.608055],[1.5956668],[1.495505],[1.4262352],[1.3462695],[1.2594373],[0.035050083],[0.035089202],[0.035124455],[0.035208944],[0.035322115],[0.035380527],[0.035195734]],"model_test_loss":0.02083713933825493,"input_size":18,"current_date_and_time":"2025-07-15_19-46-38","input_mean":[[16.164469],[-0.030030865],[0.4530188],[-0.011929912],[-0.029048208],[-0.029084828],[-0.028234662],[-0.030135768],[-0.026924115],[-0.022959951],[-0.021531954],[-0.011769504],[-0.011809296],[-0.011859953],[-0.012107499],[-0.012191469],[-0.012183576],[-0.012161244]],"input_vars":["v_ego","lateral_accel","lateral_jerk","roll","lateral_accel_m03","lateral_accel_m02","lateral_accel_m01","lateral_accel_p03","lateral_accel_p06","lateral_accel_p10","lateral_accel_p15","roll_m03","roll_m02","roll_m01","roll_p03","roll_p06","roll_p10","roll_p15"],"output_size":1,"layers":[{"dense_1_b":[[-0.05593524],[-2.802646],[0.18381701],[2.7735913],[0.70043844],[-0.67402124],[-0.0306403]],"dense_1_W":[[-0.0060694856,0.708295,-0.0040300265,-0.14072545,0.86508894,-0.20933008,-0.47414628,0.13602145,-0.37351108,-0.1507088,0.8062229,0.32620648,-0.4413763,0.27845934,0.046796944,-0.20166004,0.2805364,-0.17857681],[-1.5183858,-1.1884525,0.012948404,-0.4015399,-0.4482837,1.2997682,0.74758935,-0.18140315,-0.08297701,0.43953654,-1.01308,-0.03576563,0.48874712,-0.35160765,-0.13189487,0.2400938,-0.02507816,0.16568868],[0.012290816,-0.3639789,-0.030819947,0.23707484,0.74310154,0.1940028,0.030501615,0.39026827,0.058221884,0.30168098,0.056437366,-0.20590998,-0.5798354,-0.48759502,0.19185027,-0.1474303,0.01184457,0.2231587],[1.5026484,-1.0851525,0.012162996,0.16663143,0.17487548,1.102379,0.4405227,-0.67651707,0.44908693,-0.2039782,-0.6490339,-0.35403496,0.20746203,-0.3432079,0.028647806,0.107211135,0.23621367,-0.08824623],[0.07099266,-0.93228585,1.2776774,0.0044325506,0.15857935,1.1165909,0.9740256,-1.5084538,-0.9056588,0.12456019,0.5993922,0.3822549,-0.13951926,-0.10822766,0.0038337011,0.18770072,-0.049219564,-0.076232985],[-0.0752,-0.20068114,-1.2384826,-0.049861677,0.4789055,1.0113648,0.5513206,-1.3342785,-0.92097133,-0.06880563,0.89944464,0.117162146,-0.5786451,0.1731132,-0.07269918,-0.08290825,0.61927795,-0.32732028],[0.00064757804,2.5136843,0.013637969,0.09395495,-0.7916261,-0.5194506,-0.6840161,0.43426317,-0.14782813,0.19477805,-0.35974234,0.1649517,0.25925198,-0.43630955,-0.5161664,0.34094948,0.0005879998,-0.01794689]],"activation":"σ"},{"dense_2_W":[[0.0914673,-0.116974674,0.6729949,-0.77771014,-0.41403642,0.14140436,0.73223853],[-0.42032346,0.49695835,-0.5017433,0.87220526,0.1466709,-0.094482444,-1.1789782],[0.680824,-0.33863154,0.41371307,-0.5763291,0.3732767,-0.6742655,0.05377676],[-1.0674618,0.8340688,-0.36008632,0.5650019,0.43301603,0.3166691,-0.33432913],[-0.29696158,-0.7246317,0.16882418,-0.09805153,-0.2640285,0.2763439,0.6544825],[-0.39634275,-0.18197323,0.012897031,0.7196241,0.73943686,0.6189228,-0.44182113],[0.61815614,-0.42130506,0.20303723,-0.53927803,-0.33029187,-0.14950582,0.60663986],[-1.241183,1.4418663,-0.05617688,0.21847261,0.67225105,0.55988765,-1.1410111],[-0.61954373,0.55230546,-0.048563246,0.4581752,-0.59391123,0.20338446,-0.41244057],[-0.56894773,0.7917731,0.059939034,1.0460548,0.0929983,0.5222918,-0.4436079],[0.28442153,0.50281626,0.12484341,0.087528534,0.24470627,-0.27797765,-0.6426289],[0.49003553,-0.2646059,-0.015263944,-0.0018261729,0.23279527,0.0076607405,0.69959176],[0.5684231,-0.27704594,0.45853093,-0.15373382,-0.4746461,-0.5218501,0.7240048]],"activation":"σ","dense_2_b":[[-0.03126267],[-0.10072103],[0.014238525],[-0.08748218],[-0.007306198],[-0.06704365],[-0.015472214],[-0.26747772],[-0.2887335],[-0.20642278],[-0.0904173],[-0.04132339],[-0.055377904]]},{"dense_3_W":[[0.48765612,-0.19100322,0.22134759,-0.21214958,0.017000003,-0.6330459,0.48456302,-0.56035495,-0.4338575,-0.15609962,0.17514223,0.12882961,0.2161585],[-0.2575735,0.010117811,-0.4424225,0.62049,-0.55049926,0.19114582,0.08136277,0.0047532627,-0.36334708,0.23096415,0.23023362,-0.477106,0.0447247],[-0.30809823,-0.56456196,0.18880828,-0.15554532,0.32209295,-0.39576378,0.6519796,-0.52746034,-0.43441087,-0.043550245,0.08788765,-0.019096207,0.4919662]],"activation":"identity","dense_3_b":[[0.026150323],[-0.020686748],[0.031266637]]},{"dense_4_W":[[0.8366031,-0.86834574,0.4038856]],"dense_4_b":[[0.025044668]],"activation":"identity"}]}
|
||||||
@ -1 +1 @@
|
|||||||
{"input_std":[[9.69185],[1.540828],[1.1422535],[0.030263359],[1.6225281],[1.5997777],[1.5730089],[1.424277],[1.3139973],[1.1868707],[1.0676206],[0.030144755],[0.030192483],[0.030228745],[0.03032813],[0.030303925],[0.03031116],[0.030152585]],"model_test_loss":0.016827212646603584,"input_size":18,"current_date_and_time":"2025-04-19_23-39-22","input_mean":[[18.069342],[0.022936927],[-0.035108753],[-0.0031993124],[0.025608419],[0.0257225],[0.025207438],[0.018243022],[0.0072243717],[-0.003662435],[-0.011087718],[-0.0031280508],[-0.00311736],[-0.003131182],[-0.0035267863],[-0.004009139],[-0.0044690953],[-0.004855515]],"input_vars":["v_ego","lateral_accel","lateral_jerk","roll","lateral_accel_m03","lateral_accel_m02","lateral_accel_m01","lateral_accel_p03","lateral_accel_p06","lateral_accel_p10","lateral_accel_p15","roll_m03","roll_m02","roll_m01","roll_p03","roll_p06","roll_p10","roll_p15"],"output_size":1,"layers":[{"dense_1_b":[[0.23484495],[-3.458155],[-0.65061724],[-0.26108137],[3.8761656],[-0.41541365],[0.45187888]],"dense_1_W":[[0.13635573,1.1536281,0.06798237,-0.046843782,-0.7127543,-0.34835252,-0.47236907,1.0148009,0.20753199,0.7614391,-0.2116509,-0.045529384,-0.20713837,0.0848377,0.30062005,0.092873566,-0.0018172141,-0.17572787],[-2.305817,-0.5387374,-0.45938638,0.036208823,-0.68773305,-0.26441213,-0.03711056,0.6739384,0.16898149,0.41130275,-0.22770037,0.059460163,0.27309912,-0.30170524,-0.100190274,-0.057042886,-0.05511625,0.14404908],[0.63851106,-0.9484218,0.003824309,-0.14493565,-0.7270558,-0.53677094,1.2788634,-0.3673263,-0.13816923,0.1536996,-0.069223404,-0.018855695,-0.37567106,0.52541614,0.15179054,0.270581,-0.040576197,-0.019753123],[0.4546859,1.1357512,-0.019132193,-0.38276812,0.8006601,-0.15111838,-0.71221024,0.23249602,0.03264209,-0.17714578,0.1318619,0.3071488,0.18388422,-0.13612886,-0.14823768,-0.2395975,-0.0354379,0.12196627],[2.605286,0.015709635,-0.47207975,-0.021277286,-0.37507743,-0.6815685,-0.25641406,0.39210537,0.21238214,0.28833768,-0.13859881,0.23703852,0.10589715,-0.3116963,-0.09627983,0.015015259,-0.085346624,0.14887743],[-0.0121305175,-0.22616854,12.655966,-0.35262594,-1.4045227,-1.9047667,-2.7032876,3.181054,2.0532372,0.6247262,-0.115705006,0.5258064,-0.07909483,0.0964521,-0.10150481,0.09466132,0.0021597208,-0.16544223],[0.23776147,-1.368538,-0.08586094,0.021609895,0.6048695,0.13279381,0.2958448,-0.58526164,-0.1610705,-0.42544538,-0.23418613,-0.1616309,0.25446972,-0.15877886,-0.0019331241,-0.10039961,0.13613056,0.0012668837]],"activation":"σ"},{"dense_2_W":[[-0.5056371,0.81436396,-0.13917822,-0.80037946,-0.59604025,-0.78999925,-0.27873737],[-0.4497414,-1.368353,1.3196373,-0.49935067,3.606633,-2.2615685,2.3584154],[-0.3412033,0.6810419,0.7249957,-1.0309223,0.82100374,-0.77988064,0.18884675],[-1.7150979,3.5381098,0.28818595,-1.2821207,-1.7621884,-1.8116575,1.2756097],[-0.11904634,-0.040943474,-0.83569926,0.25027093,-0.68735474,-0.039093345,0.31753448],[0.44574547,-0.31597528,-0.31122974,0.5979627,-0.31958082,-0.2559935,-0.3460548],[0.26562846,0.13387749,-0.69484717,0.5503631,-0.6730771,0.15695189,-0.59696543],[-0.07987114,0.4068772,0.73369247,-0.9445576,0.6558189,-0.19511124,-0.1866442],[-0.34541175,0.575807,0.13408744,-0.8944516,0.82263863,0.15363207,-0.2057351],[0.66298026,-0.7701199,-0.43378943,0.8820758,0.25864363,0.56878936,0.017015105],[0.4665641,-0.28459665,-0.6549732,0.49505192,-0.8118166,0.046624012,0.20086582],[0.72007984,-0.114670254,0.08311235,0.5432469,0.23292236,-0.13743235,-0.4399662],[0.14168906,0.18236077,0.5422965,-0.1936209,0.08167626,-0.34699216,0.42852318]],"activation":"σ","dense_2_b":[[-0.48524407],[-0.064743735],[-0.02042389],[-0.4295334],[-0.20415938],[0.09099535],[-0.01917629],[-0.030794926],[-0.05813007],[0.08901565],[-0.24796419],[0.112134784],[-0.10460872]]},{"dense_3_W":[[-0.16837993,-0.5737468,0.17649585,-0.49820793,0.524844,0.03699279,0.624474,0.245737,-0.32824486,-0.37557223,0.74005604,0.007622024,0.034378406],[0.18686184,0.20867407,0.27604485,0.8802843,-0.53500175,-0.41362065,-0.5105349,0.40075368,0.5311374,-0.4655133,-0.5392229,-0.6545931,0.42653474],[-0.17580743,0.79863507,0.15938231,0.04163453,0.37848914,-0.17208116,-0.41934988,0.29429907,-0.18246712,-0.33918083,0.23200992,-0.08154047,0.22350831]],"activation":"identity","dense_3_b":[[0.100435525],[-0.05763998],[-0.07539215]]},{"dense_4_W":[[0.063197866,-0.89677685,-0.6206098]],"dense_4_b":[[0.059508733]],"activation":"identity"}]}
|
{"input_std":[[9.668097],[1.5244726],[1.2700657],[0.03216253],[1.6078212],[1.5848233],[1.5577372],[1.3927742],[1.2935301],[1.1931615],[1.1020583],[0.032136116],[0.03217024],[0.032196537],[0.03225218],[0.032214258],[0.032031752],[0.03179372]],"model_test_loss":0.018995385617017746,"input_size":18,"current_date_and_time":"2025-05-15_14-47-45","input_mean":[[18.09652],[-0.017798662],[0.027145168],[-0.0054331655],[-0.025215305],[-0.022640774],[-0.019500963],[-0.010056124],[-0.0057649272],[0.001960505],[0.0020118994],[-0.005499858],[-0.005477372],[-0.005444631],[-0.0053683305],[-0.005257134],[-0.005035867],[-0.0050971555]],"input_vars":["v_ego","lateral_accel","lateral_jerk","roll","lateral_accel_m03","lateral_accel_m02","lateral_accel_m01","lateral_accel_p03","lateral_accel_p06","lateral_accel_p10","lateral_accel_p15","roll_m03","roll_m02","roll_m01","roll_p03","roll_p06","roll_p10","roll_p15"],"output_size":1,"layers":[{"dense_1_b":[[-0.016405884],[1.4187009],[-0.30671495],[-1.4047697],[-0.20383339],[-0.3632745],[-0.028944347]],"dense_1_W":[[0.13070685,-0.6662394,-1.0739188,-0.41523784,0.019285621,-0.5666617,0.02941118,0.2413377,0.11430891,-0.15557496,-0.36541316,0.44118378,0.038414165,0.117383294,-0.026998837,-0.3802126,-0.23443018,0.43427357],[0.5493235,0.7341044,0.30259728,-0.09170222,-0.066015296,0.41798133,-0.062179696,-0.1925674,-0.15322368,0.017662844,0.21162434,-0.12112619,-0.027021965,0.05653779,0.14749303,0.28017008,-0.15880422,-0.07834965],[1.3052936,-0.038109165,1.2192534,-0.18676366,0.21888737,0.45998427,0.94506985,-0.87686205,0.044812016,-0.07512292,0.69492793,-0.59623814,0.3278255,0.39913544,0.15354112,0.04995451,-0.031020898,-0.10582342],[-0.4683151,1.0002598,0.29120648,-0.05860625,0.010191997,0.17896307,-0.3321235,0.19332078,-0.44497126,0.09236495,0.17685813,0.022076255,-0.23972619,0.11622197,0.11574386,0.1640551,0.028836682,-0.14775941],[1.2240227,0.5504716,-1.161672,0.10151114,-0.6311718,-0.4365897,-0.63896364,0.4033335,0.012773022,0.025944846,-0.62420815,0.05751297,0.043608528,-0.13193272,-0.33345297,0.18925929,0.0925279,-0.03600548],[-0.0033800902,-0.41361037,-8.50345,0.27523437,2.0881453,2.3587928,2.1091182,-2.467406,-1.9167688,-0.8961217,-0.22510983,0.037862107,-0.23643681,0.03247474,0.067485854,0.04660773,-0.2583531,0.077512406],[0.0035197088,-0.43985325,0.07051937,0.38219255,-0.67769414,-0.29911998,1.0818627,-0.6217103,-0.5443828,0.22882973,0.013560748,-0.29820752,0.11540977,-0.40309906,-0.00034299958,0.69976795,0.13301164,-0.32934943]],"activation":"σ"},{"dense_2_W":[[-0.014842439,-0.3306524,0.254514,-0.6639507,-0.534733,0.07840164,0.2324318],[-0.15334646,-0.290343,-1.047474,0.41780674,0.04612693,-0.73001504,-0.3465528],[-0.6260714,-0.5115335,-0.71161246,0.4046027,-1.2324069,-1.2851475,-0.16620061],[-0.05566019,0.48536706,-0.42460826,0.83332616,0.47045597,-0.061004266,-1.1440438],[0.42156544,-0.6722497,-0.10824958,-0.32994938,0.31952205,-0.46266714,-0.07230821],[-0.38416666,-0.7271572,-0.39645803,-0.4259647,-0.24740903,-0.17667961,-0.10970643],[0.19652602,0.026280575,-0.1651507,-0.38475782,-0.5457258,-0.1882665,0.82107437],[-0.08976335,0.35238677,0.25231764,0.004611504,-0.5936927,-0.29342756,-0.22477138],[0.25490662,-0.4851788,-0.07538396,-0.36808714,-0.05157315,-0.2439695,0.9720866],[0.48479185,-0.68759876,0.42557424,-0.56957704,-0.32759178,-0.3047872,0.7597776],[0.4211342,-1.4932247,-0.66635305,-0.10591562,-0.9298172,1.04872,0.32208702],[-0.2918295,0.63893354,0.044817235,0.87641054,0.38387123,-0.48429132,-0.8803729],[-0.60936576,-0.29061803,-0.94329685,0.6586833,0.15280105,-0.8124564,-0.538523]],"activation":"σ","dense_2_b":[[-0.009386154],[-0.25074136],[0.02986496],[-0.028872054],[-0.06481484],[-0.2976481],[-0.072934344],[-0.117011935],[0.028236326],[-0.009000545],[-0.42297846],[0.030614687],[-0.105583444]]},{"dense_3_W":[[-0.035136532,-0.27008098,-0.5048698,-0.5295355,0.29823285,0.5058221,-0.09186966,0.26433602,0.50751793,0.49806535,0.8154631,-0.5854975,-0.525581],[0.08374179,0.16962804,0.2263017,0.5973136,0.2815238,-0.0505521,0.26001385,0.36577544,-0.68805265,-0.8057493,-0.42594707,0.633128,0.08724391],[0.5107981,0.064214274,-0.061156582,-0.33331737,0.07700428,-0.40398338,0.3673148,-0.42669702,0.38095382,0.33056983,-0.3025643,-0.58125204,-0.3484819]],"activation":"identity","dense_3_b":[[0.01880667],[-0.04986152],[0.030190725]]},{"dense_4_W":[[-1.0120764,0.477425,-1.0690569]],"dense_4_b":[[-0.027314244]],"activation":"identity"}]}
|
||||||
|
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 196 KiB |
BIN
frogpilot/assets/other_images/weather_clear_day.gif
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
frogpilot/assets/other_images/weather_clear_night.gif
Normal file
|
After Width: | Height: | Size: 493 KiB |
BIN
frogpilot/assets/other_images/weather_snow.gif
Normal file
|
After Width: | Height: | Size: 466 KiB |
BIN
frogpilot/assets/other_images/weather_thunder.gif
Normal file
|
After Width: | Height: | Size: 746 KiB |
@ -216,6 +216,8 @@ def is_url_pingable(url):
|
|||||||
if response.status_code in (405, 501):
|
if response.status_code in (405, 501):
|
||||||
response = requests.get(url, headers=headers, timeout=10, allow_redirects=True, stream=True)
|
response = requests.get(url, headers=headers, timeout=10, allow_redirects=True, stream=True)
|
||||||
return response.ok
|
return response.ok
|
||||||
|
except (requests.exceptions.ConnectionError, requests.exceptions.SSLError):
|
||||||
|
return False
|
||||||
except requests.exceptions.RequestException as error:
|
except requests.exceptions.RequestException as error:
|
||||||
print(f"{error.__class__.__name__} while pinging {url}: {error}")
|
print(f"{error.__class__.__name__} while pinging {url}: {error}")
|
||||||
return False
|
return False
|
||||||
@ -337,12 +339,12 @@ def update_openpilot():
|
|||||||
if params.get("UpdaterState", encoding="utf-8") != "idle":
|
if params.get("UpdaterState", encoding="utf-8") != "idle":
|
||||||
return
|
return
|
||||||
|
|
||||||
while params.get_bool("IsOnroad") or params_memory.get_bool("UpdateSpeedLimits") or running_threads.get("lock_doors", threading.Thread()).is_alive():
|
|
||||||
time.sleep(60)
|
|
||||||
|
|
||||||
if not update_available():
|
if not update_available():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
while params.get_bool("IsOnroad") or params_memory.get_bool("UpdateSpeedLimits") or running_threads.get("lock_doors", threading.Thread()).is_alive():
|
||||||
|
time.sleep(60)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if not update_available():
|
if not update_available():
|
||||||
break
|
break
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import json
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
import tomllib
|
||||||
|
|
||||||
from functools import cache
|
from functools import cache
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -15,11 +16,13 @@ from openpilot.common.params import Params
|
|||||||
from openpilot.selfdrive.car import gen_empty_fingerprint
|
from openpilot.selfdrive.car import gen_empty_fingerprint
|
||||||
from openpilot.selfdrive.car.car_helpers import interfaces
|
from openpilot.selfdrive.car.car_helpers import interfaces
|
||||||
from openpilot.selfdrive.car.gm.values import GMFlags
|
from openpilot.selfdrive.car.gm.values import GMFlags
|
||||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
from openpilot.selfdrive.car.interfaces import TORQUE_SUBSTITUTE_PATH, CarInterfaceBase
|
||||||
from openpilot.selfdrive.car.mock.interface import CarInterface
|
from openpilot.selfdrive.car.mock.interface import CarInterface
|
||||||
from openpilot.selfdrive.car.mock.values import CAR as MOCK
|
from openpilot.selfdrive.car.mock.values import CAR as MOCK
|
||||||
|
from openpilot.selfdrive.car.subaru.values import SubaruFlags
|
||||||
from openpilot.selfdrive.car.toyota.values import ToyotaFlags, ToyotaFrogPilotFlags
|
from openpilot.selfdrive.car.toyota.values import ToyotaFlags, ToyotaFrogPilotFlags
|
||||||
from openpilot.selfdrive.controls.lib.desire_helper import LANE_CHANGE_SPEED_MIN
|
from openpilot.selfdrive.controls.lib.desire_helper import LANE_CHANGE_SPEED_MIN
|
||||||
|
from openpilot.selfdrive.controls.lib.latcontrol_torque import KP
|
||||||
from openpilot.selfdrive.modeld.constants import ModelConstants
|
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||||
from openpilot.system.hardware import HARDWARE
|
from openpilot.system.hardware import HARDWARE
|
||||||
from openpilot.system.hardware.power_monitoring import VBATT_PAUSE_CHARGING
|
from openpilot.system.hardware.power_monitoring import VBATT_PAUSE_CHARGING
|
||||||
@ -102,12 +105,27 @@ TINYGRAD_FILES = [
|
|||||||
|
|
||||||
@cache
|
@cache
|
||||||
def get_nnff_model_files():
|
def get_nnff_model_files():
|
||||||
model_dir = Path(NNFF_MODELS_PATH)
|
return [file.stem for file in NNFF_MODELS_PATH.iterdir() if file.is_file()]
|
||||||
return [file.stem for file in model_dir.iterdir() if file.is_file()]
|
|
||||||
|
@cache
|
||||||
|
def get_nnff_substitutes():
|
||||||
|
substitutes = {}
|
||||||
|
with open(TORQUE_SUBSTITUTE_PATH, "rb") as f:
|
||||||
|
substitutes_data = tomllib.load(f)
|
||||||
|
substitutes = {key: value for key, value in substitutes_data.items()}
|
||||||
|
return substitutes
|
||||||
|
|
||||||
def nnff_supported(car_fingerprint):
|
def nnff_supported(car_fingerprint):
|
||||||
for file in get_nnff_model_files():
|
model_files = get_nnff_model_files()
|
||||||
if file.startswith(car_fingerprint):
|
substitutes = get_nnff_substitutes()
|
||||||
|
|
||||||
|
fingerprints_to_check = [car_fingerprint]
|
||||||
|
if car_fingerprint in substitutes:
|
||||||
|
fingerprints_to_check.append(substitutes[car_fingerprint])
|
||||||
|
|
||||||
|
for fingerprint in fingerprints_to_check:
|
||||||
|
for file in model_files:
|
||||||
|
if file.startswith(fingerprint):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@ -160,7 +178,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
|||||||
("CECurves", "0", 1, "0"),
|
("CECurves", "0", 1, "0"),
|
||||||
("CECurvesLead", "0", 1, "0"),
|
("CECurvesLead", "0", 1, "0"),
|
||||||
("CELead", "0", 1, "0"),
|
("CELead", "0", 1, "0"),
|
||||||
("CEModelStopTime", str(PLANNER_TIME - 2), 2, "0"),
|
("CEModelStopTime", str(PLANNER_TIME - 2), 3, "0"),
|
||||||
("CENavigation", "1", 2, "0"),
|
("CENavigation", "1", 2, "0"),
|
||||||
("CENavigationIntersections", "0", 2, "0"),
|
("CENavigationIntersections", "0", 2, "0"),
|
||||||
("CENavigationLead", "1", 2, "0"),
|
("CENavigationLead", "1", 2, "0"),
|
||||||
@ -170,6 +188,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
|||||||
("CESlowerLead", "0", 1, "0"),
|
("CESlowerLead", "0", 1, "0"),
|
||||||
("CESpeed", "0", 1, "0"),
|
("CESpeed", "0", 1, "0"),
|
||||||
("CESpeedLead", "0", 1, "0"),
|
("CESpeedLead", "0", 1, "0"),
|
||||||
|
("CEStopLights", "1", 1, "0"),
|
||||||
("CEStoppedLead", "0", 1, "0"),
|
("CEStoppedLead", "0", 1, "0"),
|
||||||
("ClusterOffset", "1.015", 2, "1.015"),
|
("ClusterOffset", "1.015", 2, "1.015"),
|
||||||
("Compass", "0", 1, "0"),
|
("Compass", "0", 1, "0"),
|
||||||
@ -241,9 +260,21 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
|||||||
("HideSpeedLimit", "0", 2, "0"),
|
("HideSpeedLimit", "0", 2, "0"),
|
||||||
("HigherBitrate", "0", 2, "0"),
|
("HigherBitrate", "0", 2, "0"),
|
||||||
("HolidayThemes", "1", 0, "0"),
|
("HolidayThemes", "1", 0, "0"),
|
||||||
|
("HondaAltTune", "0", 2, "0"),
|
||||||
|
("HondaLowSpeedPedal", "0", 2, "0"),
|
||||||
|
("HondaMaxBrake", "0", 2, "0"),
|
||||||
("HumanAcceleration", "1", 2, "0"),
|
("HumanAcceleration", "1", 2, "0"),
|
||||||
("HumanFollowing", "1", 2, "0"),
|
("HumanFollowing", "1", 2, "0"),
|
||||||
|
("HumanLaneChanges", "1", 2, "0"),
|
||||||
("IncreasedStoppedDistance", "0", 1, "0"),
|
("IncreasedStoppedDistance", "0", 1, "0"),
|
||||||
|
("IncreaseFollowingLowVisibility", "0", 2, "0"),
|
||||||
|
("IncreaseFollowingRain", "0", 2, "0"),
|
||||||
|
("IncreaseFollowingRainStorm", "0", 2, "0"),
|
||||||
|
("IncreaseFollowingSnow", "0", 2, "0"),
|
||||||
|
("IncreasedStoppedDistanceLowVisibility", "0", 2, "0"),
|
||||||
|
("IncreasedStoppedDistanceRain", "0", 2, "0"),
|
||||||
|
("IncreasedStoppedDistanceRainStorm", "0", 2, "0"),
|
||||||
|
("IncreasedStoppedDistanceSnow", "0", 2, "0"),
|
||||||
("IncreaseThermalLimits", "0", 2, "0"),
|
("IncreaseThermalLimits", "0", 2, "0"),
|
||||||
("IsLdwEnabled", "0", 0, "0"),
|
("IsLdwEnabled", "0", 0, "0"),
|
||||||
("IsMetric", "0", 0, "0"),
|
("IsMetric", "0", 0, "0"),
|
||||||
@ -320,6 +351,14 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
|||||||
("RandomEvents", "0", 1, "0"),
|
("RandomEvents", "0", 1, "0"),
|
||||||
("RandomThemes", "0", 1, "0"),
|
("RandomThemes", "0", 1, "0"),
|
||||||
("RecordFront", "0", 0, "0"),
|
("RecordFront", "0", 0, "0"),
|
||||||
|
("ReduceAccelerationLowVisibility", "0", 2, "0"),
|
||||||
|
("ReduceAccelerationRain", "0", 2, "0"),
|
||||||
|
("ReduceAccelerationRainStorm", "0", 2, "0"),
|
||||||
|
("ReduceAccelerationSnow", "0", 2, "0"),
|
||||||
|
("ReduceLateralAccelerationLowVisibility", "0", 2, "0"),
|
||||||
|
("ReduceLateralAccelerationRain", "0", 2, "0"),
|
||||||
|
("ReduceLateralAccelerationRainStorm", "0", 2, "0"),
|
||||||
|
("ReduceLateralAccelerationSnow", "0", 2, "0"),
|
||||||
("RefuseVolume", "101", 2, "101"),
|
("RefuseVolume", "101", 2, "101"),
|
||||||
("RelaxedFollow", "1.75", 2, "1.75"),
|
("RelaxedFollow", "1.75", 2, "1.75"),
|
||||||
("RelaxedJerkAcceleration", "100", 3, "100"),
|
("RelaxedJerkAcceleration", "100", 3, "100"),
|
||||||
@ -404,6 +443,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
|||||||
("StoppingDecelRate", "", 3, ""),
|
("StoppingDecelRate", "", 3, ""),
|
||||||
("StoppingDecelRateStock", "", 3, ""),
|
("StoppingDecelRateStock", "", 3, ""),
|
||||||
("StoppedTimer", "0", 1, "0"),
|
("StoppedTimer", "0", 1, "0"),
|
||||||
|
("SubaruSNG", "1", 2, "0"),
|
||||||
("TacoTune", "0", 2, "0"),
|
("TacoTune", "0", 2, "0"),
|
||||||
("TacoTuneHacks", "0", 2, "0"),
|
("TacoTuneHacks", "0", 2, "0"),
|
||||||
("TetheringEnabled", "0", 0, "0"),
|
("TetheringEnabled", "0", 0, "0"),
|
||||||
@ -422,6 +462,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
|||||||
("TurnDesires", "0", 2, "0"),
|
("TurnDesires", "0", 2, "0"),
|
||||||
("UnlimitedLength", "1", 2, "0"),
|
("UnlimitedLength", "1", 2, "0"),
|
||||||
("UnlockDoors", "1", 0, "0"),
|
("UnlockDoors", "1", 0, "0"),
|
||||||
|
("UpdatedToggles", "1", 0, "0"),
|
||||||
("UpdaterAvailableBranches", "", 0, ""),
|
("UpdaterAvailableBranches", "", 0, ""),
|
||||||
("UseKonikServer", "0", 2, "0"),
|
("UseKonikServer", "0", 2, "0"),
|
||||||
("UseSI", "1", 3, "1"),
|
("UseSI", "1", 3, "1"),
|
||||||
@ -434,6 +475,8 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
|||||||
("VoltSNG", "0", 2, "0"),
|
("VoltSNG", "0", 2, "0"),
|
||||||
("WarningImmediateVolume", "101", 2, "101"),
|
("WarningImmediateVolume", "101", 2, "101"),
|
||||||
("WarningSoftVolume", "101", 2, "101"),
|
("WarningSoftVolume", "101", 2, "101"),
|
||||||
|
("WeatherPresets", "0", 2, "0"),
|
||||||
|
("WeatherToken", "", 2, ""),
|
||||||
("WheelIcon", "frog", 0, "stock"),
|
("WheelIcon", "frog", 0, "stock"),
|
||||||
("WheelSpeed", "0", 2, "0")
|
("WheelSpeed", "0", 2, "0")
|
||||||
]
|
]
|
||||||
@ -556,6 +599,7 @@ class FrogPilotVariables:
|
|||||||
toggle.has_sdsu = toggle.car_make == "toyota" and bool(CP.flags & ToyotaFlags.SMART_DSU.value)
|
toggle.has_sdsu = toggle.car_make == "toyota" and bool(CP.flags & ToyotaFlags.SMART_DSU.value)
|
||||||
has_sng = CP.autoResumeSng
|
has_sng = CP.autoResumeSng
|
||||||
toggle.has_zss = toggle.car_make == "toyota" and bool(FPCP.fpFlags & ToyotaFrogPilotFlags.ZSS.value)
|
toggle.has_zss = toggle.car_make == "toyota" and bool(FPCP.fpFlags & ToyotaFrogPilotFlags.ZSS.value)
|
||||||
|
honda_nidec = CP.safetyConfigs[0].safetyModel == SafetyModel.hondaNidec
|
||||||
is_angle_car = CP.steerControlType == car.CarParams.SteerControlType.angle
|
is_angle_car = CP.steerControlType == car.CarParams.SteerControlType.angle
|
||||||
latAccelFactor = CP.lateralTuning.torque.latAccelFactor
|
latAccelFactor = CP.lateralTuning.torque.latAccelFactor
|
||||||
longitudinalActuatorDelay = CP.longitudinalActuatorDelay
|
longitudinalActuatorDelay = CP.longitudinalActuatorDelay
|
||||||
@ -564,7 +608,7 @@ class FrogPilotVariables:
|
|||||||
startAccel = CP.startAccel
|
startAccel = CP.startAccel
|
||||||
stopAccel = CP.stopAccel
|
stopAccel = CP.stopAccel
|
||||||
steerActuatorDelay = CP.steerActuatorDelay
|
steerActuatorDelay = CP.steerActuatorDelay
|
||||||
steerKp = CP.lateralTuning.torque.kp
|
steerKp = CP.lateralTuning.pid.kp if CP.lateralTuning.which() == "pid" else KP
|
||||||
steerRatio = CP.steerRatio
|
steerRatio = CP.steerRatio
|
||||||
toggle.stoppingDecelRate = CP.stoppingDecelRate
|
toggle.stoppingDecelRate = CP.stoppingDecelRate
|
||||||
taco_hacks_allowed = CP.safetyConfigs[0].safetyModel == SafetyModel.hyundaiCanfd
|
taco_hacks_allowed = CP.safetyConfigs[0].safetyModel == SafetyModel.hyundaiCanfd
|
||||||
@ -605,7 +649,7 @@ class FrogPilotVariables:
|
|||||||
toggle.steerRatio = np.clip(params.get_float("SteerRatio"), steerRatio * 0.5, steerRatio * 1.5) if advanced_lateral_tuning and tuning_level >= level["SteerRatio"] else steerRatio
|
toggle.steerRatio = np.clip(params.get_float("SteerRatio"), steerRatio * 0.5, steerRatio * 1.5) if advanced_lateral_tuning and tuning_level >= level["SteerRatio"] else steerRatio
|
||||||
toggle.use_custom_steerRatio = bool(round(toggle.steerRatio, 2) != round(steerRatio, 2)) and not toggle.force_auto_tune or toggle.force_auto_tune_off
|
toggle.use_custom_steerRatio = bool(round(toggle.steerRatio, 2) != round(steerRatio, 2)) and not toggle.force_auto_tune or toggle.force_auto_tune_off
|
||||||
|
|
||||||
advanced_longitudinal_tuning = params.get_bool("AdvancedLongitudinalTune") if tuning_level >= level["AdvancedLongitudinalTune"] else default.get_bool("AdvancedLongitudinalTune")
|
advanced_longitudinal_tuning = toggle.openpilot_longitudinal and (params.get_bool("AdvancedLongitudinalTune") if tuning_level >= level["AdvancedLongitudinalTune"] else default.get_bool("AdvancedLongitudinalTune"))
|
||||||
toggle.longitudinalActuatorDelay = np.clip(params.get_float("LongitudinalActuatorDelay"), 0, 1) if advanced_longitudinal_tuning and tuning_level >= level["LongitudinalActuatorDelay"] else longitudinalActuatorDelay
|
toggle.longitudinalActuatorDelay = np.clip(params.get_float("LongitudinalActuatorDelay"), 0, 1) if advanced_longitudinal_tuning and tuning_level >= level["LongitudinalActuatorDelay"] else longitudinalActuatorDelay
|
||||||
toggle.max_desired_acceleration = np.clip(params.get_float("MaxDesiredAcceleration"), 0.1, 4.0) if advanced_longitudinal_tuning and tuning_level >= level["MaxDesiredAcceleration"] else default.get_float("MaxDesiredAcceleration")
|
toggle.max_desired_acceleration = np.clip(params.get_float("MaxDesiredAcceleration"), 0.1, 4.0) if advanced_longitudinal_tuning and tuning_level >= level["MaxDesiredAcceleration"] else default.get_float("MaxDesiredAcceleration")
|
||||||
toggle.startAccel = np.clip(params.get_float("StartAccel"), 0, 4) if advanced_longitudinal_tuning and tuning_level >= level["StartAccel"] else startAccel
|
toggle.startAccel = np.clip(params.get_float("StartAccel"), 0, 4) if advanced_longitudinal_tuning and tuning_level >= level["StartAccel"] else startAccel
|
||||||
@ -647,7 +691,10 @@ class FrogPilotVariables:
|
|||||||
toggle.conditional_navigation_intersections = toggle.conditional_navigation and (params.get_bool("CENavigationIntersections") if tuning_level >= level["CENavigationIntersections"] else default.get_bool("CENavigationIntersections"))
|
toggle.conditional_navigation_intersections = toggle.conditional_navigation and (params.get_bool("CENavigationIntersections") if tuning_level >= level["CENavigationIntersections"] else default.get_bool("CENavigationIntersections"))
|
||||||
toggle.conditional_navigation_lead = toggle.conditional_navigation and (params.get_bool("CENavigationLead") if tuning_level >= level["CENavigationLead"] else default.get_bool("CENavigationLead"))
|
toggle.conditional_navigation_lead = toggle.conditional_navigation and (params.get_bool("CENavigationLead") if tuning_level >= level["CENavigationLead"] else default.get_bool("CENavigationLead"))
|
||||||
toggle.conditional_navigation_turns = toggle.conditional_navigation and (params.get_bool("CENavigationTurns") if tuning_level >= level["CENavigationTurns"] else default.get_bool("CENavigationTurns"))
|
toggle.conditional_navigation_turns = toggle.conditional_navigation and (params.get_bool("CENavigationTurns") if tuning_level >= level["CENavigationTurns"] else default.get_bool("CENavigationTurns"))
|
||||||
toggle.conditional_model_stop_time = params.get_int("CEModelStopTime") if toggle.conditional_experimental_mode and tuning_level >= level["CEModelStopTime"] else default.get_int("CEModelStopTime")
|
if tuning_level >= level["CEModelStopTime"]:
|
||||||
|
toggle.conditional_model_stop_time = params.get_int("CEModelStopTime") if toggle.conditional_experimental_mode else default.get_int("CEModelStopTime")
|
||||||
|
else:
|
||||||
|
toggle.conditional_model_stop_time = default.get_int("CEModelStopTime") if toggle.conditional_experimental_mode and params.get_bool("CEStopLights") else 0
|
||||||
toggle.conditional_signal = params.get_int("CESignalSpeed") * speed_conversion if toggle.conditional_experimental_mode and tuning_level >= level["CESignalSpeed"] else default.get_int("CESignalSpeed") * CV.MPH_TO_MS
|
toggle.conditional_signal = params.get_int("CESignalSpeed") * speed_conversion if toggle.conditional_experimental_mode and tuning_level >= level["CESignalSpeed"] else default.get_int("CESignalSpeed") * CV.MPH_TO_MS
|
||||||
toggle.conditional_signal_lane_detection = toggle.conditional_signal != 0 and (params.get_bool("CESignalLaneDetection") if tuning_level >= level["CESignalLaneDetection"] else default.get_bool("CESignalLaneDetection"))
|
toggle.conditional_signal_lane_detection = toggle.conditional_signal != 0 and (params.get_bool("CESignalLaneDetection") if tuning_level >= level["CESignalLaneDetection"] else default.get_bool("CESignalLaneDetection"))
|
||||||
toggle.cem_status = toggle.conditional_experimental_mode and (params.get_bool("ShowCEMStatus") if tuning_level >= level["ShowCEMStatus"] else default.get_bool("ShowCEMStatus")) or toggle.debug_mode
|
toggle.cem_status = toggle.conditional_experimental_mode and (params.get_bool("ShowCEMStatus") if tuning_level >= level["ShowCEMStatus"] else default.get_bool("ShowCEMStatus")) or toggle.debug_mode
|
||||||
@ -785,6 +832,10 @@ class FrogPilotVariables:
|
|||||||
toggle.holiday_themes = params.get_bool("HolidayThemes") if tuning_level >= level["HolidayThemes"] else default.get_bool("HolidayThemes")
|
toggle.holiday_themes = params.get_bool("HolidayThemes") if tuning_level >= level["HolidayThemes"] else default.get_bool("HolidayThemes")
|
||||||
toggle.current_holiday_theme = holiday_theme if toggle.holiday_themes else "stock"
|
toggle.current_holiday_theme = holiday_theme if toggle.holiday_themes else "stock"
|
||||||
|
|
||||||
|
toggle.honda_alt_Tune = toggle.openpilot_longitudinal and toggle.car_make == "honda" and honda_nidec and (params.get_bool("HondaAltTune") if tuning_level >= level["HondaAltTune"] else default.get_bool("HondaAltTune"))
|
||||||
|
toggle.honda_low_speed_pedal = toggle.openpilot_longitudinal and toggle.car_make == "honda" and toggle.has_pedal and (params.get_bool("HondaLowSpeedPedal") if tuning_level >= level["HondaLowSpeedPedal"] else default.get_bool("HondaLowSpeedPedal"))
|
||||||
|
toggle.honda_nidec_max_brake = toggle.openpilot_longitudinal and toggle.car_make == "honda" and honda_nidec and (params.get_bool("HondaMaxBrake") if tuning_level >= level["HondaMaxBrake"] else default.get_bool("HondaMaxBrake"))
|
||||||
|
|
||||||
toggle.lane_changes = params.get_bool("LaneChanges") if tuning_level >= level["LaneChanges"] else default.get_bool("LaneChanges")
|
toggle.lane_changes = params.get_bool("LaneChanges") if tuning_level >= level["LaneChanges"] else default.get_bool("LaneChanges")
|
||||||
toggle.lane_change_delay = params.get_float("LaneChangeTime") if toggle.lane_changes and tuning_level >= level["LaneChangeTime"] else default.get_float("LaneChangeTime")
|
toggle.lane_change_delay = params.get_float("LaneChangeTime") if toggle.lane_changes and tuning_level >= level["LaneChangeTime"] else default.get_float("LaneChangeTime")
|
||||||
toggle.lane_detection_width = params.get_float("LaneDetectionWidth") * distance_conversion if toggle.lane_changes and tuning_level >= level["LaneDetectionWidth"] else default.get_float("LaneDetectionWidth") * CV.FOOT_TO_METER
|
toggle.lane_detection_width = params.get_float("LaneDetectionWidth") * distance_conversion if toggle.lane_changes and tuning_level >= level["LaneDetectionWidth"] else default.get_float("LaneDetectionWidth") * CV.FOOT_TO_METER
|
||||||
@ -817,6 +868,7 @@ class FrogPilotVariables:
|
|||||||
toggle.deceleration_profile = params.get_int("DecelerationProfile") if longitudinal_tuning and tuning_level >= level["DecelerationProfile"] else default.get_int("DecelerationProfile")
|
toggle.deceleration_profile = params.get_int("DecelerationProfile") if longitudinal_tuning and tuning_level >= level["DecelerationProfile"] else default.get_int("DecelerationProfile")
|
||||||
toggle.human_acceleration = longitudinal_tuning and (params.get_bool("HumanAcceleration") if tuning_level >= level["HumanAcceleration"] else default.get_bool("HumanAcceleration"))
|
toggle.human_acceleration = longitudinal_tuning and (params.get_bool("HumanAcceleration") if tuning_level >= level["HumanAcceleration"] else default.get_bool("HumanAcceleration"))
|
||||||
toggle.human_following = longitudinal_tuning and (params.get_bool("HumanFollowing") if tuning_level >= level["HumanFollowing"] else default.get_bool("HumanFollowing"))
|
toggle.human_following = longitudinal_tuning and (params.get_bool("HumanFollowing") if tuning_level >= level["HumanFollowing"] else default.get_bool("HumanFollowing"))
|
||||||
|
toggle.human_lane_changes = longitudinal_tuning and has_radar and (params.get_bool("HumanLaneChanges") if tuning_level >= level["HumanLaneChanges"] else default.get_bool("HumanLaneChanges"))
|
||||||
toggle.lead_detection_probability = np.clip(params.get_int("LeadDetectionThreshold") / 100, 0.25, 0.50) if longitudinal_tuning and tuning_level >= level["LeadDetectionThreshold"] else default.get_int("LeadDetectionThreshold") / 100
|
toggle.lead_detection_probability = np.clip(params.get_int("LeadDetectionThreshold") / 100, 0.25, 0.50) if longitudinal_tuning and tuning_level >= level["LeadDetectionThreshold"] else default.get_int("LeadDetectionThreshold") / 100
|
||||||
toggle.taco_tune = longitudinal_tuning and (params.get_bool("TacoTune") if tuning_level >= level["TacoTune"] else default.get_bool("TacoTune"))
|
toggle.taco_tune = longitudinal_tuning and (params.get_bool("TacoTune") if tuning_level >= level["TacoTune"] else default.get_bool("TacoTune"))
|
||||||
|
|
||||||
@ -882,7 +934,7 @@ class FrogPilotVariables:
|
|||||||
toggle.pause_lateral_below_speed = params.get_int("PauseLateralSpeed") * speed_conversion if quality_of_life_lateral and tuning_level >= level["PauseLateralSpeed"] else default.get_int("PauseLateralSpeed") * CV.MPH_TO_MS
|
toggle.pause_lateral_below_speed = params.get_int("PauseLateralSpeed") * speed_conversion if quality_of_life_lateral and tuning_level >= level["PauseLateralSpeed"] else default.get_int("PauseLateralSpeed") * CV.MPH_TO_MS
|
||||||
toggle.pause_lateral_below_signal = toggle.pause_lateral_below_speed != 0 and (params.get_bool("PauseLateralOnSignal") if tuning_level >= level["PauseLateralOnSignal"] else default.get_bool("PauseLateralOnSignal"))
|
toggle.pause_lateral_below_signal = toggle.pause_lateral_below_speed != 0 and (params.get_bool("PauseLateralOnSignal") if tuning_level >= level["PauseLateralOnSignal"] else default.get_bool("PauseLateralOnSignal"))
|
||||||
|
|
||||||
quality_of_life_longitudinal = params.get_bool("QOLLongitudinal") if tuning_level >= level["QOLLongitudinal"] else default.get_bool("QOLLongitudinal")
|
quality_of_life_longitudinal = toggle.openpilot_longitudinal and (params.get_bool("QOLLongitudinal") if tuning_level >= level["QOLLongitudinal"] else default.get_bool("QOLLongitudinal"))
|
||||||
toggle.cruise_increase = params.get_int("CustomCruise") if quality_of_life_longitudinal and not pcm_cruise and tuning_level >= level["CustomCruise"] else default.get_int("CustomCruise")
|
toggle.cruise_increase = params.get_int("CustomCruise") if quality_of_life_longitudinal and not pcm_cruise and tuning_level >= level["CustomCruise"] else default.get_int("CustomCruise")
|
||||||
toggle.cruise_increase_long = params.get_int("CustomCruiseLong") if quality_of_life_longitudinal and not pcm_cruise and tuning_level >= level["CustomCruiseLong"] else default.get_int("CustomCruiseLong")
|
toggle.cruise_increase_long = params.get_int("CustomCruiseLong") if quality_of_life_longitudinal and not pcm_cruise and tuning_level >= level["CustomCruiseLong"] else default.get_int("CustomCruiseLong")
|
||||||
toggle.force_stops = quality_of_life_longitudinal and (params.get_bool("ForceStops") if tuning_level >= level["ForceStops"] else default.get_bool("ForceStops"))
|
toggle.force_stops = quality_of_life_longitudinal and (params.get_bool("ForceStops") if tuning_level >= level["ForceStops"] else default.get_bool("ForceStops"))
|
||||||
@ -892,6 +944,23 @@ class FrogPilotVariables:
|
|||||||
toggle.map_deceleration = map_gears and (params.get_bool("MapDeceleration") if tuning_level >= level["MapDeceleration"] else default.get_bool("MapDeceleration"))
|
toggle.map_deceleration = map_gears and (params.get_bool("MapDeceleration") if tuning_level >= level["MapDeceleration"] else default.get_bool("MapDeceleration"))
|
||||||
toggle.reverse_cruise_increase = quality_of_life_longitudinal and toggle.car_make == "toyota" and pcm_cruise and (params.get_bool("ReverseCruise") if tuning_level >= level["ReverseCruise"] else default.get_bool("ReverseCruise"))
|
toggle.reverse_cruise_increase = quality_of_life_longitudinal and toggle.car_make == "toyota" and pcm_cruise and (params.get_bool("ReverseCruise") if tuning_level >= level["ReverseCruise"] else default.get_bool("ReverseCruise"))
|
||||||
toggle.set_speed_offset = params.get_int("SetSpeedOffset") * (1 if toggle.is_metric else CV.MPH_TO_KPH) if quality_of_life_longitudinal and not pcm_cruise and tuning_level >= level["SetSpeedOffset"] else default.get_int("SetSpeedOffset") * CV.MPH_TO_KPH
|
toggle.set_speed_offset = params.get_int("SetSpeedOffset") * (1 if toggle.is_metric else CV.MPH_TO_KPH) if quality_of_life_longitudinal and not pcm_cruise and tuning_level >= level["SetSpeedOffset"] else default.get_int("SetSpeedOffset") * CV.MPH_TO_KPH
|
||||||
|
toggle.weather_presets = quality_of_life_longitudinal and (params.get_bool("WeatherPresets") if tuning_level >= level["WeatherPresets"] else default.get_bool("WeatherPresets"))
|
||||||
|
toggle.increase_following_distance_low_visibility = params.get_float("IncreaseFollowingLowVisibility") if toggle.weather_presets and tuning_level >= level["IncreaseFollowingLowVisibility"] else default.get_float("IncreaseFollowingLowVisibility")
|
||||||
|
toggle.increase_following_distance_rain = params.get_float("IncreaseFollowingRain") if toggle.weather_presets and tuning_level >= level["IncreaseFollowingRain"] else default.get_float("IncreaseFollowingRain")
|
||||||
|
toggle.increase_following_distance_rain_storm = params.get_float("IncreaseFollowingRainStorm") if toggle.weather_presets and tuning_level >= level["IncreaseFollowingRainStorm"] else default.get_float("IncreaseFollowingRainStorm")
|
||||||
|
toggle.increase_following_distance_snow = params.get_float("IncreaseFollowingSnow") if toggle.weather_presets and tuning_level >= level["IncreaseFollowingSnow"] else default.get_float("IncreaseFollowingSnow")
|
||||||
|
toggle.increase_stopped_distance_low_visibility = params.get_int("IncreasedStoppedDistanceLowVisibility") * distance_conversion if toggle.weather_presets and tuning_level >= level["IncreasedStoppedDistanceLowVisibility"] else default.get_int("IncreasedStoppedDistanceLowVisibility") * CV.FOOT_TO_METER
|
||||||
|
toggle.increase_stopped_distance_rain = params.get_int("IncreasedStoppedDistanceRain") * distance_conversion if toggle.weather_presets and tuning_level >= level["IncreasedStoppedDistanceRain"] else default.get_int("IncreasedStoppedDistanceRain") * CV.FOOT_TO_METER
|
||||||
|
toggle.increase_stopped_distance_rain_storm = params.get_int("IncreasedStoppedDistanceRainStorm") * distance_conversion if toggle.weather_presets and tuning_level >= level["IncreasedStoppedDistanceRainStorm"] else default.get_int("IncreasedStoppedDistanceRainStorm") * CV.FOOT_TO_METER
|
||||||
|
toggle.increase_stopped_distance_snow = params.get_int("IncreasedStoppedDistanceSnow") * distance_conversion if toggle.weather_presets and tuning_level >= level["IncreasedStoppedDistanceSnow"] else default.get_int("IncreasedStoppedDistanceSnow") * CV.FOOT_TO_METER
|
||||||
|
toggle.reduce_acceleration_low_visibility = (params.get_int("ReduceAccelerationLowVisibility") if toggle.weather_presets and tuning_level >= level["ReduceAccelerationLowVisibility"] else default.get_int("ReduceAccelerationLowVisibility")) / 100
|
||||||
|
toggle.reduce_acceleration_rain = (params.get_int("ReduceAccelerationRain") if toggle.weather_presets and tuning_level >= level["ReduceAccelerationRain"] else default.get_int("ReduceAccelerationRain")) / 100
|
||||||
|
toggle.reduce_acceleration_rain_storm = (params.get_int("ReduceAccelerationRainStorm") if toggle.weather_presets and tuning_level >= level["ReduceAccelerationRainStorm"] else default.get_int("ReduceAccelerationRainStorm")) / 100
|
||||||
|
toggle.reduce_acceleration_snow = (params.get_int("ReduceAccelerationSnow") if toggle.weather_presets and tuning_level >= level["ReduceAccelerationSnow"] else default.get_int("ReduceAccelerationSnow")) / 100
|
||||||
|
toggle.reduce_lateral_acceleration_low_visibility = (params.get_int("ReduceLateralAccelerationLowVisibility") if toggle.weather_presets and tuning_level >= level["ReduceLateralAccelerationLowVisibility"] else default.get_int("ReduceLateralAccelerationLowVisibility")) / 100
|
||||||
|
toggle.reduce_lateral_acceleration_rain = (params.get_int("ReduceLateralAccelerationRain") if toggle.weather_presets and tuning_level >= level["ReduceLateralAccelerationRain"] else default.get_int("ReduceLateralAccelerationRain")) / 100
|
||||||
|
toggle.reduce_lateral_acceleration_rain_storm = (params.get_int("ReduceLateralAccelerationRainStorm") if toggle.weather_presets and tuning_level >= level["ReduceLateralAccelerationRainStorm"] else default.get_int("ReduceLateralAccelerationRainStorm")) / 100
|
||||||
|
toggle.reduce_lateral_acceleration_snow = (params.get_int("ReduceLateralAccelerationSnow") if toggle.weather_presets and tuning_level >= level["ReduceLateralAccelerationSnow"] else default.get_int("ReduceLateralAccelerationSnow")) / 100
|
||||||
|
|
||||||
quality_of_life_visuals = params.get_bool("QOLVisuals") if tuning_level >= level["QOLVisuals"] else default.get_bool("QOLVisuals")
|
quality_of_life_visuals = params.get_bool("QOLVisuals") if tuning_level >= level["QOLVisuals"] else default.get_bool("QOLVisuals")
|
||||||
toggle.camera_view = params.get_int("CameraView") if quality_of_life_visuals and tuning_level >= level["CameraView"] else default.get_int("CameraView")
|
toggle.camera_view = params.get_int("CameraView") if quality_of_life_visuals and tuning_level >= level["CameraView"] else default.get_int("CameraView")
|
||||||
@ -949,6 +1018,8 @@ class FrogPilotVariables:
|
|||||||
toggle.startup_alert_top = params.get("StartupMessageTop", encoding="utf-8") if tuning_level >= level["StartupMessageTop"] else default.get("StartupMessageTop", encoding="utf-8")
|
toggle.startup_alert_top = params.get("StartupMessageTop", encoding="utf-8") if tuning_level >= level["StartupMessageTop"] else default.get("StartupMessageTop", encoding="utf-8")
|
||||||
toggle.startup_alert_bottom = params.get("StartupMessageBottom", encoding="utf-8") if tuning_level >= level["StartupMessageBottom"] else default.get("StartupMessageBottom", encoding="utf-8")
|
toggle.startup_alert_bottom = params.get("StartupMessageBottom", encoding="utf-8") if tuning_level >= level["StartupMessageBottom"] else default.get("StartupMessageBottom", encoding="utf-8")
|
||||||
|
|
||||||
|
toggle.subaru_sng = toggle.car_make == "subaru" and not (CP.flags & SubaruFlags.GLOBAL_GEN2 or CP.flags & SubaruFlags.HYBRID) and (params.get_bool("SubaruSNG") if tuning_level >= level["SubaruSNG"] else default.get_bool("SubaruSNG"))
|
||||||
|
|
||||||
toggle.taco_tune_hacks = taco_hacks_allowed and (params.get_bool("TacoTuneHacks") if tuning_level >= level["TacoTuneHacks"] else default.get_bool("TacoTuneHacks"))
|
toggle.taco_tune_hacks = taco_hacks_allowed and (params.get_bool("TacoTuneHacks") if tuning_level >= level["TacoTuneHacks"] else default.get_bool("TacoTuneHacks"))
|
||||||
|
|
||||||
toggle.tethering_config = params.get_int("TetheringEnabled")
|
toggle.tethering_config = params.get_int("TetheringEnabled")
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from cereal import car, custom
|
from cereal import car, custom
|
||||||
from openpilot.selfdrive.controls.lib.drive_helpers import CRUISE_LONG_PRESS
|
from openpilot.selfdrive.controls.lib.drive_helpers import CRUISE_LONG_PRESS
|
||||||
from openpilot.selfdrive.controls.lib.events import EventName
|
from openpilot.selfdrive.controls.lib.events import ET
|
||||||
|
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import NON_DRIVING_GEARS, params, params_memory
|
from openpilot.frogpilot.common.frogpilot_variables import NON_DRIVING_GEARS, params, params_memory
|
||||||
|
|
||||||
@ -98,8 +98,8 @@ class FrogPilotCard:
|
|||||||
self.always_on_lateral_enabled &= carState.gearShifter not in NON_DRIVING_GEARS
|
self.always_on_lateral_enabled &= carState.gearShifter not in NON_DRIVING_GEARS
|
||||||
self.always_on_lateral_enabled &= sm["frogpilotPlan"].lateralCheck
|
self.always_on_lateral_enabled &= sm["frogpilotPlan"].lateralCheck
|
||||||
self.always_on_lateral_enabled &= sm["liveCalibration"].calPerc >= 1
|
self.always_on_lateral_enabled &= sm["liveCalibration"].calPerc >= 1
|
||||||
|
self.always_on_lateral_enabled &= sm["controlsState"].alertType != ET.IMMEDIATE_DISABLE or frogpilot_toggles.frogs_go_moo
|
||||||
self.always_on_lateral_enabled &= not (carState.brakePressed and carState.vEgo < self.car.frogpilot_toggles.always_on_lateral_pause_speed) or carState.standstill
|
self.always_on_lateral_enabled &= not (carState.brakePressed and carState.vEgo < self.car.frogpilot_toggles.always_on_lateral_pause_speed) or carState.standstill
|
||||||
self.always_on_lateral_enabled &= not any(event.immediateDisable for events in (sm["onroadEvents"], sm["frogpilotOnroadEvents"]) for event in events if event.name != EventName.speedTooLow) or self.car.frogpilot_toggles.frogs_go_moo
|
|
||||||
|
|
||||||
if sm.updated["frogpilotPlan"] or any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in carState.buttonEvents):
|
if sm.updated["frogpilotPlan"] or any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in carState.buttonEvents):
|
||||||
self.accel_pressed = any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in carState.buttonEvents)
|
self.accel_pressed = any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in carState.buttonEvents)
|
||||||
|
|||||||
@ -18,6 +18,7 @@ from openpilot.frogpilot.controls.lib.frogpilot_acceleration import FrogPilotAcc
|
|||||||
from openpilot.frogpilot.controls.lib.frogpilot_events import FrogPilotEvents
|
from openpilot.frogpilot.controls.lib.frogpilot_events import FrogPilotEvents
|
||||||
from openpilot.frogpilot.controls.lib.frogpilot_following import FrogPilotFollowing
|
from openpilot.frogpilot.controls.lib.frogpilot_following import FrogPilotFollowing
|
||||||
from openpilot.frogpilot.controls.lib.frogpilot_vcruise import FrogPilotVCruise
|
from openpilot.frogpilot.controls.lib.frogpilot_vcruise import FrogPilotVCruise
|
||||||
|
from openpilot.frogpilot.controls.lib.weather_checker import WeatherChecker
|
||||||
|
|
||||||
class FrogPilotPlanner:
|
class FrogPilotPlanner:
|
||||||
def __init__(self, error_log, ThemeManager):
|
def __init__(self, error_log, ThemeManager):
|
||||||
@ -26,6 +27,7 @@ class FrogPilotPlanner:
|
|||||||
self.frogpilot_events = FrogPilotEvents(self, error_log, ThemeManager)
|
self.frogpilot_events = FrogPilotEvents(self, error_log, ThemeManager)
|
||||||
self.frogpilot_following = FrogPilotFollowing(self)
|
self.frogpilot_following = FrogPilotFollowing(self)
|
||||||
self.frogpilot_vcruise = FrogPilotVCruise(self)
|
self.frogpilot_vcruise = FrogPilotVCruise(self)
|
||||||
|
self.frogpilot_weather = WeatherChecker()
|
||||||
|
|
||||||
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg:
|
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg:
|
||||||
self.CP = msg
|
self.CP = msg
|
||||||
@ -113,6 +115,11 @@ class FrogPilotPlanner:
|
|||||||
|
|
||||||
self.v_cruise = self.frogpilot_vcruise.update(gps_position, now, time_validated, v_cruise, v_ego, sm, frogpilot_toggles)
|
self.v_cruise = self.frogpilot_vcruise.update(gps_position, now, time_validated, v_cruise, v_ego, sm, frogpilot_toggles)
|
||||||
|
|
||||||
|
if gps_position and time_validated and frogpilot_toggles.weather_presets:
|
||||||
|
self.frogpilot_weather.update_weather(gps_position, now, frogpilot_toggles)
|
||||||
|
else:
|
||||||
|
self.frogpilot_weather.weather_id = 0
|
||||||
|
|
||||||
def update_lead_status(self):
|
def update_lead_status(self):
|
||||||
following_lead = self.lead_one.status
|
following_lead = self.lead_one.status
|
||||||
following_lead &= self.lead_one.dRel < self.model_length + STOP_DISTANCE
|
following_lead &= self.lead_one.dRel < self.model_length + STOP_DISTANCE
|
||||||
@ -146,6 +153,8 @@ class FrogPilotPlanner:
|
|||||||
frogpilotPlan.frogpilotEvents = self.frogpilot_events.events.to_msg()
|
frogpilotPlan.frogpilotEvents = self.frogpilot_events.events.to_msg()
|
||||||
|
|
||||||
frogpilotPlan.increasedStoppedDistance = frogpilot_toggles.increase_stopped_distance if not sm["frogpilotCarState"].trafficModeEnabled else 0
|
frogpilotPlan.increasedStoppedDistance = frogpilot_toggles.increase_stopped_distance if not sm["frogpilotCarState"].trafficModeEnabled else 0
|
||||||
|
if self.frogpilot_weather.weather_id != 0:
|
||||||
|
frogpilotPlan.increasedStoppedDistance += self.frogpilot_weather.increase_stopped_distance
|
||||||
|
|
||||||
frogpilotPlan.laneWidthLeft = self.lane_width_left
|
frogpilotPlan.laneWidthLeft = self.lane_width_left
|
||||||
frogpilotPlan.laneWidthRight = self.lane_width_right
|
frogpilotPlan.laneWidthRight = self.lane_width_right
|
||||||
@ -177,4 +186,7 @@ class FrogPilotPlanner:
|
|||||||
|
|
||||||
frogpilotPlan.vCruise = self.v_cruise
|
frogpilotPlan.vCruise = self.v_cruise
|
||||||
|
|
||||||
|
frogpilotPlan.weatherDaytime = self.frogpilot_weather.is_daytime
|
||||||
|
frogpilotPlan.weatherId = self.frogpilot_weather.weather_id
|
||||||
|
|
||||||
pm.send("frogpilotPlan", frogpilot_plan_send)
|
pm.send("frogpilotPlan", frogpilot_plan_send)
|
||||||
|
|||||||
@ -90,6 +90,8 @@ class CurveSpeedController:
|
|||||||
|
|
||||||
def update_target(self, v_ego):
|
def update_target(self, v_ego):
|
||||||
lateral_acceleration = self.lateral_acceleration
|
lateral_acceleration = self.lateral_acceleration
|
||||||
|
if self.frogpilot_planner.frogpilot_weather.weather_id != 0:
|
||||||
|
lateral_acceleration -= self.lateral_acceleration * self.frogpilot_planner.frogpilot_weather.reduce_lateral_acceleration
|
||||||
|
|
||||||
if self.target_set:
|
if self.target_set:
|
||||||
csc_speed = (lateral_acceleration / abs(self.frogpilot_planner.road_curvature))**0.5
|
csc_speed = (lateral_acceleration / abs(self.frogpilot_planner.road_curvature))**0.5
|
||||||
|
|||||||
@ -64,6 +64,9 @@ class FrogPilotAcceleration:
|
|||||||
self.max_accel = min(get_max_accel_low_speeds(self.max_accel, self.frogpilot_planner.v_cruise), self.max_accel)
|
self.max_accel = min(get_max_accel_low_speeds(self.max_accel, self.frogpilot_planner.v_cruise), self.max_accel)
|
||||||
self.max_accel = min(get_max_accel_ramp_off(self.max_accel, self.frogpilot_planner.v_cruise, v_ego), self.max_accel)
|
self.max_accel = min(get_max_accel_ramp_off(self.max_accel, self.frogpilot_planner.v_cruise, v_ego), self.max_accel)
|
||||||
|
|
||||||
|
if self.frogpilot_planner.frogpilot_weather.weather_id != 0:
|
||||||
|
self.max_accel -= self.max_accel * self.frogpilot_planner.frogpilot_weather.reduce_acceleration
|
||||||
|
|
||||||
if self.frogpilot_planner.tracking_lead:
|
if self.frogpilot_planner.tracking_lead:
|
||||||
self.min_accel = ACCEL_MIN
|
self.min_accel = ACCEL_MIN
|
||||||
elif sm["frogpilotCarState"].forceCoast:
|
elif sm["frogpilotCarState"].forceCoast:
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import numpy as np
|
|||||||
|
|
||||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import COMFORT_BRAKE, STOP_DISTANCE, desired_follow_distance, get_jerk_factor, get_T_FOLLOW
|
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import COMFORT_BRAKE, STOP_DISTANCE, desired_follow_distance, get_jerk_factor, get_T_FOLLOW
|
||||||
|
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT
|
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT, MAX_T_FOLLOW
|
||||||
|
|
||||||
TRAFFIC_MODE_BP = [0., CITY_SPEED_LIMIT]
|
TRAFFIC_MODE_BP = [0., CITY_SPEED_LIMIT]
|
||||||
|
|
||||||
@ -63,9 +63,13 @@ class FrogPilotFollowing:
|
|||||||
self.danger_jerk = self.base_danger_jerk
|
self.danger_jerk = self.base_danger_jerk
|
||||||
self.speed_jerk = self.base_speed_jerk
|
self.speed_jerk = self.base_speed_jerk
|
||||||
|
|
||||||
self.following_lead = self.frogpilot_planner.tracking_lead and self.frogpilot_planner.lead_one.dRel < (self.t_follow + 1) * v_ego
|
self.following_lead = self.frogpilot_planner.tracking_lead and self.frogpilot_planner.lead_one.dRel < (self.t_follow * 2) * v_ego
|
||||||
|
|
||||||
|
if self.frogpilot_planner.frogpilot_weather.weather_id != 0:
|
||||||
|
self.t_follow = min(self.t_follow + self.frogpilot_planner.frogpilot_weather.increase_following_distance, MAX_T_FOLLOW)
|
||||||
|
|
||||||
if sm["controlsState"].enabled and self.frogpilot_planner.tracking_lead:
|
if sm["controlsState"].enabled and self.frogpilot_planner.tracking_lead:
|
||||||
|
if not sm["frogpilotCarState"].trafficModeEnabled:
|
||||||
self.update_follow_values(self.frogpilot_planner.lead_one.dRel, v_ego, self.frogpilot_planner.lead_one.vLead, frogpilot_toggles)
|
self.update_follow_values(self.frogpilot_planner.lead_one.dRel, v_ego, self.frogpilot_planner.lead_one.vLead, frogpilot_toggles)
|
||||||
self.desired_follow_distance = int(desired_follow_distance(v_ego, self.frogpilot_planner.lead_one.vLead, self.t_follow))
|
self.desired_follow_distance = int(desired_follow_distance(v_ego, self.frogpilot_planner.lead_one.vLead, self.t_follow))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -1,14 +1,16 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from cereal import log
|
||||||
from openpilot.common.conversions import Conversions as CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
from openpilot.common.realtime import DT_MDL
|
from openpilot.common.realtime import DT_MDL
|
||||||
from openpilot.selfdrive.controls.controlsd import EventName, FrogPilotEventName, State
|
from openpilot.selfdrive.controls.controlsd import ACTIVE_STATES, EventName, FrogPilotEventName, State
|
||||||
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
|
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
|
||||||
from openpilot.selfdrive.ui.soundd import FrogPilotAudibleAlert
|
from openpilot.selfdrive.ui.soundd import FrogPilotAudibleAlert
|
||||||
|
|
||||||
from openpilot.frogpilot.common.frogpilot_utilities import clean_model_name
|
from openpilot.frogpilot.common.frogpilot_utilities import clean_model_name
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import params
|
from openpilot.frogpilot.common.frogpilot_variables import params
|
||||||
|
from openpilot.frogpilot.controls.lib.weather_checker import WEATHER_CATEGORIES
|
||||||
|
|
||||||
RANDOM_EVENTS = {
|
RANDOM_EVENTS = {
|
||||||
FrogPilotEventName.accel30: "accel30",
|
FrogPilotEventName.accel30: "accel30",
|
||||||
@ -28,6 +30,7 @@ RANDOM_EVENTS = {
|
|||||||
class FrogPilotTracking:
|
class FrogPilotTracking:
|
||||||
def __init__(self, frogpilot_planner, frogpilot_toggles):
|
def __init__(self, frogpilot_planner, frogpilot_toggles):
|
||||||
self.frogpilot_events = frogpilot_planner.frogpilot_events
|
self.frogpilot_events = frogpilot_planner.frogpilot_events
|
||||||
|
self.frogpilot_weather = frogpilot_planner.frogpilot_weather
|
||||||
|
|
||||||
self.frogpilot_stats = json.loads(params.get("FrogPilotStats") or "{}")
|
self.frogpilot_stats = json.loads(params.get("FrogPilotStats") or "{}")
|
||||||
self.frogpilot_stats.setdefault("AOLTime", self.frogpilot_stats.get("TotalAOLTime", 0))
|
self.frogpilot_stats.setdefault("AOLTime", self.frogpilot_stats.get("TotalAOLTime", 0))
|
||||||
@ -37,6 +40,14 @@ class FrogPilotTracking:
|
|||||||
|
|
||||||
self.frogpilot_stats = {key: value for key, value in self.frogpilot_stats.items() if not key.startswith("Total")}
|
self.frogpilot_stats = {key: value for key, value in self.frogpilot_stats.items() if not key.startswith("Total")}
|
||||||
|
|
||||||
|
if "ResetStats" not in self.frogpilot_stats:
|
||||||
|
self.frogpilot_stats["Disengages"] = 0
|
||||||
|
self.frogpilot_stats["Engages"] = 0
|
||||||
|
self.frogpilot_stats["FrogChirps"] = 0
|
||||||
|
self.frogpilot_stats["FrogSqueaks"] = 0
|
||||||
|
self.frogpilot_stats["Overrides"] = 0
|
||||||
|
self.frogpilot_stats["ResetStats"] = True
|
||||||
|
|
||||||
params.put("FrogPilotStats", json.dumps(self.frogpilot_stats))
|
params.put("FrogPilotStats", json.dumps(self.frogpilot_stats))
|
||||||
|
|
||||||
self.drive_added = False
|
self.drive_added = False
|
||||||
@ -48,8 +59,10 @@ class FrogPilotTracking:
|
|||||||
self.previous_events = set()
|
self.previous_events = set()
|
||||||
self.previous_random_events = set()
|
self.previous_random_events = set()
|
||||||
|
|
||||||
|
self.personality_map = {v: k.capitalize() for k, v in log.LongitudinalPersonality.schema.enumerants.items()}
|
||||||
|
|
||||||
|
self.previous_state = State.disabled
|
||||||
self.sound = FrogPilotAudibleAlert.none
|
self.sound = FrogPilotAudibleAlert.none
|
||||||
self.state = State.disabled
|
|
||||||
|
|
||||||
self.model_name = clean_model_name(dict(zip(frogpilot_toggles.available_models.split(","), frogpilot_toggles.available_model_names.split(",")))[frogpilot_toggles.model])
|
self.model_name = clean_model_name(dict(zip(frogpilot_toggles.available_models.split(","), frogpilot_toggles.available_model_names.split(",")))[frogpilot_toggles.model])
|
||||||
|
|
||||||
@ -83,6 +96,11 @@ class FrogPilotTracking:
|
|||||||
self.frogpilot_stats["LateralTime"] = self.frogpilot_stats.get("LateralTime", 0) + DT_MDL
|
self.frogpilot_stats["LateralTime"] = self.frogpilot_stats.get("LateralTime", 0) + DT_MDL
|
||||||
if sm["carControl"].longActive:
|
if sm["carControl"].longActive:
|
||||||
self.frogpilot_stats["LongitudinalTime"] = self.frogpilot_stats.get("LongitudinalTime", 0) + DT_MDL
|
self.frogpilot_stats["LongitudinalTime"] = self.frogpilot_stats.get("LongitudinalTime", 0) + DT_MDL
|
||||||
|
|
||||||
|
personality_name = self.personality_map.get(sm["controlsState"].personality, "Unknown")
|
||||||
|
total_personality_times = self.frogpilot_stats.get("PersonalityTimes", {})
|
||||||
|
total_personality_times[personality_name] = total_personality_times.get(personality_name, 0) + DT_MDL
|
||||||
|
self.frogpilot_stats["PersonalityTimes"] = total_personality_times
|
||||||
elif sm["frogpilotCarState"].alwaysOnLateralEnabled:
|
elif sm["frogpilotCarState"].alwaysOnLateralEnabled:
|
||||||
self.frogpilot_stats["AOLTime"] = self.frogpilot_stats.get("AOLTime", 0) + DT_MDL
|
self.frogpilot_stats["AOLTime"] = self.frogpilot_stats.get("AOLTime", 0) + DT_MDL
|
||||||
|
|
||||||
@ -101,21 +119,21 @@ class FrogPilotTracking:
|
|||||||
self.distance_since_override += v_ego * DT_MDL
|
self.distance_since_override += v_ego * DT_MDL
|
||||||
self.frogpilot_stats["LongestDistanceWithoutOverride"] = max(self.distance_since_override, self.frogpilot_stats.get("LongestDistanceWithoutOverride", 0))
|
self.frogpilot_stats["LongestDistanceWithoutOverride"] = max(self.distance_since_override, self.frogpilot_stats.get("LongestDistanceWithoutOverride", 0))
|
||||||
|
|
||||||
if sm["controlsState"].state != self.state:
|
if sm["controlsState"].state != self.previous_state:
|
||||||
if sm["controlsState"].state == State.disabled:
|
if sm["controlsState"].state in ACTIVE_STATES and self.previous_state not in ACTIVE_STATES:
|
||||||
self.frogpilot_stats["Disengages"] = self.frogpilot_stats.get("Disengages", 0) + 1
|
|
||||||
|
|
||||||
if frogpilot_toggles.sound_pack == "frog":
|
|
||||||
self.frogpilot_stats["FrogSqueaks"] = self.frogpilot_stats.get("FrogSqueaks", 0) + 1
|
|
||||||
elif sm["controlsState"].state == State.enabled:
|
|
||||||
self.frogpilot_stats["Engages"] = self.frogpilot_stats.get("Engages", 0) + 1
|
self.frogpilot_stats["Engages"] = self.frogpilot_stats.get("Engages", 0) + 1
|
||||||
|
|
||||||
if frogpilot_toggles.sound_pack == "frog":
|
if frogpilot_toggles.sound_pack == "frog":
|
||||||
self.frogpilot_stats["FrogChirps"] = self.frogpilot_stats.get("FrogChirps", 0) + 1
|
self.frogpilot_stats["FrogChirps"] = self.frogpilot_stats.get("FrogChirps", 0) + 1
|
||||||
elif sm["controlsState"].state == State.overriding:
|
|
||||||
|
elif sm["controlsState"].state == State.disabled and self.previous_state in ACTIVE_STATES:
|
||||||
|
self.frogpilot_stats["Disengages"] = self.frogpilot_stats.get("Disengages", 0) + 1
|
||||||
|
if frogpilot_toggles.sound_pack == "frog":
|
||||||
|
self.frogpilot_stats["FrogSqueaks"] = self.frogpilot_stats.get("FrogSqueaks", 0) + 1
|
||||||
|
|
||||||
|
if sm["controlsState"].state == State.overriding and self.previous_state != State.overriding:
|
||||||
self.frogpilot_stats["Overrides"] = self.frogpilot_stats.get("Overrides", 0) + 1
|
self.frogpilot_stats["Overrides"] = self.frogpilot_stats.get("Overrides", 0) + 1
|
||||||
|
|
||||||
self.state = sm["controlsState"].state
|
self.previous_state = sm["controlsState"].state
|
||||||
|
|
||||||
current_events = {event for event in self.frogpilot_events.event_names}
|
current_events = {event for event in self.frogpilot_events.event_names}
|
||||||
if len(current_events) > 0:
|
if len(current_events) > 0:
|
||||||
@ -140,6 +158,30 @@ class FrogPilotTracking:
|
|||||||
|
|
||||||
self.previous_random_events = current_random_events
|
self.previous_random_events = current_random_events
|
||||||
|
|
||||||
|
if self.frogpilot_weather.sunrise != 0 and self.frogpilot_weather.sunset != 0:
|
||||||
|
if self.frogpilot_weather.is_daytime:
|
||||||
|
self.frogpilot_stats["DayTime"] = self.frogpilot_stats.get("DayTime", 0) + DT_MDL
|
||||||
|
else:
|
||||||
|
self.frogpilot_stats["NightTime"] = self.frogpilot_stats.get("NightTime", 0) + DT_MDL
|
||||||
|
|
||||||
|
weather_api_calls = self.frogpilot_stats.get("WeatherAPICalls", {})
|
||||||
|
weather_api_calls["2.5"] = weather_api_calls.get("2.5", 0) + self.frogpilot_weather.api_25_calls
|
||||||
|
weather_api_calls["3.0"] = weather_api_calls.get("3.0", 0) + self.frogpilot_weather.api_3_calls
|
||||||
|
self.frogpilot_stats["WeatherAPICalls"] = weather_api_calls
|
||||||
|
|
||||||
|
self.frogpilot_weather.api_25_calls = 0
|
||||||
|
self.frogpilot_weather.api_3_calls = 0
|
||||||
|
|
||||||
|
suffix = "unknown"
|
||||||
|
for category in WEATHER_CATEGORIES.values():
|
||||||
|
if any(start <= self.frogpilot_weather.weather_id <= end for start, end in category["ranges"]):
|
||||||
|
suffix = category["suffix"]
|
||||||
|
break
|
||||||
|
|
||||||
|
weather_times = self.frogpilot_stats.get("WeatherTimes", {})
|
||||||
|
weather_times[suffix] = weather_times.get(suffix, 0) + DT_MDL
|
||||||
|
self.frogpilot_stats["WeatherTimes"] = weather_times
|
||||||
|
|
||||||
if self.tracked_time > 60 and sm["carState"].standstill and self.enabled:
|
if self.tracked_time > 60 and sm["carState"].standstill and self.enabled:
|
||||||
if time_validated:
|
if time_validated:
|
||||||
current_month = now.month
|
current_month = now.month
|
||||||
|
|||||||
@ -58,16 +58,6 @@ class FrogPilotVCruise:
|
|||||||
|
|
||||||
self.csc_target = v_cruise
|
self.csc_target = v_cruise
|
||||||
|
|
||||||
# Mike's extended lead linear braking
|
|
||||||
if self.frogpilot_planner.lead_one.vLead < v_ego > CRUISING_SPEED and sm["controlsState"].enabled and self.frogpilot_planner.tracking_lead and frogpilot_toggles.human_following:
|
|
||||||
if not self.frogpilot_planner.frogpilot_following.following_lead:
|
|
||||||
decel_rate = (v_ego - self.frogpilot_planner.lead_one.vLead)**2 / self.frogpilot_planner.lead_one.dRel
|
|
||||||
self.braking_target = max(v_ego - (decel_rate * DT_MDL), self.frogpilot_planner.lead_one.vLead + CRUISING_SPEED)
|
|
||||||
else:
|
|
||||||
self.braking_target = v_cruise
|
|
||||||
else:
|
|
||||||
self.braking_target = v_cruise
|
|
||||||
|
|
||||||
# Pfeiferj's Speed Limit Controller
|
# Pfeiferj's Speed Limit Controller
|
||||||
self.slc.frogpilot_toggles = frogpilot_toggles
|
self.slc.frogpilot_toggles = frogpilot_toggles
|
||||||
|
|
||||||
@ -97,10 +87,10 @@ class FrogPilotVCruise:
|
|||||||
|
|
||||||
self.tracked_model_length = self.frogpilot_planner.model_length
|
self.tracked_model_length = self.frogpilot_planner.model_length
|
||||||
|
|
||||||
targets = [self.braking_target, self.csc_target, v_cruise]
|
targets = [self.csc_target, v_cruise]
|
||||||
if frogpilot_toggles.speed_limit_controller:
|
if frogpilot_toggles.speed_limit_controller:
|
||||||
targets.append(max(self.slc.overridden_speed, self.slc_target + self.slc_offset) - v_ego_diff)
|
targets.append(max(self.slc.overridden_speed, self.slc_target + self.slc_offset) - v_ego_diff)
|
||||||
|
|
||||||
v_cruise = min([target if target > CRUISING_SPEED else v_cruise for target in targets])
|
v_cruise = min([target if target >= CRUISING_SPEED else v_cruise for target in targets])
|
||||||
|
|
||||||
return v_cruise
|
return v_cruise
|
||||||
|
|||||||
@ -18,7 +18,7 @@ from openpilot.selfdrive.controls.lib.pid import PIDController
|
|||||||
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
||||||
from openpilot.selfdrive.modeld.constants import ModelConstants
|
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||||
|
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import NNFF_MODELS_PATH, get_nnff_model_files
|
from openpilot.frogpilot.common.frogpilot_variables import NNFF_MODELS_PATH, get_nnff_model_files, get_nnff_substitutes
|
||||||
|
|
||||||
# At higher speeds (25+mph) we can assume:
|
# At higher speeds (25+mph) we can assume:
|
||||||
# Lateral acceleration achieved by a specific car correlates to
|
# Lateral acceleration achieved by a specific car correlates to
|
||||||
@ -32,7 +32,7 @@ from openpilot.frogpilot.common.frogpilot_variables import NNFF_MODELS_PATH, get
|
|||||||
# move it at all, this is compensated for too.
|
# move it at all, this is compensated for too.
|
||||||
|
|
||||||
# dict used to rename activation functions whose names aren't valid python identifiers
|
# dict used to rename activation functions whose names aren't valid python identifiers
|
||||||
ACTIVATION_FUNCTION_NAMES = {'σ': 'sigmoid'}
|
ACTIVATION_FUNCTION_NAMES = {"σ": "sigmoid"}
|
||||||
|
|
||||||
LOW_SPEED_X = [0, 10, 20, 30]
|
LOW_SPEED_X = [0, 10, 20, 30]
|
||||||
LOW_SPEED_Y = [12, 3, 1, 0]
|
LOW_SPEED_Y = [12, 3, 1, 0]
|
||||||
@ -52,8 +52,8 @@ class FluxModel:
|
|||||||
|
|
||||||
self.layers = []
|
self.layers = []
|
||||||
for layer_params in params["layers"]:
|
for layer_params in params["layers"]:
|
||||||
bias_array = np.array(layer_params[next(key for key in layer_params.keys() if key.endswith('_b'))], dtype=np.float32).T
|
bias_array = np.array(layer_params[next(key for key in layer_params.keys() if key.endswith("_b"))], dtype=np.float32).T
|
||||||
weight_array = np.array(layer_params[next(key for key in layer_params.keys() if key.endswith('_W'))], dtype=np.float32).T
|
weight_array = np.array(layer_params[next(key for key in layer_params.keys() if key.endswith("_W"))], dtype=np.float32).T
|
||||||
|
|
||||||
activation = layer_params["activation"]
|
activation = layer_params["activation"]
|
||||||
for name, replacement in ACTIVATION_FUNCTION_NAMES.items():
|
for name, replacement in ACTIVATION_FUNCTION_NAMES.items():
|
||||||
@ -126,15 +126,27 @@ def get_nn_model_path(car, eps_firmware) -> str | None:
|
|||||||
best = max(candidates, key=lambda model: similarity(model, query))
|
best = max(candidates, key=lambda model: similarity(model, query))
|
||||||
return os.path.join(NNFF_MODELS_PATH, f"{best}.json"), similarity(best, query)
|
return os.path.join(NNFF_MODELS_PATH, f"{best}.json"), similarity(best, query)
|
||||||
|
|
||||||
def find_valid_model(*queries):
|
def find_valid_model(*queries_with_candidates):
|
||||||
for query in queries:
|
for query, candidate in queries_with_candidates:
|
||||||
path, score = best_model_path(query)
|
path, score = best_model_path(query)
|
||||||
if path and car in path and score >= 0.9:
|
if path and candidate in path and score >= 0.9:
|
||||||
return path
|
return path
|
||||||
return None
|
return None
|
||||||
|
|
||||||
query1 = f"{car} {eps_firmware}" if len(eps_firmware) > 3 else car
|
substitutes = get_nnff_substitutes()
|
||||||
return find_valid_model(query1, car)
|
sub_candidate = substitutes.get(car, car)
|
||||||
|
|
||||||
|
candidates_to_check = [car]
|
||||||
|
if car != sub_candidate:
|
||||||
|
candidates_to_check.append(sub_candidate)
|
||||||
|
|
||||||
|
queries = []
|
||||||
|
for candidate in candidates_to_check:
|
||||||
|
query_with_fw = f"{candidate} {eps_firmware}" if len(eps_firmware) > 3 else candidate
|
||||||
|
queries.append((query_with_fw, candidate))
|
||||||
|
queries.append((candidate, candidate))
|
||||||
|
|
||||||
|
return find_valid_model(*queries)
|
||||||
|
|
||||||
def get_predicted_lateral_jerk(lat_accels, t_diffs):
|
def get_predicted_lateral_jerk(lat_accels, t_diffs):
|
||||||
# compute finite difference between subsequent model_data.acceleration.y values
|
# compute finite difference between subsequent model_data.acceleration.y values
|
||||||
@ -162,8 +174,8 @@ class LatControlNNFF(LatControl):
|
|||||||
self.nnff_loaded = self.lat_torque_nn_model is not None
|
self.nnff_loaded = self.lat_torque_nn_model is not None
|
||||||
|
|
||||||
self.torque_params = CP.lateralTuning.torque
|
self.torque_params = CP.lateralTuning.torque
|
||||||
self.pid = PIDController(self.torque_params.kp, self.torque_params.ki,
|
self.pid = PIDController(1.0, 0.3, k_d=0.0,
|
||||||
k_f=self.torque_params.kf, pos_limit=self.steer_max, neg_limit=-self.steer_max)
|
pos_limit=self.steer_max, neg_limit=-self.steer_max)
|
||||||
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
|
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
|
||||||
self.use_steering_angle = self.torque_params.useSteeringAngle
|
self.use_steering_angle = self.torque_params.useSteeringAngle
|
||||||
self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg
|
self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg
|
||||||
@ -336,7 +348,6 @@ class LatControlNNFF(LatControl):
|
|||||||
ff = self.torque_from_lateral_accel(gravity_adjusted_lateral_accel, self.torque_params)
|
ff = self.torque_from_lateral_accel(gravity_adjusted_lateral_accel, self.torque_params)
|
||||||
|
|
||||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
||||||
self.pid._k_p = frogpilot_toggles.steerKp
|
|
||||||
output_torque = self.pid.update(pid_log.error,
|
output_torque = self.pid.update(pid_log.error,
|
||||||
feedforward=ff,
|
feedforward=ff,
|
||||||
speed=CS.vEgo,
|
speed=CS.vEgo,
|
||||||
|
|||||||
171
frogpilot/controls/lib/weather_checker.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from openpilot.common.params import Params
|
||||||
|
|
||||||
|
from openpilot.frogpilot.common.frogpilot_utilities import calculate_distance_to_point, is_url_pingable
|
||||||
|
|
||||||
|
CACHE_DISTANCE = 25
|
||||||
|
MAX_RETRIES = 3
|
||||||
|
RETRY_DELAY = 60
|
||||||
|
|
||||||
|
# Reference: https://openweathermap.org/weather-conditions
|
||||||
|
WEATHER_CATEGORIES = {
|
||||||
|
"RAIN": {
|
||||||
|
"ranges": [(300, 321), (500, 504)],
|
||||||
|
"suffix": "rain",
|
||||||
|
},
|
||||||
|
"RAIN_STORM": {
|
||||||
|
"ranges": [(200, 232), (511, 511), (520, 531)],
|
||||||
|
"suffix": "rain_storm",
|
||||||
|
},
|
||||||
|
"SNOW": {
|
||||||
|
"ranges": [(600, 622)],
|
||||||
|
"suffix": "snow",
|
||||||
|
},
|
||||||
|
"LOW_VISIBILITY": {
|
||||||
|
"ranges": [(701, 762)],
|
||||||
|
"suffix": "low_visibility",
|
||||||
|
},
|
||||||
|
"CLEAR": {
|
||||||
|
"ranges": [(800, 800)],
|
||||||
|
"suffix": "clear",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
class WeatherChecker:
|
||||||
|
def __init__(self):
|
||||||
|
self.is_daytime = False
|
||||||
|
|
||||||
|
self.api_25_calls = 0
|
||||||
|
self.api_3_calls = 0
|
||||||
|
self.increase_following_distance = 0
|
||||||
|
self.increase_stopped_distance = 0
|
||||||
|
self.reduce_acceleration = 0
|
||||||
|
self.reduce_lateral_acceleration = 0
|
||||||
|
self.sunrise = 0
|
||||||
|
self.sunset = 0
|
||||||
|
self.weather_id = 0
|
||||||
|
|
||||||
|
self.hourly_forecast = None
|
||||||
|
self.last_gps_position = None
|
||||||
|
self.last_updated = None
|
||||||
|
|
||||||
|
user_api_key = Params().get("WeatherToken", encoding="utf-8")
|
||||||
|
self.api_key = user_api_key or os.environ.get("WEATHER_TOKEN", "")
|
||||||
|
|
||||||
|
if user_api_key:
|
||||||
|
self.check_interval = 60
|
||||||
|
else:
|
||||||
|
self.check_interval = 15 * 60
|
||||||
|
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update({"Accept-Language": "en"})
|
||||||
|
self.session.headers.update({"User-Agent": "frogpilot-weather-checker/1.0 (https://github.com/FrogAi/FrogPilot)"})
|
||||||
|
|
||||||
|
self.executor = ThreadPoolExecutor(max_workers=1)
|
||||||
|
|
||||||
|
def update_offsets(self, frogpilot_toggles):
|
||||||
|
suffix = WEATHER_CATEGORIES["CLEAR"]["suffix"]
|
||||||
|
for category in WEATHER_CATEGORIES.values():
|
||||||
|
if any(start <= self.weather_id <= end for start, end in category["ranges"]):
|
||||||
|
suffix = category["suffix"]
|
||||||
|
break
|
||||||
|
|
||||||
|
if suffix != WEATHER_CATEGORIES["CLEAR"]["suffix"]:
|
||||||
|
self.increase_following_distance = getattr(frogpilot_toggles, f"increase_following_distance_{suffix}")
|
||||||
|
self.increase_stopped_distance = getattr(frogpilot_toggles, f"increase_stopped_distance_{suffix}")
|
||||||
|
self.reduce_acceleration = getattr(frogpilot_toggles, f"reduce_acceleration_{suffix}")
|
||||||
|
self.reduce_lateral_acceleration = getattr(frogpilot_toggles, f"reduce_lateral_acceleration_{suffix}")
|
||||||
|
else:
|
||||||
|
self.increase_following_distance = 0
|
||||||
|
self.increase_stopped_distance = 0
|
||||||
|
self.reduce_acceleration = 0
|
||||||
|
self.reduce_lateral_acceleration = 0
|
||||||
|
|
||||||
|
def update_weather(self, gps_position, now, frogpilot_toggles):
|
||||||
|
if not self.api_key:
|
||||||
|
self.weather_id = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.last_gps_position and self.last_updated:
|
||||||
|
distance = calculate_distance_to_point(
|
||||||
|
self.last_gps_position["latitude"] * CV.DEG_TO_RAD,
|
||||||
|
self.last_gps_position["longitude"] * CV.DEG_TO_RAD,
|
||||||
|
gps_position.get("latitude") * CV.DEG_TO_RAD,
|
||||||
|
gps_position.get("longitude") * CV.DEG_TO_RAD
|
||||||
|
)
|
||||||
|
if distance / 1000 > CACHE_DISTANCE:
|
||||||
|
self.hourly_forecast = None
|
||||||
|
self.last_updated = None
|
||||||
|
|
||||||
|
if self.sunrise and self.sunset:
|
||||||
|
self.is_daytime = self.sunrise <= int(now.timestamp()) < self.sunset
|
||||||
|
|
||||||
|
if self.last_updated and (now - self.last_updated).total_seconds() < self.check_interval:
|
||||||
|
if self.hourly_forecast:
|
||||||
|
current_forecast = min(self.hourly_forecast, key=lambda f: abs(f["dt"] - now.timestamp()))
|
||||||
|
self.weather_id = current_forecast.get("weather", [{}])[0].get("id", 0)
|
||||||
|
self.update_offsets(frogpilot_toggles)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.last_updated = now
|
||||||
|
|
||||||
|
def complete_request(future):
|
||||||
|
data = future.result()
|
||||||
|
if data:
|
||||||
|
self.hourly_forecast = data.get("hourly")
|
||||||
|
self.last_gps_position = gps_position
|
||||||
|
|
||||||
|
if "current" in data:
|
||||||
|
source_data = data.get("current", {})
|
||||||
|
current_data = source_data
|
||||||
|
else:
|
||||||
|
source_data = data
|
||||||
|
current_data = source_data.get("sys", source_data)
|
||||||
|
|
||||||
|
self.sunrise = current_data.get("sunrise", 0)
|
||||||
|
self.sunset = current_data.get("sunset", 0)
|
||||||
|
self.weather_id = source_data.get("weather", [{}])[0].get("id", 0)
|
||||||
|
|
||||||
|
self.update_offsets(frogpilot_toggles)
|
||||||
|
|
||||||
|
def make_request():
|
||||||
|
if not is_url_pingable("https://api.openweathermap.org"):
|
||||||
|
return None
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"lat": gps_position["latitude"],
|
||||||
|
"lon": gps_position["longitude"],
|
||||||
|
"appid": self.api_key,
|
||||||
|
"units": "metric",
|
||||||
|
"exclude": "alerts,minutely,daily",
|
||||||
|
}
|
||||||
|
|
||||||
|
for attempt in range(1, MAX_RETRIES + 1):
|
||||||
|
try:
|
||||||
|
self.api_3_calls += 1
|
||||||
|
response = self.session.get("https://api.openweathermap.org/data/3.0/onecall", params=params, timeout=10)
|
||||||
|
if response.status_code == 429:
|
||||||
|
fallback_params = params.copy()
|
||||||
|
fallback_params.pop("exclude", None)
|
||||||
|
self.api_25_calls += 1
|
||||||
|
fallback_response = self.session.get("https://api.openweathermap.org/data/2.5/weather", params=fallback_params, timeout=10)
|
||||||
|
fallback_response.raise_for_status()
|
||||||
|
return fallback_response.json()
|
||||||
|
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
except Exception:
|
||||||
|
if attempt < MAX_RETRIES:
|
||||||
|
time.sleep(RETRY_DELAY)
|
||||||
|
continue
|
||||||
|
return None
|
||||||
|
|
||||||
|
future = self.executor.submit(make_request)
|
||||||
|
future.add_done_callback(complete_request)
|
||||||
@ -2,20 +2,18 @@ import json
|
|||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import requests
|
import requests
|
||||||
import sys
|
|
||||||
|
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), "..", "third_party"))
|
|
||||||
|
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from influxdb_client import InfluxDBClient, Point
|
from influxdb_client import InfluxDBClient, Point
|
||||||
from influxdb_client.client.write_api import SYNCHRONOUS
|
from influxdb_client.client.write_api import SYNCHRONOUS
|
||||||
|
|
||||||
|
from cereal import car
|
||||||
from openpilot.common.conversions import Conversions as CV
|
from openpilot.common.conversions import Conversions as CV
|
||||||
from openpilot.system.hardware import HARDWARE
|
from openpilot.system.hardware import HARDWARE
|
||||||
from openpilot.system.version import get_build_metadata
|
from openpilot.system.version import get_build_metadata
|
||||||
|
|
||||||
from openpilot.frogpilot.common.frogpilot_utilities import clean_model_name, run_cmd
|
from openpilot.frogpilot.common.frogpilot_utilities import clean_model_name
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import get_frogpilot_toggles, params
|
from openpilot.frogpilot.common.frogpilot_variables import get_frogpilot_toggles, params
|
||||||
|
|
||||||
BASE_URL = "https://nominatim.openstreetmap.org"
|
BASE_URL = "https://nominatim.openstreetmap.org"
|
||||||
@ -93,7 +91,7 @@ def get_city_center(latitude, longitude):
|
|||||||
print(f"Falling back to (0, 0) for {latitude}, {longitude}")
|
print(f"Falling back to (0, 0) for {latitude}, {longitude}")
|
||||||
return float(0.0), float(0.0), "N/A", "N/A", "N/A"
|
return float(0.0), float(0.0), "N/A", "N/A", "N/A"
|
||||||
|
|
||||||
except Exception as exception:
|
except Exception:
|
||||||
print(f"Falling back to (0, 0) for {latitude}, {longitude}")
|
print(f"Falling back to (0, 0) for {latitude}, {longitude}")
|
||||||
return float(0.0), float(0.0), "N/A", "N/A", "N/A"
|
return float(0.0), float(0.0), "N/A", "N/A", "N/A"
|
||||||
|
|
||||||
@ -107,18 +105,13 @@ def update_branch_commits(now):
|
|||||||
points.append(Point("branch_commits").field("commit", sha).tag("branch", branch).time(now))
|
points.append(Point("branch_commits").field("commit", sha).tag("branch", branch).time(now))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to fetch commit for {branch}: {e}")
|
print(f"Failed to fetch commit for {branch}: {e}")
|
||||||
|
|
||||||
return points
|
return points
|
||||||
|
|
||||||
|
|
||||||
def send_stats():
|
def send_stats():
|
||||||
try:
|
try:
|
||||||
build_metadata = get_build_metadata()
|
build_metadata = get_build_metadata()
|
||||||
frogpilot_toggles = get_frogpilot_toggles()
|
frogpilot_toggles = get_frogpilot_toggles()
|
||||||
|
|
||||||
if frogpilot_toggles.frogs_go_moo:
|
|
||||||
return
|
|
||||||
|
|
||||||
if frogpilot_toggles.car_make == "mock":
|
if frogpilot_toggles.car_make == "mock":
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -127,71 +120,72 @@ def send_stats():
|
|||||||
token = os.environ.get("STATS_TOKEN", "")
|
token = os.environ.get("STATS_TOKEN", "")
|
||||||
url = os.environ.get("STATS_URL", "")
|
url = os.environ.get("STATS_URL", "")
|
||||||
|
|
||||||
|
car_params = "{}"
|
||||||
|
msg_bytes = params.get("CarParamsPersistent")
|
||||||
|
if msg_bytes:
|
||||||
|
with car.CarParams.from_bytes(msg_bytes) as CP:
|
||||||
|
cp_dict = CP.to_dict()
|
||||||
|
cp_dict.pop("carFw", None)
|
||||||
|
car_params = json.dumps(cp_dict)
|
||||||
|
|
||||||
|
dongle_id = params.get("FrogPilotDongleId", encoding="utf-8")
|
||||||
frogpilot_stats = json.loads(params.get("FrogPilotStats") or "{}")
|
frogpilot_stats = json.loads(params.get("FrogPilotStats") or "{}")
|
||||||
|
|
||||||
location = json.loads(params.get("LastGPSPosition") or "{}")
|
location = json.loads(params.get("LastGPSPosition") or "{}")
|
||||||
if not (location.get("latitude") and location.get("longitude")):
|
original_latitude = location.get("latitude", 0.0)
|
||||||
return
|
original_longitude = location.get("longitude", 0.0)
|
||||||
original_latitude = location.get("latitude")
|
|
||||||
original_longitude = location.get("longitude")
|
|
||||||
latitude, longitude, city, state, country = get_city_center(original_latitude, original_longitude)
|
latitude, longitude, city, state, country = get_city_center(original_latitude, original_longitude)
|
||||||
|
|
||||||
theme_sources = [
|
|
||||||
frogpilot_toggles.icon_pack.replace("-animated", ""),
|
|
||||||
frogpilot_toggles.color_scheme,
|
|
||||||
frogpilot_toggles.distance_icons.replace("-animated", ""),
|
|
||||||
frogpilot_toggles.signal_icons.replace("-animated", ""),
|
|
||||||
frogpilot_toggles.sound_pack
|
|
||||||
]
|
|
||||||
|
|
||||||
theme_counter = Counter(theme_sources)
|
|
||||||
most_common = theme_counter.most_common()
|
|
||||||
max_count = most_common[0][1]
|
|
||||||
selected_theme = random.choice([item for item, count in most_common if count == max_count]).replace("-user_created", "").replace("_", " ")
|
|
||||||
|
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
|
theme_attributes = sorted(["color_scheme", "distance_icons", "icon_pack", "signal_icons", "sound_pack"])
|
||||||
|
theme_counts = Counter(getattr(frogpilot_toggles, attribute).replace("-animated", "") for attribute in theme_attributes)
|
||||||
|
winners = [theme for theme, count in theme_counts.items() if count == max(theme_counts.values(), default=0)]
|
||||||
|
if len(winners) > 1 and "stock" in winners:
|
||||||
|
winners.remove("stock")
|
||||||
|
selected_theme = random.choice(winners).replace("-user_created", "").replace("_", " ") if winners else "stock"
|
||||||
|
|
||||||
user_point = (
|
user_point = (
|
||||||
Point("user_stats")
|
Point("user_stats")
|
||||||
.field("blocked_user", frogpilot_toggles.block_user)
|
.field("calibrated_lateral_acceleration", params.get_float("CalibratedLateralAcceleration"))
|
||||||
.field("car_make", "GM" if frogpilot_toggles.car_make == "gm" else frogpilot_toggles.car_make.title())
|
.field("calibration_progress", params.get_float("CalibrationProgress"))
|
||||||
.field("car_model", frogpilot_toggles.car_model)
|
.field("car_params", car_params)
|
||||||
.field("city", city)
|
.field("city", city)
|
||||||
.field("commit", build_metadata.openpilot.git_commit)
|
.field("commit", build_metadata.openpilot.git_commit)
|
||||||
.field("country", country)
|
.field("country", country)
|
||||||
.field("current_months_kilometers", int(frogpilot_stats.get("CurrentMonthsKilometers", 0)))
|
|
||||||
.field("device", HARDWARE.get_device_type())
|
.field("device", HARDWARE.get_device_type())
|
||||||
.field("driving_model", clean_model_name(frogpilot_toggles.model_name))
|
|
||||||
.field("event", 1)
|
.field("event", 1)
|
||||||
.field("frogpilot_drives", int(frogpilot_stats.get("FrogPilotDrives", 0)))
|
|
||||||
.field("frogpilot_hours", float(frogpilot_stats.get("FrogPilotSeconds", 0)) / (60 * 60))
|
|
||||||
.field("frogpilot_miles", float(frogpilot_stats.get("FrogPilotMeters", 0)) * CV.METER_TO_MILE)
|
|
||||||
.field("goat_scream", frogpilot_toggles.goat_scream_alert)
|
|
||||||
.field("has_cc_long", frogpilot_toggles.has_cc_long)
|
|
||||||
.field("has_openpilot_longitudinal", frogpilot_toggles.openpilot_longitudinal)
|
|
||||||
.field("has_pedal", frogpilot_toggles.has_pedal)
|
|
||||||
.field("has_sdsu", frogpilot_toggles.has_sdsu)
|
|
||||||
.field("has_zss", frogpilot_toggles.has_zss)
|
|
||||||
.field("latitude", latitude)
|
.field("latitude", latitude)
|
||||||
.field("longitude", longitude)
|
.field("longitude", longitude)
|
||||||
.field("rainbow_path", frogpilot_toggles.rainbow_path)
|
|
||||||
.field("random_events", frogpilot_toggles.random_events)
|
|
||||||
.field("state", state)
|
.field("state", state)
|
||||||
|
.field("stats", json.dumps(frogpilot_stats))
|
||||||
.field("theme", selected_theme.title())
|
.field("theme", selected_theme.title())
|
||||||
.field("total_aol_seconds", float(frogpilot_stats.get("AOLTime", 0)))
|
.field("toggles", json.dumps(frogpilot_toggles.__dict__))
|
||||||
.field("total_lateral_seconds", float(frogpilot_stats.get("LateralTime", 0)))
|
|
||||||
.field("total_longitudinal_seconds", float(frogpilot_stats.get("LongitudinalTime", 0)))
|
|
||||||
.field("total_stopped_seconds", float(frogpilot_stats.get("StandstillTime", 0)))
|
|
||||||
.field("total_tracked_seconds", float(frogpilot_stats.get("TrackedTime", 0)))
|
|
||||||
.field("tuning_level", params.get_int("TuningLevel") + 1 if params.get_bool("TuningLevelConfirmed") else 0)
|
.field("tuning_level", params.get_int("TuningLevel") + 1 if params.get_bool("TuningLevelConfirmed") else 0)
|
||||||
.field("using_default_model", params.get("Model", encoding="utf-8").endswith("_default"))
|
.field("using_default_model", params.get("Model", encoding="utf-8").endswith("_default"))
|
||||||
.field("using_stock_acc", not (frogpilot_toggles.has_cc_long or frogpilot_toggles.openpilot_longitudinal))
|
|
||||||
.tag("branch", build_metadata.channel)
|
.tag("branch", build_metadata.channel)
|
||||||
.tag("dongle_id", params.get("FrogPilotDongleId", encoding="utf-8"))
|
.tag("dongle_id", dongle_id)
|
||||||
.time(now)
|
.time(now)
|
||||||
)
|
)
|
||||||
|
|
||||||
all_points = [user_point] + update_branch_commits(now)
|
model_scores = json.loads(params.get("ModelDrivesAndScores") or "{}")
|
||||||
|
model_points = []
|
||||||
|
for model_name, data in sorted(model_scores.items()):
|
||||||
|
drives = data.get("Drives", 0)
|
||||||
|
score = data.get("Score", 0)
|
||||||
|
|
||||||
|
if drives > 0:
|
||||||
|
point = (
|
||||||
|
Point("model_scores")
|
||||||
|
.field("drives", int(drives))
|
||||||
|
.field("score", int(score))
|
||||||
|
.tag("dongle_id", dongle_id)
|
||||||
|
.tag("model_name", clean_model_name(model_name))
|
||||||
|
.time(now)
|
||||||
|
)
|
||||||
|
model_points.append(point)
|
||||||
|
|
||||||
|
all_points = model_points + [user_point] + update_branch_commits(now)
|
||||||
|
|
||||||
client = InfluxDBClient(org=org_ID, token=token, url=url)
|
client = InfluxDBClient(org=org_ID, token=token, url=url)
|
||||||
client.write_api(write_options=SYNCHRONOUS).write(bucket=bucket, org=org_ID, record=all_points)
|
client.write_api(write_options=SYNCHRONOUS).write(bucket=bucket, org=org_ID, record=all_points)
|
||||||
|
|||||||
@ -9,6 +9,7 @@ from datetime import datetime, timedelta, timezone
|
|||||||
|
|
||||||
from cereal import log, messaging
|
from cereal import log, messaging
|
||||||
|
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
from openpilot.frogpilot.common.frogpilot_utilities import calculate_distance_to_point, calculate_lane_width, is_url_pingable
|
from openpilot.frogpilot.common.frogpilot_utilities import calculate_distance_to_point, calculate_lane_width, is_url_pingable
|
||||||
from openpilot.frogpilot.common.frogpilot_variables import params, params_memory
|
from openpilot.frogpilot.common.frogpilot_variables import params, params_memory
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ class MapSpeedLogger:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def meters_to_deg_lon(meters, latitude):
|
def meters_to_deg_lon(meters, latitude):
|
||||||
return meters / (METERS_PER_DEG_LAT * math.cos(math.radians(latitude)))
|
return meters / (METERS_PER_DEG_LAT * math.cos(latitude * CV.DEG_TO_RAD))
|
||||||
|
|
||||||
def get_speed_limit_source(self):
|
def get_speed_limit_source(self):
|
||||||
sources = [
|
sources = [
|
||||||
@ -165,7 +166,7 @@ class MapSpeedLogger:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
def filter_segments_for_entry(self, entry):
|
def filter_segments_for_entry(self, entry):
|
||||||
bearing_rad = math.radians(entry["bearing"])
|
bearing_rad = entry["bearing"] * CV.DEG_TO_RAD
|
||||||
start_lat, start_lon = entry["start_coordinates"]["latitude"], entry["start_coordinates"]["longitude"]
|
start_lat, start_lon = entry["start_coordinates"]["latitude"], entry["start_coordinates"]["longitude"]
|
||||||
end_lat, end_lon = entry["end_coordinates"]["latitude"], entry["end_coordinates"]["longitude"]
|
end_lat, end_lon = entry["end_coordinates"]["latitude"], entry["end_coordinates"]["longitude"]
|
||||||
mid_lat = (start_lat + end_lat) / 2
|
mid_lat = (start_lat + end_lat) / 2
|
||||||
@ -229,10 +230,10 @@ class MapSpeedLogger:
|
|||||||
return
|
return
|
||||||
|
|
||||||
distance = calculate_distance_to_point(
|
distance = calculate_distance_to_point(
|
||||||
math.radians(self.previous_coordinates["latitude"]),
|
self.previous_coordinates["latitude"] * CV.DEG_TO_RAD,
|
||||||
math.radians(self.previous_coordinates["longitude"]),
|
self.previous_coordinates["longitude"] * CV.DEG_TO_RAD,
|
||||||
math.radians(current_latitude),
|
current_latitude * CV.DEG_TO_RAD,
|
||||||
math.radians(current_longitude)
|
current_longitude * CV.DEG_TO_RAD
|
||||||
)
|
)
|
||||||
if distance < 1:
|
if distance < 1:
|
||||||
return
|
return
|
||||||
@ -318,7 +319,6 @@ class MapSpeedLogger:
|
|||||||
|
|
||||||
self.update_params(dataset, filtered_dataset)
|
self.update_params(dataset, filtered_dataset)
|
||||||
params_memory.put("UpdateSpeedLimitsStatus", "Completed!")
|
params_memory.put("UpdateSpeedLimitsStatus", "Completed!")
|
||||||
params_memory.remove("UpdateSpeedLimits")
|
|
||||||
|
|
||||||
def update_cached_segments(self, latitude, longitude, vetting=False):
|
def update_cached_segments(self, latitude, longitude, vetting=False):
|
||||||
if not self.is_in_cached_box(latitude, longitude):
|
if not self.is_in_cached_box(latitude, longitude):
|
||||||
@ -398,6 +398,8 @@ def main():
|
|||||||
previously_started = False
|
previously_started = False
|
||||||
elif params_memory.get_bool("UpdateSpeedLimits"):
|
elif params_memory.get_bool("UpdateSpeedLimits"):
|
||||||
logger.process_speed_limits()
|
logger.process_speed_limits()
|
||||||
|
|
||||||
|
params_memory.remove("UpdateSpeedLimits")
|
||||||
else:
|
else:
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
|
|||||||
@ -236,7 +236,7 @@ export function NavDestination() {
|
|||||||
state.suggestions = "[]";
|
state.suggestions = "[]";
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to calculate route:", err);
|
console.error("Failed to calculate route:", err);
|
||||||
showSnackbar("Failed to calculate route…");
|
showSnackbar("Failed to calculate route...");
|
||||||
} finally {
|
} finally {
|
||||||
state.loadingRoute = false;
|
state.loadingRoute = false;
|
||||||
}
|
}
|
||||||
@ -433,7 +433,7 @@ export function NavDestination() {
|
|||||||
|
|
||||||
showSnackbar(`"${fav.name}" renamed to "${newName}"!`, "success");
|
showSnackbar(`"${fav.name}" renamed to "${newName}"!`, "success");
|
||||||
} catch {
|
} catch {
|
||||||
showSnackbar("Failed to edit favorite name…");
|
showSnackbar("Failed to edit favorite name...");
|
||||||
} finally {
|
} finally {
|
||||||
state.showRenameFavoriteModal = false;
|
state.showRenameFavoriteModal = false;
|
||||||
}
|
}
|
||||||
@ -771,7 +771,7 @@ function NavigationDestination({
|
|||||||
showSnackbar(message || "Added to favorites!");
|
showSnackbar(message || "Added to favorites!");
|
||||||
await loadFavorites();
|
await loadFavorites();
|
||||||
} catch {
|
} catch {
|
||||||
showSnackbar("Failed to add to favorites…");
|
showSnackbar("Failed to add to favorites...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function toggleFavorite() {
|
async function toggleFavorite() {
|
||||||
@ -782,7 +782,7 @@ function NavigationDestination({
|
|||||||
if (fav) {
|
if (fav) {
|
||||||
removeFavorite(fav);
|
removeFavorite(fav);
|
||||||
} else {
|
} else {
|
||||||
showSnackbar("Couldn't find favorite entry…");
|
showSnackbar("Couldn't find favorite entry...");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await favoriteDestination();
|
await favoriteDestination();
|
||||||
|
|||||||
@ -74,7 +74,6 @@ public:
|
|||||||
WifiManager *wifi;
|
WifiManager *wifi;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void reviewModel();
|
|
||||||
void themeUpdated();
|
void themeUpdated();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,10 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
|||||||
ScrollView *dataMainPanel = new ScrollView(dataMainList, this);
|
ScrollView *dataMainPanel = new ScrollView(dataMainList, this);
|
||||||
dataLayout->addWidget(dataMainPanel);
|
dataLayout->addWidget(dataMainPanel);
|
||||||
|
|
||||||
|
FrogPilotListWidget *statsLabelsList = new FrogPilotListWidget(this);
|
||||||
|
ScrollView *statsLabelsPanel = new ScrollView(statsLabelsList, this);
|
||||||
|
dataLayout->addWidget(statsLabelsPanel);
|
||||||
|
|
||||||
ButtonControl *deleteDrivingDataButton = new ButtonControl(tr("Delete Driving Data"), tr("DELETE"), tr("<b>Delete all stored driving footage and data</b> to free up space and clear private information."));
|
ButtonControl *deleteDrivingDataButton = new ButtonControl(tr("Delete Driving Data"), tr("DELETE"), tr("<b>Delete all stored driving footage and data</b> to free up space and clear private information."));
|
||||||
QObject::connect(deleteDrivingDataButton, &ButtonControl::clicked, [=]() {
|
QObject::connect(deleteDrivingDataButton, &ButtonControl::clicked, [=]() {
|
||||||
QDir hdDataDir("/data/media/0/realdata_HD/");
|
QDir hdDataDir("/data/media/0/realdata_HD/");
|
||||||
@ -594,4 +598,245 @@ FrogPilotDataPanel::FrogPilotDataPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
|||||||
toggleBackupButton->showDescription();
|
toggleBackupButton->showDescription();
|
||||||
}
|
}
|
||||||
dataMainList->addItem(toggleBackupButton);
|
dataMainList->addItem(toggleBackupButton);
|
||||||
|
|
||||||
|
FrogPilotButtonsControl *viewStatsButton = new FrogPilotButtonsControl(tr("FrogPilot Stats"), tr("<b>View your collected FrogPilot stats.</b>"), "", {tr("RESET"), tr("VIEW")});
|
||||||
|
QObject::connect(viewStatsButton, &FrogPilotButtonsControl::buttonClicked, [dataLayout, statsLabelsPanel, this](int id) {
|
||||||
|
if (id == 0) {
|
||||||
|
if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all of your FrogPilot stats?"), tr("Reset"), this)) {
|
||||||
|
params.remove("FrogPilotStats");
|
||||||
|
params_cache.remove("FrogPilotStats");
|
||||||
|
}
|
||||||
|
} else if (id == 1) {
|
||||||
|
emit openSubPanel();
|
||||||
|
dataLayout->setCurrentWidget(statsLabelsPanel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (forceOpenDescriptions) {
|
||||||
|
viewStatsButton->showDescription();
|
||||||
|
}
|
||||||
|
dataMainList->addItem(viewStatsButton);
|
||||||
|
|
||||||
|
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [dataLayout, dataMainPanel] {
|
||||||
|
dataLayout->setCurrentWidget(dataMainPanel);
|
||||||
|
});
|
||||||
|
QObject::connect(parent, &FrogPilotSettingsWindow::updateMetric, [this](bool metric){isMetric = metric;});
|
||||||
|
QObject::connect(uiState(), &UIState::offroadTransition, [statsLabelsList, this](bool offroad) {
|
||||||
|
if (offroad) {
|
||||||
|
updateStatsLabels(statsLabelsList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
updateStatsLabels(statsLabelsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotDataPanel::updateStatsLabels(FrogPilotListWidget *labelsList) {
|
||||||
|
labelsList->clear();
|
||||||
|
|
||||||
|
QJsonObject stats = QJsonDocument::fromJson(QString::fromStdString(params.get("FrogPilotStats")).toUtf8()).object();
|
||||||
|
|
||||||
|
static QSet<QString> ignored_keys = {
|
||||||
|
"Month"
|
||||||
|
};
|
||||||
|
|
||||||
|
static QMap<QString, QPair<QString, QString>> key_map = {
|
||||||
|
{"AEBEvents", {tr("Total Emergency Brake Alerts"), "count"}},
|
||||||
|
{"AOLTime", {tr("Time Using \"Always On Lateral\""), "time"}},
|
||||||
|
{"CruiseSpeedTimes", {tr("Favorite Set Speed"), "speed"}},
|
||||||
|
{"Disengages", {tr("Total Disengagements"), "count"}},
|
||||||
|
{"Engages", {tr("Total Engagements"), "count"}},
|
||||||
|
{"ExperimentalModeTime", {tr("Time Using \"Experimental Mode\""), "time"}},
|
||||||
|
{"FrogChirps", {tr("Total Frog Chirps"), "count"}},
|
||||||
|
{"FrogHops", {tr("Total Frog Hops"), "count"}},
|
||||||
|
{"FrogPilotDrives", {tr("Total Drives"), "count"}},
|
||||||
|
{"FrogPilotMeters", {tr("Total Distance Driven"), "distance"}},
|
||||||
|
{"FrogPilotSeconds", {tr("Total Driving Time"), "time"}},
|
||||||
|
{"FrogSqueaks", {tr("Total Frog Squeaks"), "count"}},
|
||||||
|
{"GoatScreams", {tr("Total Goat Screams"), "count"}},
|
||||||
|
{"HighestAcceleration", {tr("Highest Acceleration Rate"), "accel"}},
|
||||||
|
{"LateralTime", {tr("Time Using Lateral Control"), "time"}},
|
||||||
|
{"LongestDistanceWithoutOverride", {tr("Longest Distance Without an Override"), "distance"}},
|
||||||
|
{"LongitudinalTime", {tr("Time Using Longitudinal Control"), "time"}},
|
||||||
|
{"ModelTimes", {tr("Driving Models:"), "other"}},
|
||||||
|
{"Month", {tr("Month"), "other"}},
|
||||||
|
{"Overrides", {tr("Total Overrides"), "count"}},
|
||||||
|
{"OverrideTime", {tr("Time Overriding openpilot"), "time"}},
|
||||||
|
{"RandomEvents", {tr("Random Events:"), "other"}},
|
||||||
|
{"StandstillTime", {tr("Time Stopped"), "time"}},
|
||||||
|
{"StopLightTime", {tr("Time Spent at Stoplights"), "time"}},
|
||||||
|
{"TrackedTime", {tr("Total Time Tracked"), "time"}}
|
||||||
|
};
|
||||||
|
|
||||||
|
static QSet<QString> parent_keys = {
|
||||||
|
"ModelTimes",
|
||||||
|
"RandomEvents"
|
||||||
|
};
|
||||||
|
|
||||||
|
static QSet<QString> percentage_keys = {
|
||||||
|
"AOLTime",
|
||||||
|
"ExperimentalModeTime",
|
||||||
|
"LateralTime",
|
||||||
|
"LongitudinalTime",
|
||||||
|
"OverrideTime",
|
||||||
|
"StandstillTime",
|
||||||
|
"StopLightTime"
|
||||||
|
};
|
||||||
|
|
||||||
|
static QMap<QString, QString> random_events_map = {
|
||||||
|
{"accel30", tr("UwUs")},
|
||||||
|
{"accel35", tr("Loch Ness Encounters")},
|
||||||
|
{"accel40", tr("Visits to 1955")},
|
||||||
|
{"dejaVuCurve", tr("Deja Vu Moments")},
|
||||||
|
{"firefoxSteerSaturated", tr("Internet Explorer Weeeeeeees")},
|
||||||
|
{"hal9000", tr("HAL 9000 Denials")},
|
||||||
|
{"openpilotCrashedRandomEvent", tr("openpilot Crashes")},
|
||||||
|
{"thisIsFineSteerSaturated", tr("This Is Fine Moments")},
|
||||||
|
{"toBeContinued", tr("To Be Continued Moments")},
|
||||||
|
{"vCruise69", tr("Noices")},
|
||||||
|
{"yourFrogTriedToKillMe", tr("Attempted Frog Murders")},
|
||||||
|
{"youveGotMail", tr("Total Mail Received")}
|
||||||
|
};
|
||||||
|
|
||||||
|
QStringList keys = key_map.keys();
|
||||||
|
std::sort(keys.begin(), keys.end(), [&](const QString &a, const QString &b) {
|
||||||
|
return key_map.value(a).first.toLower() < key_map.value(b).first.toLower();
|
||||||
|
});
|
||||||
|
|
||||||
|
double tracked_time = stats.contains("TrackedTime") ? stats.value("TrackedTime").toDouble() : 0.0;
|
||||||
|
|
||||||
|
std::function<QString(double)> format_number = [&](double number) {
|
||||||
|
return QLocale().toString(number);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<QString(double)> format_distance = [&](double meters) {
|
||||||
|
double value;
|
||||||
|
QString unit;
|
||||||
|
if (isMetric) {
|
||||||
|
value = meters / 1000.0;
|
||||||
|
unit = (value == 1.0) ? tr(" kilometer") : tr(" kilometers");
|
||||||
|
} else {
|
||||||
|
value = meters * METER_TO_MILE;
|
||||||
|
unit = (value == 1.0) ? tr(" mile") : tr(" miles");
|
||||||
|
}
|
||||||
|
return format_number(qRound(value)) + unit;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<QString(int)> format_time = [&](int seconds) {
|
||||||
|
static int seconds_in_day = 60 * 60 * 24;
|
||||||
|
static int seconds_in_hour = 60 * 60;
|
||||||
|
|
||||||
|
int days = seconds / seconds_in_day;
|
||||||
|
int hours = (seconds % seconds_in_day) / seconds_in_hour;
|
||||||
|
int minutes = (seconds % seconds_in_hour) / 60;
|
||||||
|
|
||||||
|
QString result;
|
||||||
|
if (days > 0) result += format_number(days) + (days == 1 ? tr(" day ") : tr(" days "));
|
||||||
|
if (hours > 0 || days > 0) result += format_number(hours) + (hours == 1 ? tr(" hour ") : tr(" hours "));
|
||||||
|
result += format_number(minutes) + (minutes == 1 ? tr(" minute") : tr(" minutes"));
|
||||||
|
return result.trimmed();
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const QString &key : keys) {
|
||||||
|
if (ignored_keys.contains(key)) continue;
|
||||||
|
|
||||||
|
QJsonValue value = stats.contains(key) ? stats.value(key) : QJsonValue(0);
|
||||||
|
QString label_text = key_map.value(key).first;
|
||||||
|
QString type = key_map.value(key).second;
|
||||||
|
|
||||||
|
if (key == "CruiseSpeedTimes" && value.isObject()) {
|
||||||
|
QJsonObject speeds = value.toObject();
|
||||||
|
|
||||||
|
double max_time = -1.0;
|
||||||
|
QString best_speed;
|
||||||
|
for (QJsonObject::const_iterator it = speeds.begin(); it != speeds.end(); ++it) {
|
||||||
|
double time = it.value().toDouble();
|
||||||
|
if (time > max_time) {
|
||||||
|
best_speed = it.key();
|
||||||
|
max_time = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString display_speed;
|
||||||
|
if (isMetric) {
|
||||||
|
display_speed = QString::number(qRound(best_speed.toDouble() * MS_TO_KPH)) + " " + tr("km/h");
|
||||||
|
} else {
|
||||||
|
display_speed = QString::number(qRound(best_speed.toDouble() * MS_TO_MPH)) + " " + tr("mph");
|
||||||
|
}
|
||||||
|
|
||||||
|
labelsList->addItem(new LabelControl(label_text, display_speed + " (" + format_time(max_time) + ")", "", this));
|
||||||
|
} else if (parent_keys.contains(key) && value.isObject()) {
|
||||||
|
labelsList->addItem(new LabelControl(label_text, "", "", this));
|
||||||
|
|
||||||
|
QJsonObject subobj = value.toObject();
|
||||||
|
QStringList subkeys;
|
||||||
|
|
||||||
|
if (key == "RandomEvents") {
|
||||||
|
subkeys = random_events_map.keys();
|
||||||
|
} else {
|
||||||
|
subkeys = subobj.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(subkeys.begin(), subkeys.end(), [&](const QString &a, const QString &b) {
|
||||||
|
QString display_a, display_b;
|
||||||
|
if (key == "ModelTimes") {
|
||||||
|
display_a = processModelName(a);
|
||||||
|
display_b = processModelName(b);
|
||||||
|
} else if (key == "RandomEvents") {
|
||||||
|
display_a = random_events_map.value(a, a);
|
||||||
|
display_b = random_events_map.value(b, b);
|
||||||
|
} else {
|
||||||
|
display_a = a;
|
||||||
|
display_b = b;
|
||||||
|
}
|
||||||
|
return display_a.toLower() < display_b.toLower();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const QString &subkey : subkeys) {
|
||||||
|
QString display_subkey;
|
||||||
|
if (key == "ModelTimes") {
|
||||||
|
display_subkey = processModelName(subkey);
|
||||||
|
} else if (key == "RandomEvents") {
|
||||||
|
display_subkey = random_events_map.value(subkey, subkey);
|
||||||
|
} else {
|
||||||
|
display_subkey = subkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString subvalue;
|
||||||
|
if (key == "ModelTimes") {
|
||||||
|
subvalue = format_time(subobj.value(subkey).toDouble());
|
||||||
|
} else {
|
||||||
|
subvalue = subobj.value(subkey).toVariant().toString().isEmpty() ? "0" : format_number(subobj.value(subkey).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
labelsList->addItem(new LabelControl(" " + display_subkey, subvalue, "", this));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QString display_value;
|
||||||
|
if (type == "accel") {
|
||||||
|
display_value = QString::number(value.toDouble(), 'f', 2) + " " + tr("m/s²");
|
||||||
|
} else if (type == "count") {
|
||||||
|
QString trimmed_label = label_text;
|
||||||
|
if (trimmed_label.startsWith(tr("Total "))) {
|
||||||
|
trimmed_label = trimmed_label.mid(6);
|
||||||
|
}
|
||||||
|
display_value = format_number(value.toInt()) + " " + trimmed_label;
|
||||||
|
} else if (type == "distance") {
|
||||||
|
display_value = format_distance(value.toDouble());
|
||||||
|
} else if (type == "time") {
|
||||||
|
display_value = format_time(value.toDouble());
|
||||||
|
} else {
|
||||||
|
display_value = value.toVariant().toString().isEmpty() ? "0" : value.toVariant().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
labelsList->addItem(new LabelControl(label_text, display_value, "", this));
|
||||||
|
|
||||||
|
if (percentage_keys.contains(key)) {
|
||||||
|
int percent = 0;
|
||||||
|
if (tracked_time > 0.0) {
|
||||||
|
percent = (value.toDouble() * 100.0) / tracked_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
labelsList->addItem(new LabelControl(tr("% of ") + label_text, format_number(percent) + "%", "", this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,16 @@ class FrogPilotDataPanel : public FrogPilotListWidget {
|
|||||||
public:
|
public:
|
||||||
explicit FrogPilotDataPanel(FrogPilotSettingsWindow *parent);
|
explicit FrogPilotDataPanel(FrogPilotSettingsWindow *parent);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void openSubPanel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void updateStatsLabels(FrogPilotListWidget *labelsList);
|
||||||
|
|
||||||
|
bool isMetric;
|
||||||
|
|
||||||
FrogPilotSettingsWindow *parent;
|
FrogPilotSettingsWindow *parent;
|
||||||
|
|
||||||
Params params;
|
Params params;
|
||||||
|
Params params_cache{"/cache/params"};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -15,24 +15,55 @@
|
|||||||
|
|
||||||
bool nnffLogFileExists(const QString &carFingerprint) {
|
bool nnffLogFileExists(const QString &carFingerprint) {
|
||||||
static QStringList files;
|
static QStringList files;
|
||||||
|
static QMap<QString, QString> substitutes;
|
||||||
|
|
||||||
if (files.isEmpty()) {
|
if (files.isEmpty()) {
|
||||||
QFileInfoList fileInfoList = QDir(QStringLiteral("../../frogpilot/assets/nnff_models")).entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
|
QFileInfoList fileInfoList = QDir(QStringLiteral("../../frogpilot/assets/nnff_models")).entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
|
||||||
for (const QFileInfo &fileInfo : fileInfoList) {
|
for (const QFileInfo &fileInfo : fileInfoList) {
|
||||||
files.append(fileInfo.completeBaseName());
|
files.append(fileInfo.completeBaseName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFile sub_file(QStringLiteral("../../selfdrive/car/torque_data/substitute.toml"));
|
||||||
|
if (sub_file.open(QIODevice::ReadOnly)) {
|
||||||
|
QTextStream in(&sub_file);
|
||||||
|
while (!in.atEnd()) {
|
||||||
|
QString line = in.readLine().trimmed();
|
||||||
|
if (line.startsWith("#") || line.startsWith("legend") || !line.contains("=")) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList parts = line.split("=");
|
||||||
|
if (parts.size() == 2) {
|
||||||
|
QString key = parts[0].trimmed().remove('"');
|
||||||
|
QString value = parts[1].trimmed().remove('"');
|
||||||
|
if (!key.isEmpty() && !value.isEmpty()) {
|
||||||
|
substitutes[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList fingerprintsToCheck;
|
||||||
|
fingerprintsToCheck.append(carFingerprint);
|
||||||
|
if (substitutes.contains(carFingerprint)) {
|
||||||
|
fingerprintsToCheck.append(substitutes.value(carFingerprint));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const QString &fingerprint : fingerprintsToCheck) {
|
||||||
for (const QString &file : files) {
|
for (const QString &file : files) {
|
||||||
if (file.startsWith(carFingerprint)) {
|
if (file.startsWith(fingerprint)) {
|
||||||
std::cout << "NNFF supports fingerprint: " << file.toStdString() << std::endl;
|
std::cout << "NNFF model found for fingerprint: " << fingerprint.toStdString() << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrogPilotSettingsWindow::createPanelButtons(FrogPilotListWidget *list) {
|
void FrogPilotSettingsWindow::createPanelButtons(FrogPilotListWidget *list) {
|
||||||
|
FrogPilotDataPanel *frogpilotDataPanel = new FrogPilotDataPanel(this);
|
||||||
FrogPilotDevicePanel *frogpilotDevicePanel = new FrogPilotDevicePanel(this);
|
FrogPilotDevicePanel *frogpilotDevicePanel = new FrogPilotDevicePanel(this);
|
||||||
FrogPilotLateralPanel *frogpilotLateralPanel = new FrogPilotLateralPanel(this);
|
FrogPilotLateralPanel *frogpilotLateralPanel = new FrogPilotLateralPanel(this);
|
||||||
FrogPilotLongitudinalPanel *frogpilotLongitudinalPanel = new FrogPilotLongitudinalPanel(this);
|
FrogPilotLongitudinalPanel *frogpilotLongitudinalPanel = new FrogPilotLongitudinalPanel(this);
|
||||||
@ -49,7 +80,7 @@ void FrogPilotSettingsWindow::createPanelButtons(FrogPilotListWidget *list) {
|
|||||||
{{tr("MANAGE"), frogpilotSoundsPanel}},
|
{{tr("MANAGE"), frogpilotSoundsPanel}},
|
||||||
{{tr("DRIVING MODEL"), frogpilotModelPanel}, {tr("GAS / BRAKE"), frogpilotLongitudinalPanel}, {tr("STEERING"), frogpilotLateralPanel}},
|
{{tr("DRIVING MODEL"), frogpilotModelPanel}, {tr("GAS / BRAKE"), frogpilotLongitudinalPanel}, {tr("STEERING"), frogpilotLateralPanel}},
|
||||||
{{tr("MAP DATA"), frogpilotMapsPanel}, {tr("NAVIGATION"), frogpilotNavigationPanel}},
|
{{tr("MAP DATA"), frogpilotMapsPanel}, {tr("NAVIGATION"), frogpilotNavigationPanel}},
|
||||||
{{tr("DATA"), new FrogPilotDataPanel(this)}, {tr("DEVICE CONTROLS"), frogpilotDevicePanel}, {tr("UTILITIES"), new FrogPilotUtilitiesPanel(this)}},
|
{{tr("DATA"), frogpilotDataPanel}, {tr("DEVICE CONTROLS"), frogpilotDevicePanel}, {tr("UTILITIES"), new FrogPilotUtilitiesPanel(this)}},
|
||||||
{{tr("APPEARANCE"), frogpilotVisualsPanel}, {tr("THEME"), frogpilotThemesPanel}},
|
{{tr("APPEARANCE"), frogpilotVisualsPanel}, {tr("THEME"), frogpilotThemesPanel}},
|
||||||
{{tr("VEHICLE SETTINGS"), frogpilotVehiclesPanel}, {tr("WHEEL CONTROLS"), frogpilotWheelPanel}}
|
{{tr("VEHICLE SETTINGS"), frogpilotVehiclesPanel}, {tr("WHEEL CONTROLS"), frogpilotWheelPanel}}
|
||||||
};
|
};
|
||||||
@ -107,10 +138,12 @@ void FrogPilotSettingsWindow::createPanelButtons(FrogPilotListWidget *list) {
|
|||||||
list->addItem(panelButton);
|
list->addItem(panelButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QObject::connect(frogpilotDataPanel, &FrogPilotDataPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||||
QObject::connect(frogpilotDevicePanel, &FrogPilotDevicePanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
QObject::connect(frogpilotDevicePanel, &FrogPilotDevicePanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||||
QObject::connect(frogpilotLateralPanel, &FrogPilotLateralPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
QObject::connect(frogpilotLateralPanel, &FrogPilotLateralPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||||
QObject::connect(frogpilotLongitudinalPanel, &FrogPilotLongitudinalPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
QObject::connect(frogpilotLongitudinalPanel, &FrogPilotLongitudinalPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||||
QObject::connect(frogpilotLongitudinalPanel, &FrogPilotLongitudinalPanel::openSubSubPanel, this, &FrogPilotSettingsWindow::openSubSubPanel);
|
QObject::connect(frogpilotLongitudinalPanel, &FrogPilotLongitudinalPanel::openSubSubPanel, this, &FrogPilotSettingsWindow::openSubSubPanel);
|
||||||
|
QObject::connect(frogpilotLongitudinalPanel, &FrogPilotLongitudinalPanel::openSubSubSubPanel, this, &FrogPilotSettingsWindow::openSubSubSubPanel);
|
||||||
QObject::connect(frogpilotMapsPanel, &FrogPilotMapsPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
QObject::connect(frogpilotMapsPanel, &FrogPilotMapsPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||||
QObject::connect(frogpilotModelPanel, &FrogPilotModelPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
QObject::connect(frogpilotModelPanel, &FrogPilotModelPanel::openSubPanel, this, &FrogPilotSettingsWindow::openSubPanel);
|
||||||
QObject::connect(frogpilotNavigationPanel, &FrogPilotNavigationPanel::closeSubPanel, this, &FrogPilotSettingsWindow::closeSubPanel);
|
QObject::connect(frogpilotNavigationPanel, &FrogPilotNavigationPanel::closeSubPanel, this, &FrogPilotSettingsWindow::closeSubPanel);
|
||||||
@ -176,6 +209,7 @@ FrogPilotSettingsWindow::FrogPilotSettingsWindow(SettingsWindow *parent) : QFram
|
|||||||
QObject::connect(parent, &SettingsWindow::closePanel, this, &FrogPilotSettingsWindow::closePanel);
|
QObject::connect(parent, &SettingsWindow::closePanel, this, &FrogPilotSettingsWindow::closePanel);
|
||||||
QObject::connect(parent, &SettingsWindow::closeSubPanel, this, &FrogPilotSettingsWindow::closeSubPanel);
|
QObject::connect(parent, &SettingsWindow::closeSubPanel, this, &FrogPilotSettingsWindow::closeSubPanel);
|
||||||
QObject::connect(parent, &SettingsWindow::closeSubSubPanel, this, &FrogPilotSettingsWindow::closeSubSubPanel);
|
QObject::connect(parent, &SettingsWindow::closeSubSubPanel, this, &FrogPilotSettingsWindow::closeSubSubPanel);
|
||||||
|
QObject::connect(parent, &SettingsWindow::closeSubSubSubPanel, this, &FrogPilotSettingsWindow::closeSubSubSubPanel);
|
||||||
QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotSettingsWindow::updateMetric);
|
QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotSettingsWindow::updateMetric);
|
||||||
QObject::connect(parent, &SettingsWindow::updateTuningLevel, this, &FrogPilotSettingsWindow::updateTuningLevel);
|
QObject::connect(parent, &SettingsWindow::updateTuningLevel, this, &FrogPilotSettingsWindow::updateTuningLevel);
|
||||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &FrogPilotSettingsWindow::updateVariables);
|
QObject::connect(uiState(), &UIState::offroadTransition, this, &FrogPilotSettingsWindow::updateVariables);
|
||||||
@ -270,13 +304,15 @@ void FrogPilotSettingsWindow::updateVariables() {
|
|||||||
hasPedal = CP.getEnableGasInterceptor();
|
hasPedal = CP.getEnableGasInterceptor();
|
||||||
hasRadar = !CP.getRadarUnavailable();
|
hasRadar = !CP.getRadarUnavailable();
|
||||||
hasSDSU = frogpilot_toggles.value("has_sdsu").toBool();
|
hasSDSU = frogpilot_toggles.value("has_sdsu").toBool();
|
||||||
hasSNG = hasOpenpilotLongitudinal && CP.getAutoResumeSng();
|
hasSNG = CP.getAutoResumeSng();
|
||||||
hasZSS = frogpilot_toggles.value("has_zss").toBool();
|
hasZSS = frogpilot_toggles.value("has_zss").toBool();
|
||||||
isAngleCar = CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE;
|
isAngleCar = CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE;
|
||||||
isBolt = carFingerprint == "CHEVROLET_BOLT_CC" || carFingerprint == "CHEVROLET_BOLT_EUV";
|
isBolt = carFingerprint == "CHEVROLET_BOLT_CC" || carFingerprint == "CHEVROLET_BOLT_EUV";
|
||||||
isGM = carMake == "gm";
|
isGM = carMake == "gm";
|
||||||
isHKG = carMake == "hyundai";
|
isHKG = carMake == "hyundai";
|
||||||
isHKGCanFd = isHKG && safetyModel == cereal::CarParams::SafetyModel::HYUNDAI_CANFD;
|
isHKGCanFd = isHKG && safetyModel == cereal::CarParams::SafetyModel::HYUNDAI_CANFD;
|
||||||
|
isHonda = carMake == "honda";
|
||||||
|
isHondaNidec = isHonda && safetyModel == cereal::CarParams::SafetyModel::HONDA_NIDEC;
|
||||||
isSubaru = carMake == "subaru";
|
isSubaru = carMake == "subaru";
|
||||||
isTorqueCar = CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::TORQUE;
|
isTorqueCar = CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::TORQUE;
|
||||||
isToyota = carMake == "toyota";
|
isToyota = carMake == "toyota";
|
||||||
@ -286,7 +322,7 @@ void FrogPilotSettingsWindow::updateVariables() {
|
|||||||
longitudinalActuatorDelay = CP.getLongitudinalActuatorDelay();
|
longitudinalActuatorDelay = CP.getLongitudinalActuatorDelay();
|
||||||
startAccel = CP.getStartAccel();
|
startAccel = CP.getStartAccel();
|
||||||
steerActuatorDelay = CP.getSteerActuatorDelay();
|
steerActuatorDelay = CP.getSteerActuatorDelay();
|
||||||
steerKp = CP.getLateralTuning().getTorque().getKp();
|
steerKp = 1.0;
|
||||||
steerRatio = CP.getSteerRatio();
|
steerRatio = CP.getSteerRatio();
|
||||||
stopAccel = CP.getStopAccel();
|
stopAccel = CP.getStopAccel();
|
||||||
stoppingDecelRate = CP.getStoppingDecelRate();
|
stoppingDecelRate = CP.getStoppingDecelRate();
|
||||||
|
|||||||
@ -1,8 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "selfdrive/ui/qt/offroad/settings.h"
|
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||||
|
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
|
||||||
class FrogPilotSettingsWindow : public QFrame {
|
class FrogPilotSettingsWindow : public QFrame {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -32,6 +38,8 @@ public:
|
|||||||
bool isGM = true;
|
bool isGM = true;
|
||||||
bool isHKG = true;
|
bool isHKG = true;
|
||||||
bool isHKGCanFd = true;
|
bool isHKGCanFd = true;
|
||||||
|
bool isHonda = true;
|
||||||
|
bool isHondaNidec = true;
|
||||||
bool isSubaru = false;
|
bool isSubaru = false;
|
||||||
bool isTorqueCar = false;
|
bool isTorqueCar = false;
|
||||||
bool isToyota = true;
|
bool isToyota = true;
|
||||||
@ -59,9 +67,11 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void closeSubPanel();
|
void closeSubPanel();
|
||||||
void closeSubSubPanel();
|
void closeSubSubPanel();
|
||||||
|
void closeSubSubSubPanel();
|
||||||
void openPanel();
|
void openPanel();
|
||||||
void openSubPanel();
|
void openSubPanel();
|
||||||
void openSubSubPanel();
|
void openSubSubPanel();
|
||||||
|
void openSubSubSubPanel();
|
||||||
void updateMetric(bool metric, bool bootRun=false);
|
void updateMetric(bool metric, bool bootRun=false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -365,7 +365,7 @@ void FrogPilotLateralPanel::updateToggles() {
|
|||||||
else if (key == "ForceAutoTune") {
|
else if (key == "ForceAutoTune") {
|
||||||
setVisible &= !parent->hasAutoTune;
|
setVisible &= !parent->hasAutoTune;
|
||||||
setVisible &= !parent->isAngleCar;
|
setVisible &= !parent->isAngleCar;
|
||||||
setVisible &= parent->isTorqueCar || forcingTorqueController;
|
setVisible &= parent->isTorqueCar || forcingTorqueController || usingNNFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (key == "ForceAutoTuneOff") {
|
else if (key == "ForceAutoTuneOff") {
|
||||||
@ -402,20 +402,20 @@ void FrogPilotLateralPanel::updateToggles() {
|
|||||||
else if (key == "SteerFriction") {
|
else if (key == "SteerFriction") {
|
||||||
setVisible &= parent->friction != 0;
|
setVisible &= parent->friction != 0;
|
||||||
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
||||||
setVisible &= parent->isTorqueCar || forcingTorqueController;
|
setVisible &= parent->isTorqueCar || forcingTorqueController || usingNNFF;
|
||||||
setVisible &= !usingNNFF;
|
setVisible &= !usingNNFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (key == "SteerKP") {
|
else if (key == "SteerKP") {
|
||||||
setVisible &= parent->steerKp != 0;
|
setVisible &= parent->steerKp != 0;
|
||||||
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
setVisible &= parent->isTorqueCar || forcingTorqueController || usingNNFF;
|
||||||
setVisible &= parent->isTorqueCar || forcingTorqueController;
|
setVisible &= !parent->isAngleCar;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (key == "SteerLatAccel") {
|
else if (key == "SteerLatAccel") {
|
||||||
setVisible &= parent->latAccelFactor != 0;
|
setVisible &= parent->latAccelFactor != 0;
|
||||||
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
||||||
setVisible &= parent->isTorqueCar || forcingTorqueController;
|
setVisible &= parent->isTorqueCar || forcingTorqueController || usingNNFF;
|
||||||
setVisible &= !usingNNFF;
|
setVisible &= !usingNNFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#include "frogpilot/ui/qt/offroad/longitudinal_settings.h"
|
#include "frogpilot/ui/qt/offroad/longitudinal_settings.h"
|
||||||
|
|
||||||
FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||||
|
networkManager = new QNetworkAccessManager(this);
|
||||||
|
|
||||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||||
QString className = this->metaObject()->className();
|
QString className = this->metaObject()->className();
|
||||||
|
|
||||||
@ -33,6 +35,11 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
|||||||
FrogPilotListWidget *speedLimitControllerVisualList = new FrogPilotListWidget(this);
|
FrogPilotListWidget *speedLimitControllerVisualList = new FrogPilotListWidget(this);
|
||||||
FrogPilotListWidget *standardPersonalityList = new FrogPilotListWidget(this);
|
FrogPilotListWidget *standardPersonalityList = new FrogPilotListWidget(this);
|
||||||
FrogPilotListWidget *trafficPersonalityList = new FrogPilotListWidget(this);
|
FrogPilotListWidget *trafficPersonalityList = new FrogPilotListWidget(this);
|
||||||
|
FrogPilotListWidget *weatherList = new FrogPilotListWidget(this);
|
||||||
|
FrogPilotListWidget *weatherLowVisibilityList = new FrogPilotListWidget(this);
|
||||||
|
FrogPilotListWidget *weatherRainList = new FrogPilotListWidget(this);
|
||||||
|
FrogPilotListWidget *weatherRainStormList = new FrogPilotListWidget(this);
|
||||||
|
FrogPilotListWidget *weatherSnowList = new FrogPilotListWidget(this);
|
||||||
|
|
||||||
ScrollView *advancedLongitudinalTunePanel = new ScrollView(advancedLongitudinalTuneList, this);
|
ScrollView *advancedLongitudinalTunePanel = new ScrollView(advancedLongitudinalTuneList, this);
|
||||||
ScrollView *aggressivePersonalityPanel = new ScrollView(aggressivePersonalityList, this);
|
ScrollView *aggressivePersonalityPanel = new ScrollView(aggressivePersonalityList, this);
|
||||||
@ -48,6 +55,11 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
|||||||
ScrollView *speedLimitControllerVisualPanel = new ScrollView(speedLimitControllerVisualList, this);
|
ScrollView *speedLimitControllerVisualPanel = new ScrollView(speedLimitControllerVisualList, this);
|
||||||
ScrollView *standardPersonalityPanel = new ScrollView(standardPersonalityList, this);
|
ScrollView *standardPersonalityPanel = new ScrollView(standardPersonalityList, this);
|
||||||
ScrollView *trafficPersonalityPanel = new ScrollView(trafficPersonalityList, this);
|
ScrollView *trafficPersonalityPanel = new ScrollView(trafficPersonalityList, this);
|
||||||
|
ScrollView *weatherLowVisibilityPanel = new ScrollView(weatherLowVisibilityList, this);
|
||||||
|
ScrollView *weatherPanel = new ScrollView(weatherList, this);
|
||||||
|
ScrollView *weatherRainPanel = new ScrollView(weatherRainList, this);
|
||||||
|
ScrollView *weatherRainStormPanel = new ScrollView(weatherRainStormList, this);
|
||||||
|
ScrollView *weatherSnowPanel = new ScrollView(weatherSnowList, this);
|
||||||
|
|
||||||
longitudinalLayout->addWidget(advancedLongitudinalTunePanel);
|
longitudinalLayout->addWidget(advancedLongitudinalTunePanel);
|
||||||
longitudinalLayout->addWidget(aggressivePersonalityPanel);
|
longitudinalLayout->addWidget(aggressivePersonalityPanel);
|
||||||
@ -63,6 +75,11 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
|||||||
longitudinalLayout->addWidget(speedLimitControllerVisualPanel);
|
longitudinalLayout->addWidget(speedLimitControllerVisualPanel);
|
||||||
longitudinalLayout->addWidget(standardPersonalityPanel);
|
longitudinalLayout->addWidget(standardPersonalityPanel);
|
||||||
longitudinalLayout->addWidget(trafficPersonalityPanel);
|
longitudinalLayout->addWidget(trafficPersonalityPanel);
|
||||||
|
longitudinalLayout->addWidget(weatherLowVisibilityPanel);
|
||||||
|
longitudinalLayout->addWidget(weatherPanel);
|
||||||
|
longitudinalLayout->addWidget(weatherRainPanel);
|
||||||
|
longitudinalLayout->addWidget(weatherRainStormPanel);
|
||||||
|
longitudinalLayout->addWidget(weatherSnowPanel);
|
||||||
|
|
||||||
const std::vector<std::tuple<QString, QString, QString, QString>> longitudinalToggles {
|
const std::vector<std::tuple<QString, QString, QString, QString>> longitudinalToggles {
|
||||||
{"AdvancedLongitudinalTune", tr("Advanced Longitudinal Tuning"), tr("<b>Advanced acceleration and braking control changes</b> to fine-tune how openpilot drives."), "../../frogpilot/assets/toggle_icons/icon_advanced_longitudinal_tune.png"},
|
{"AdvancedLongitudinalTune", tr("Advanced Longitudinal Tuning"), tr("<b>Advanced acceleration and braking control changes</b> to fine-tune how openpilot drives."), "../../frogpilot/assets/toggle_icons/icon_advanced_longitudinal_tune.png"},
|
||||||
@ -77,9 +94,10 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
|||||||
{"ConditionalExperimental", tr("Conditional Experimental Mode"), tr("<b>Automatically switch to \"Experimental Mode\" when set conditions are met.</b> Allows the model to handle challenging situations with smarter decision making."), "../../frogpilot/assets/toggle_icons/icon_conditional.png"},
|
{"ConditionalExperimental", tr("Conditional Experimental Mode"), tr("<b>Automatically switch to \"Experimental Mode\" when set conditions are met.</b> Allows the model to handle challenging situations with smarter decision making."), "../../frogpilot/assets/toggle_icons/icon_conditional.png"},
|
||||||
{"CESpeed", tr("Below"), tr("<b>Switch to \"Experimental Mode\" when driving below this speed without a lead</b> to help openpilot handle low-speed situations more smoothly."), ""},
|
{"CESpeed", tr("Below"), tr("<b>Switch to \"Experimental Mode\" when driving below this speed without a lead</b> to help openpilot handle low-speed situations more smoothly."), ""},
|
||||||
{"CECurves", tr("Curve Detected Ahead"), tr("<b>Switch to \"Experimental Mode\" when a curve is detected</b> to allow the model to set an appropriate speed for the curve."), ""},
|
{"CECurves", tr("Curve Detected Ahead"), tr("<b>Switch to \"Experimental Mode\" when a curve is detected</b> to allow the model to set an appropriate speed for the curve."), ""},
|
||||||
|
{"CEStopLights", tr("\"Detected\" Stop Lights/Signs"), tr("<b>Switch to \"Experimental Mode\" whenever the driving model \"detects\" a red light or stop sign.</b><br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights or stop signs. In \"Experimental Mode\", openpilot makes end-to-end driving decisions from camera input, which means it may stop even when there's no clear reason!</i>"), ""},
|
||||||
{"CELead", tr("Lead Detected Ahead"), tr("<b>Switch to \"Experimental Mode\" when a slower or stopped vehicle is detected.</b> Can make braking smoother and more reliable on some vehicles."), ""},
|
{"CELead", tr("Lead Detected Ahead"), tr("<b>Switch to \"Experimental Mode\" when a slower or stopped vehicle is detected.</b> Can make braking smoother and more reliable on some vehicles."), ""},
|
||||||
{"CENavigation", tr("Navigation-Based"), tr("<b>Switch to \"Experimental Mode\" when approaching intersections or turns on the active route</b> while using \"Navigate on openpilot\" (NOO) to allow the model to set an appropriate speed for upcoming maneuvers."), ""},
|
{"CENavigation", tr("Navigation-Based"), tr("<b>Switch to \"Experimental Mode\" when approaching intersections or turns on the active route</b> while using \"Navigate on openpilot\" (NOO) to allow the model to set an appropriate speed for upcoming maneuvers."), ""},
|
||||||
{"CEModelStopTime", tr("Predicted Stop In"), tr("<b>Switch to \"Experimental Mode\" when openpilot predicts a stop within the set time.</b> This is usually triggered when the model \"sees\" a red light or stop sign ahead.<br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights or stop signs. In \"Experimental Mode\", openpilot makes end-to-end driving decisions from camera input, which means it may stop even when there's no clear reason.</i>"), ""},
|
{"CEModelStopTime", tr("Predicted Stop In"), tr("<b>Switch to \"Experimental Mode\" when openpilot predicts a stop within the set time.</b> This is usually triggered when the model \"sees\" a red light or stop sign ahead.<br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights or stop signs. In \"Experimental Mode\", openpilot makes end-to-end driving decisions from camera input, which means it may stop even when there's no clear reason!</i>"), ""},
|
||||||
{"CESignalSpeed", tr("Turn Signal Below"), tr("<b>Switch to \"Experimental Mode\" when using a turn signal below the set speed</b> to allow the model to choose an appropriate speed for smoother left and right turns."), ""},
|
{"CESignalSpeed", tr("Turn Signal Below"), tr("<b>Switch to \"Experimental Mode\" when using a turn signal below the set speed</b> to allow the model to choose an appropriate speed for smoother left and right turns."), ""},
|
||||||
{"ShowCEMStatus", tr("Status Widget"), tr("<b>Show which condition triggered \"Experimental Mode\"</b> on the driving screen."), ""},
|
{"ShowCEMStatus", tr("Status Widget"), tr("<b>Show which condition triggered \"Experimental Mode\"</b> on the driving screen."), ""},
|
||||||
|
|
||||||
@ -132,17 +150,45 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
|||||||
{"DecelerationProfile", tr("Deceleration Profile"), tr("<b>How firmly openpilot slows down.</b> \"Eco\" favors coasting, \"Sport\" applies stronger braking."), ""},
|
{"DecelerationProfile", tr("Deceleration Profile"), tr("<b>How firmly openpilot slows down.</b> \"Eco\" favors coasting, \"Sport\" applies stronger braking."), ""},
|
||||||
{"HumanAcceleration", tr("Human-Like Acceleration"), tr("<b>Acceleration that mimics human behavior</b> by easing the throttle at low speeds and adding extra power when taking off from a stop."), ""},
|
{"HumanAcceleration", tr("Human-Like Acceleration"), tr("<b>Acceleration that mimics human behavior</b> by easing the throttle at low speeds and adding extra power when taking off from a stop."), ""},
|
||||||
{"HumanFollowing", tr("Human-Like Following"), tr("<b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking."), ""},
|
{"HumanFollowing", tr("Human-Like Following"), tr("<b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking."), ""},
|
||||||
|
{"HumanLaneChanges", tr("Human-Like Lane Changes"), tr("<b>Lane-change behavior that mimics human drivers</b> by anticipating and tracking adjacent vehicles during lane changes."), ""},
|
||||||
{"LeadDetectionThreshold", tr("Lead Detection Sensitivity"), tr("<b>How sensitive openpilot is to detecting vehicles.</b> Higher sensitivity allows quicker detection at longer distances but may react to non-vehicle objects; lower sensitivity is more conservative and reduces false detections."), ""},
|
{"LeadDetectionThreshold", tr("Lead Detection Sensitivity"), tr("<b>How sensitive openpilot is to detecting vehicles.</b> Higher sensitivity allows quicker detection at longer distances but may react to non-vehicle objects; lower sensitivity is more conservative and reduces false detections."), ""},
|
||||||
{"TacoTune", tr("\"Taco Bell Run\" Turn Speed Hack"), tr("<b>The turn-speed hack from comma's 2022 \"Taco Bell Run\".</b> Designed to slow down for left and right turns."), ""},
|
{"TacoTune", tr("\"Taco Bell Run\" Turn Speed Hack"), tr("<b>The turn-speed hack from comma's 2022 \"Taco Bell Run\".</b> Designed to slow down for left and right turns."), ""},
|
||||||
|
|
||||||
{"QOLLongitudinal", tr("Quality of Life"), tr("<b>Miscellaneous acceleration and braking control changes</b> to fine-tune how openpilot drives."), "../../frogpilot/assets/toggle_icons/icon_quality_of_life.png"},
|
{"QOLLongitudinal", tr("Quality of Life"), tr("<b>Miscellaneous acceleration and braking control changes</b> to fine-tune how openpilot drives."), "../../frogpilot/assets/toggle_icons/icon_quality_of_life.png"},
|
||||||
{"CustomCruise", tr("Cruise Interval"), tr("<b>How much the set speed increases or decreases</b> for each + or – cruise control button press."), ""},
|
{"CustomCruise", tr("Cruise Interval"), tr("<b>How much the set speed increases or decreases</b> for each + or – cruise control button press."), ""},
|
||||||
{"CustomCruiseLong", tr("Cruise Interval (Hold)"), tr("<b>How much the set speed increases or decreases while holding the + or – cruise control buttons.</b>"), ""},
|
{"CustomCruiseLong", tr("Cruise Interval (Hold)"), tr("<b>How much the set speed increases or decreases while holding the + or – cruise control buttons.</b>"), ""},
|
||||||
{"ForceStops", tr("Force Stop at \"Detected\" Stop Lights/Signs"), tr("<b>Force openpilot to stop whenever the driving model \"detects\" a red light or stop sign.</b><br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights or stop signs. In \"Experimental Mode\", openpilot makes end-to-end driving decisions from camera input, which means it may stop even when there's no clear reason.</i>"), ""},
|
{"ForceStops", tr("Force Stop at \"Detected\" Stop Lights/Signs"), tr("<b>Force openpilot to stop whenever the driving model \"detects\" a red light or stop sign.</b><br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights or stop signs. In \"Experimental Mode\", openpilot makes end-to-end driving decisions from camera input, which means it may stop even when there's no clear reason!</i>"), ""},
|
||||||
{"IncreasedStoppedDistance", tr("Increase Stopped Distance by:"), tr("<b>Add extra space when stopped behind vehicles.</b> Increase for more room; decrease for shorter gaps."), ""},
|
{"IncreasedStoppedDistance", tr("Increase Stopped Distance by:"), tr("<b>Add extra space when stopped behind vehicles.</b> Increase for more room; decrease for shorter gaps."), ""},
|
||||||
{"MapGears", tr("Map Accel/Decel to Gears"), tr("<b>Map the Acceleration or Deceleration profiles to the vehicle's \"Eco\" and \"Sport\" gear modes.</b>"), ""},
|
{"MapGears", tr("Map Accel/Decel to Gears"), tr("<b>Map the Acceleration or Deceleration profiles to the vehicle's \"Eco\" and \"Sport\" gear modes.</b>"), ""},
|
||||||
{"SetSpeedOffset", tr("Offset Set Speed by:"), tr("<b>Increase the set speed by the chosen offset.</b> For example, set +5 if you usually drive 5 over the limit."), ""},
|
{"SetSpeedOffset", tr("Offset Set Speed by:"), tr("<b>Increase the set speed by the chosen offset.</b> For example, set +5 if you usually drive 5 over the limit."), ""},
|
||||||
{"ReverseCruise", tr("Reverse Cruise Increase"), tr("<b>Reverse the cruise control button behavior</b> so a short press increases the set speed by 5 instead of 1."), ""},
|
{"ReverseCruise", tr("Reverse Cruise Increase"), tr("<b>Reverse the cruise control button behavior</b> so a short press increases the set speed by 5 instead of 1."), ""},
|
||||||
|
{"WeatherPresets", tr("Weather Condition Offsets"), tr("<b>Automatically adjust driving behavior based on real-time weather.</b> Helps maintain comfort and safety in low visibility, rain, or snow."), ""},
|
||||||
|
|
||||||
|
{"LowVisibilityOffsets", tr("Low Visibility"), tr("<b>Driving adjustments for fog, haze, or other low-visibility conditions.</b>"), ""},
|
||||||
|
{"IncreaseFollowingLowVisibility", tr("Increase Following Distance by:"), tr("<b>Add extra space behind lead vehicles in low visibility.</b> Increase for more space; decrease for tighter gaps."), ""},
|
||||||
|
{"IncreasedStoppedDistanceLowVisibility", tr("Increase Stopped Distance by:"), tr("<b>Add extra buffer when stopped behind vehicles in low visibility.</b> Increase for more room; decrease for shorter gaps."), ""},
|
||||||
|
{"ReduceAccelerationLowVisibility", tr("Reduce Acceleration by:"), tr("<b>Lower the maximum acceleration in low visibility.</b> Increase for softer takeoffs; decrease for quicker but less stable takeoffs."), ""},
|
||||||
|
{"ReduceLateralAccelerationLowVisibility", tr("Reduce Speed in Curves by:"), tr("<b>Lower the desired speed while driving through curves in low visibility.</b> Increase for safer, gentler turns; decrease for more aggressive driving in curves."), ""},
|
||||||
|
|
||||||
|
{"RainOffsets", tr("Rain"), tr("<b>Driving adjustments for rainy conditions.</b>"), ""},
|
||||||
|
{"IncreaseFollowingRain", tr("Increase Following Distance by:"), tr("<b>Add extra space behind lead vehicles in rain.</b> Increase for more space; decrease for tighter gaps."), ""},
|
||||||
|
{"IncreasedStoppedDistanceRain", tr("Increase Stopped Distance by:"), tr("<b>Add extra buffer when stopped behind vehicles in rain.</b> Increase for more room; decrease for shorter gaps."), ""},
|
||||||
|
{"ReduceAccelerationRain", tr("Reduce Acceleration by:"), tr("<b>Lower the maximum acceleration in rain.</b> Increase for softer takeoffs; decrease for quicker but less stable takeoffs."), ""},
|
||||||
|
{"ReduceLateralAccelerationRain", tr("Reduce Speed in Curves by:"), tr("<b>Lower the desired speed while driving through curves in rain.</b> Increase for safer, gentler turns; decrease for more aggressive driving in curves."), ""},
|
||||||
|
|
||||||
|
{"RainStormOffsets", tr("Rainstorms"), tr("<b>Driving adjustments for rainstorms.</b>"), ""},
|
||||||
|
{"IncreaseFollowingRainStorm", tr("Increase Following Distance by:"), tr("<b>Add extra space behind lead vehicles in a rainstorm.</b> Increase for more space; decrease for tighter gaps."), ""},
|
||||||
|
{"IncreasedStoppedDistanceRainStorm", tr("Increase Stopped Distance by:"), tr("<b>Add extra buffer when stopped behind vehicles in a rainstorm.</b> Increase for more room; decrease for shorter gaps."), ""},
|
||||||
|
{"ReduceAccelerationRainStorm", tr("Reduce Acceleration by:"), tr("<b>Lower the maximum acceleration in a rainstorm.</b> Increase for softer takeoffs; decrease for quicker but less stable takeoffs."), ""},
|
||||||
|
{"ReduceLateralAccelerationRainStorm", tr("Reduce Speed in Curves by:"), tr("<b>Lower the desired speed while driving through curves in a rainstorm.</b> Increase for safer, gentler turns; decrease for more aggressive driving in curves."), ""},
|
||||||
|
|
||||||
|
{"SnowOffsets", tr("Snow"), tr("<b>Driving adjustments for snowy conditions.</b>"), ""},
|
||||||
|
{"IncreaseFollowingSnow", tr("Increase Following Distance by:"), tr("<b>Add extra space behind lead vehicles in snow.</b> Increase for more space; decrease for tighter gaps."), ""},
|
||||||
|
{"IncreasedStoppedDistanceSnow", tr("Increase Stopped Distance by:"), tr("<b>Add extra buffer when stopped behind vehicles in snow.</b> Increase for more room; decrease for shorter gaps."), ""},
|
||||||
|
{"ReduceAccelerationSnow", tr("Reduce Acceleration by:"), tr("<b>Lower the maximum acceleration in snow.</b> Increase for softer takeoffs; decrease for quicker but less stable takeoffs."), ""},
|
||||||
|
{"ReduceLateralAccelerationSnow", tr("Reduce Speed in Curves by:"), tr("<b>Lower the desired speed while driving through curves in snow.</b> Increase for safer, gentler turns; decrease for more aggressive driving in curves."), ""},
|
||||||
|
|
||||||
|
{"SetWeatherKey", tr("Set Your Own Key"), tr("<b>Set your own \"OpenWeatherMap\" key to increase the weather update rate.</b><br><br><i>Personal keys grant 1,000 free calls per day, allowing for updates every minute. The default key is shared and only updates every 15 minutes.</i>"), ""},
|
||||||
|
|
||||||
{"SpeedLimitController", tr("Speed Limit Controller"), tr("<b>Limit openpilot's maximum driving speed to the current speed limit</b> obtained from downloaded maps, Mapbox, Navigate on openpilot, or the dashboard for supported vehicles (Ford, Genesis, Hyundai, Kia, Lexus, Toyota)."), "../../frogpilot/assets/toggle_icons/icon_speed_limit.png"},
|
{"SpeedLimitController", tr("Speed Limit Controller"), tr("<b>Limit openpilot's maximum driving speed to the current speed limit</b> obtained from downloaded maps, Mapbox, Navigate on openpilot, or the dashboard for supported vehicles (Ford, Genesis, Hyundai, Kia, Lexus, Toyota)."), "../../frogpilot/assets/toggle_icons/icon_speed_limit.png"},
|
||||||
{"SLCFallback", tr("Fallback Speed"), tr("<b>The speed used by \"Speed Limit Controller\" when no speed limit is found.</b><br><br>- <b>Set Speed</b>: Use the cruise set speed<br>- <b>Experimental Mode</b>: Estimate the limit using the driving model<br>- <b>Previous Limit</b>: Keep using the last confirmed limit"), ""},
|
{"SLCFallback", tr("Fallback Speed"), tr("<b>The speed used by \"Speed Limit Controller\" when no speed limit is found.</b><br><br>- <b>Set Speed</b>: Use the cruise set speed<br>- <b>Experimental Mode</b>: Estimate the limit using the driving model<br>- <b>Previous Limit</b>: Keep using the last confirmed limit"), ""},
|
||||||
@ -361,6 +407,116 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
|||||||
longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, icon, mapGearsToggles, mapGearsToggleNames);
|
longitudinalToggle = new FrogPilotButtonToggleControl(param, title, desc, icon, mapGearsToggles, mapGearsToggleNames);
|
||||||
} else if (param == "SetSpeedOffset") {
|
} else if (param == "SetSpeedOffset") {
|
||||||
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr(" mph"));
|
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, tr(" mph"));
|
||||||
|
} else if (param == "WeatherPresets") {
|
||||||
|
FrogPilotManageControl *weatherToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||||
|
QObject::connect(weatherToggle, &FrogPilotManageControl::manageButtonClicked, [longitudinalLayout, weatherPanel, this]() {
|
||||||
|
openSubSubPanel();
|
||||||
|
|
||||||
|
longitudinalLayout->setCurrentWidget(weatherPanel);
|
||||||
|
|
||||||
|
qolOpen = true;
|
||||||
|
});
|
||||||
|
longitudinalToggle = weatherToggle;
|
||||||
|
} else if (param == "SetWeatherKey") {
|
||||||
|
weatherKeyControl = new FrogPilotButtonsControl(title, desc, icon, {tr("ADD"), tr("TEST")});
|
||||||
|
QObject::connect(weatherKeyControl, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||||
|
if (id == 0) {
|
||||||
|
if (!params.get("WeatherToken").empty()) {
|
||||||
|
if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to remove your key?"), this)) {
|
||||||
|
params.remove("WeatherToken");
|
||||||
|
params_cache.remove("WeatherToken");
|
||||||
|
|
||||||
|
weatherKeyControl->setText(0, tr("ADD"));
|
||||||
|
weatherKeyControl->setVisibleButton(1, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QString key = InputDialog::getText(tr("Enter your \"OpenWeatherMap\" key"), this).trimmed();
|
||||||
|
if (key.length() == 32) {
|
||||||
|
params.put("WeatherToken", key.toStdString());
|
||||||
|
|
||||||
|
weatherKeyControl->setText(0, tr("REMOVE"));
|
||||||
|
weatherKeyControl->setVisibleButton(1, true);
|
||||||
|
} else if (!key.isEmpty()) {
|
||||||
|
ConfirmationDialog::alert(tr("Invalid key!"), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
weatherKeyControl->setValue(tr("Testing..."));
|
||||||
|
|
||||||
|
QString key = QString::fromStdString(params.get("WeatherToken"));
|
||||||
|
QString url = QString("https://api.openweathermap.org/data/2.5/weather?lat=42.4293&lon=-83.9850&appid=%1").arg(key);
|
||||||
|
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
QNetworkReply *reply = networkManager->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, [=]() {
|
||||||
|
weatherKeyControl->setValue("");
|
||||||
|
|
||||||
|
QString message;
|
||||||
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
|
message = tr("Key is valid!");
|
||||||
|
} else if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 401) {
|
||||||
|
message = tr("Invalid key!");
|
||||||
|
} else {
|
||||||
|
message = tr("An error occurred: %1").arg(reply->errorString());
|
||||||
|
}
|
||||||
|
ConfirmationDialog::alert(message, this);
|
||||||
|
reply->deleteLater();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
longitudinalToggle = weatherKeyControl;
|
||||||
|
} else if (param == "LowVisibilityOffsets") {
|
||||||
|
ButtonControl *manageLowVisibilitOffsetsButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||||
|
QObject::connect(manageLowVisibilitOffsetsButton, &ButtonControl::clicked, [longitudinalLayout, weatherLowVisibilityPanel, this]() {
|
||||||
|
openSubSubSubPanel();
|
||||||
|
|
||||||
|
longitudinalLayout->setCurrentWidget(weatherLowVisibilityPanel);
|
||||||
|
|
||||||
|
weatherOpen = true;
|
||||||
|
});
|
||||||
|
longitudinalToggle = manageLowVisibilitOffsetsButton;
|
||||||
|
} else if (param == "RainOffsets") {
|
||||||
|
ButtonControl *manageRainOffsetsButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||||
|
QObject::connect(manageRainOffsetsButton, &ButtonControl::clicked, [longitudinalLayout, weatherRainPanel, this]() {
|
||||||
|
openSubSubSubPanel();
|
||||||
|
|
||||||
|
longitudinalLayout->setCurrentWidget(weatherRainPanel);
|
||||||
|
|
||||||
|
weatherOpen = true;
|
||||||
|
});
|
||||||
|
longitudinalToggle = manageRainOffsetsButton;
|
||||||
|
} else if (param == "RainStormOffsets") {
|
||||||
|
ButtonControl *manageRainStormOffsetsButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||||
|
QObject::connect(manageRainStormOffsetsButton, &ButtonControl::clicked, [longitudinalLayout, weatherRainStormPanel, this]() {
|
||||||
|
openSubSubSubPanel();
|
||||||
|
|
||||||
|
longitudinalLayout->setCurrentWidget(weatherRainStormPanel);
|
||||||
|
|
||||||
|
weatherOpen = true;
|
||||||
|
});
|
||||||
|
longitudinalToggle = manageRainStormOffsetsButton;
|
||||||
|
} else if (param == "SnowOffsets") {
|
||||||
|
ButtonControl *manageSnowOffsetsButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||||
|
QObject::connect(manageSnowOffsetsButton, &ButtonControl::clicked, [longitudinalLayout, weatherSnowPanel, this]() {
|
||||||
|
openSubSubSubPanel();
|
||||||
|
|
||||||
|
longitudinalLayout->setCurrentWidget(weatherSnowPanel);
|
||||||
|
|
||||||
|
weatherOpen = true;
|
||||||
|
});
|
||||||
|
longitudinalToggle = manageSnowOffsetsButton;
|
||||||
|
} else if (param == "IncreaseFollowingLowVisibility" || param == "IncreaseFollowingRain" || param == "IncreaseFollowingRainStorm" || param == "IncreaseFollowingSnow") {
|
||||||
|
std::map<float, QString> followTimeLabels;
|
||||||
|
for (float i = 0; i <= 3; i += 0.01) {
|
||||||
|
followTimeLabels[i] = std::lround(i / 0.01) == 1 / 0.01 ? QString::number(i, 'f', 2) + tr(" second") : QString::number(i, 'f', 2) + tr(" seconds");
|
||||||
|
}
|
||||||
|
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 3, QString(), followTimeLabels, 0.01, true);
|
||||||
|
} else if (param == "IncreasedStoppedDistanceLowVisibility" || param == "IncreasedStoppedDistanceRain" || param == "IncreasedStoppedDistanceRainStorm" || param == "IncreasedStoppedDistanceSnow") {
|
||||||
|
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, tr(" feet"));
|
||||||
|
} else if (param == "ReduceAccelerationLowVisibility" || param == "ReduceAccelerationRain" || param == "ReduceAccelerationRainStorm" || param == "ReduceAccelerationSnow") {
|
||||||
|
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, "%", std::map<float, QString>(), 1);
|
||||||
|
} else if (param == "ReduceLateralAccelerationLowVisibility" || param == "ReduceLateralAccelerationRain" || param == "ReduceLateralAccelerationRainStorm" || param == "ReduceLateralAccelerationSnow") {
|
||||||
|
longitudinalToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, "%", std::map<float, QString>(), 1);
|
||||||
|
|
||||||
} else if (param == "SpeedLimitController") {
|
} else if (param == "SpeedLimitController") {
|
||||||
FrogPilotManageControl *speedLimitControllerToggle = new FrogPilotManageControl(param, title, desc, icon);
|
FrogPilotManageControl *speedLimitControllerToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||||
@ -505,6 +661,16 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
|||||||
standardPersonalityList->addItem(longitudinalToggle);
|
standardPersonalityList->addItem(longitudinalToggle);
|
||||||
} else if (trafficPersonalityKeys.contains(param)) {
|
} else if (trafficPersonalityKeys.contains(param)) {
|
||||||
trafficPersonalityList->addItem(longitudinalToggle);
|
trafficPersonalityList->addItem(longitudinalToggle);
|
||||||
|
} else if (weatherKeys.contains(param)) {
|
||||||
|
weatherList->addItem(longitudinalToggle);
|
||||||
|
} else if (weatherLowVisibilityKeys.contains(param)) {
|
||||||
|
weatherLowVisibilityList->addItem(longitudinalToggle);
|
||||||
|
} else if (weatherRainKeys.contains(param)) {
|
||||||
|
weatherRainList->addItem(longitudinalToggle);
|
||||||
|
} else if (weatherRainStormKeys.contains(param)) {
|
||||||
|
weatherRainStormList->addItem(longitudinalToggle);
|
||||||
|
} else if (weatherSnowKeys.contains(param)) {
|
||||||
|
weatherSnowList->addItem(longitudinalToggle);
|
||||||
} else {
|
} else {
|
||||||
longitudinalList->addItem(longitudinalToggle);
|
longitudinalList->addItem(longitudinalToggle);
|
||||||
|
|
||||||
@ -637,23 +803,38 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
|
|||||||
openDescriptions(forceOpenDescriptions, toggles);
|
openDescriptions(forceOpenDescriptions, toggles);
|
||||||
longitudinalLayout->setCurrentWidget(longitudinalPanel);
|
longitudinalLayout->setCurrentWidget(longitudinalPanel);
|
||||||
});
|
});
|
||||||
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubSubPanel, [longitudinalLayout, customDrivingPersonalityPanel, speedLimitControllerPanel, this]() {
|
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubSubPanel, [longitudinalLayout, customDrivingPersonalityPanel, qolPanel, speedLimitControllerPanel, this]() {
|
||||||
openDescriptions(forceOpenDescriptions, toggles);
|
openDescriptions(forceOpenDescriptions, toggles);
|
||||||
|
|
||||||
if (customPersonalityOpen) {
|
if (customPersonalityOpen) {
|
||||||
longitudinalLayout->setCurrentWidget(customDrivingPersonalityPanel);
|
longitudinalLayout->setCurrentWidget(customDrivingPersonalityPanel);
|
||||||
|
|
||||||
customPersonalityOpen = false;
|
customPersonalityOpen = false;
|
||||||
|
} else if (qolOpen) {
|
||||||
|
longitudinalLayout->setCurrentWidget(qolPanel);
|
||||||
|
|
||||||
|
qolOpen = false;
|
||||||
} else if (slcOpen) {
|
} else if (slcOpen) {
|
||||||
longitudinalLayout->setCurrentWidget(speedLimitControllerPanel);
|
longitudinalLayout->setCurrentWidget(speedLimitControllerPanel);
|
||||||
|
|
||||||
slcOpen = false;
|
slcOpen = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
QObject::connect(parent, &FrogPilotSettingsWindow::closeSubSubSubPanel, [longitudinalLayout, weatherPanel, this]() {
|
||||||
|
openDescriptions(forceOpenDescriptions, toggles);
|
||||||
|
|
||||||
|
if (weatherOpen) {
|
||||||
|
longitudinalLayout->setCurrentWidget(weatherPanel);
|
||||||
|
|
||||||
|
weatherOpen = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
QObject::connect(parent, &FrogPilotSettingsWindow::updateMetric, this, &FrogPilotLongitudinalPanel::updateMetric);
|
QObject::connect(parent, &FrogPilotSettingsWindow::updateMetric, this, &FrogPilotLongitudinalPanel::updateMetric);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrogPilotLongitudinalPanel::showEvent(QShowEvent *event) {
|
void FrogPilotLongitudinalPanel::showEvent(QShowEvent *event) {
|
||||||
|
FrogPilotUIState &fs = *frogpilotUIState();
|
||||||
|
|
||||||
frogpilotToggleLevels = parent->frogpilotToggleLevels;
|
frogpilotToggleLevels = parent->frogpilotToggleLevels;
|
||||||
|
|
||||||
calibratedLateralAccelerationLabel->setText(QString::number(params.getFloat("CalibratedLateralAcceleration"), 'f', 2) + tr(" m/s²"));
|
calibratedLateralAccelerationLabel->setText(QString::number(params.getFloat("CalibratedLateralAcceleration"), 'f', 2) + tr(" m/s²"));
|
||||||
@ -666,6 +847,10 @@ void FrogPilotLongitudinalPanel::showEvent(QShowEvent *event) {
|
|||||||
vEgoStartingToggle->setTitle(QString(tr("Start Speed (Default: %1)")).arg(QString::number(parent->vEgoStarting, 'f', 2)));
|
vEgoStartingToggle->setTitle(QString(tr("Start Speed (Default: %1)")).arg(QString::number(parent->vEgoStarting, 'f', 2)));
|
||||||
vEgoStoppingToggle->setTitle(QString(tr("Stop Speed (Default: %1)")).arg(QString::number(parent->vEgoStopping, 'f', 2)));
|
vEgoStoppingToggle->setTitle(QString(tr("Stop Speed (Default: %1)")).arg(QString::number(parent->vEgoStopping, 'f', 2)));
|
||||||
|
|
||||||
|
bool keyExists = !params.get("WeatherToken").empty();
|
||||||
|
weatherKeyControl->setText(0, keyExists ? tr("REMOVE") : tr("ADD"));
|
||||||
|
weatherKeyControl->setVisibleButton(1, keyExists && fs.frogpilot_scene.online);
|
||||||
|
|
||||||
updateToggles();
|
updateToggles();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,6 +861,10 @@ void FrogPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
|
|||||||
double speedConversion = metric ? MILE_TO_KM : KM_TO_MILE;
|
double speedConversion = metric ? MILE_TO_KM : KM_TO_MILE;
|
||||||
|
|
||||||
params.putIntNonBlocking("IncreasedStoppedDistance", params.getInt("IncreasedStoppedDistance") * distanceConversion);
|
params.putIntNonBlocking("IncreasedStoppedDistance", params.getInt("IncreasedStoppedDistance") * distanceConversion);
|
||||||
|
params.putIntNonBlocking("IncreasedStoppedDistanceLowVisibility", params.getInt("IncreasedStoppedDistanceLowVisibility") * distanceConversion);
|
||||||
|
params.putIntNonBlocking("IncreasedStoppedDistanceRain", params.getInt("IncreasedStoppedDistanceRain") * distanceConversion);
|
||||||
|
params.putIntNonBlocking("IncreasedStoppedDistanceRainStorm", params.getInt("IncreasedStoppedDistanceRainStorm") * distanceConversion);
|
||||||
|
params.putIntNonBlocking("IncreasedStoppedDistanceSnow", params.getInt("IncreasedStoppedDistanceSnow") * distanceConversion);
|
||||||
|
|
||||||
params.putIntNonBlocking("CESignalSpeed", params.getInt("CESignalSpeed") * speedConversion);
|
params.putIntNonBlocking("CESignalSpeed", params.getInt("CESignalSpeed") * speedConversion);
|
||||||
params.putIntNonBlocking("CESpeed", params.getInt("CESpeed") * speedConversion);
|
params.putIntNonBlocking("CESpeed", params.getInt("CESpeed") * speedConversion);
|
||||||
@ -731,6 +920,10 @@ void FrogPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
|
|||||||
FrogPilotParamValueControl *offset6Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset6"]);
|
FrogPilotParamValueControl *offset6Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset6"]);
|
||||||
FrogPilotParamValueControl *offset7Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset7"]);
|
FrogPilotParamValueControl *offset7Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset7"]);
|
||||||
FrogPilotParamValueControl *increasedStoppedDistanceToggle = static_cast<FrogPilotParamValueControl*>(toggles["IncreasedStoppedDistance"]);
|
FrogPilotParamValueControl *increasedStoppedDistanceToggle = static_cast<FrogPilotParamValueControl*>(toggles["IncreasedStoppedDistance"]);
|
||||||
|
FrogPilotParamValueControl *increasedStoppedDistanceLowVisibilityToggle = static_cast<FrogPilotParamValueControl*>(toggles["IncreasedStoppedDistanceLowVisibility"]);
|
||||||
|
FrogPilotParamValueControl *increasedStoppedDistanceRainToggle = static_cast<FrogPilotParamValueControl*>(toggles["IncreasedStoppedDistanceRain"]);
|
||||||
|
FrogPilotParamValueControl *increasedStoppedDistanceRainStormToggle = static_cast<FrogPilotParamValueControl*>(toggles["IncreasedStoppedDistanceRainStorm"]);
|
||||||
|
FrogPilotParamValueControl *increasedStoppedDistanceSnowToggle = static_cast<FrogPilotParamValueControl*>(toggles["IncreasedStoppedDistanceSnow"]);
|
||||||
FrogPilotParamValueControl *setSpeedOffsetToggle = static_cast<FrogPilotParamValueControl*>(toggles["SetSpeedOffset"]);
|
FrogPilotParamValueControl *setSpeedOffsetToggle = static_cast<FrogPilotParamValueControl*>(toggles["SetSpeedOffset"]);
|
||||||
|
|
||||||
if (metric) {
|
if (metric) {
|
||||||
@ -751,6 +944,10 @@ void FrogPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
|
|||||||
offset7Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 75 and 99 mph."));
|
offset7Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 75 and 99 mph."));
|
||||||
|
|
||||||
increasedStoppedDistanceToggle->updateControl(0, 3, metricDistanceLabels);
|
increasedStoppedDistanceToggle->updateControl(0, 3, metricDistanceLabels);
|
||||||
|
increasedStoppedDistanceLowVisibilityToggle->updateControl(0, 3, metricDistanceLabels);
|
||||||
|
increasedStoppedDistanceRainToggle->updateControl(0, 3, metricDistanceLabels);
|
||||||
|
increasedStoppedDistanceRainStormToggle->updateControl(0, 3, metricDistanceLabels);
|
||||||
|
increasedStoppedDistanceSnowToggle->updateControl(0, 3, metricDistanceLabels);
|
||||||
|
|
||||||
ceSignal->updateControl(0, 150, metricSpeedLabels);
|
ceSignal->updateControl(0, 150, metricSpeedLabels);
|
||||||
ceSpeedToggle->updateControl(0, 150, metricSpeedLabels);
|
ceSpeedToggle->updateControl(0, 150, metricSpeedLabels);
|
||||||
@ -782,6 +979,10 @@ void FrogPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
|
|||||||
offset7Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 75 and 99 mph."));
|
offset7Toggle->setDescription(tr("<b>How much to offset posted speed-limits</b> between 75 and 99 mph."));
|
||||||
|
|
||||||
increasedStoppedDistanceToggle->updateControl(0, 10, imperialDistanceLabels);
|
increasedStoppedDistanceToggle->updateControl(0, 10, imperialDistanceLabels);
|
||||||
|
increasedStoppedDistanceLowVisibilityToggle->updateControl(0, 10, imperialDistanceLabels);
|
||||||
|
increasedStoppedDistanceRainToggle->updateControl(0, 10, imperialDistanceLabels);
|
||||||
|
increasedStoppedDistanceRainStormToggle->updateControl(0, 10, imperialDistanceLabels);
|
||||||
|
increasedStoppedDistanceSnowToggle->updateControl(0, 10, imperialDistanceLabels);
|
||||||
|
|
||||||
ceSignal->updateControl(0, 99, imperialSpeedLabels);
|
ceSignal->updateControl(0, 99, imperialSpeedLabels);
|
||||||
ceSpeedToggle->updateControl(0, 99, imperialSpeedLabels);
|
ceSpeedToggle->updateControl(0, 99, imperialSpeedLabels);
|
||||||
@ -812,7 +1013,11 @@ void FrogPilotLongitudinalPanel::updateToggles() {
|
|||||||
|
|
||||||
bool setVisible = parent->tuningLevel >= frogpilotToggleLevels[key].toDouble();
|
bool setVisible = parent->tuningLevel >= frogpilotToggleLevels[key].toDouble();
|
||||||
|
|
||||||
if (key == "CustomCruise" || key == "CustomCruiseLong" || key == "SetSpeedLimit" || key == "SetSpeedOffset") {
|
if (key == "CEStopLights") {
|
||||||
|
setVisible &= !toggles["CEModelStopTime"]->isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (key == "CustomCruise" || key == "CustomCruiseLong" || key == "SetSpeedLimit" || key == "SetSpeedOffset") {
|
||||||
setVisible &= !parent->hasPCMCruise;
|
setVisible &= !parent->hasPCMCruise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -820,6 +1025,10 @@ void FrogPilotLongitudinalPanel::updateToggles() {
|
|||||||
setVisible &= parent->isToyota;
|
setVisible &= parent->isToyota;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (key == "HumanLaneChanges") {
|
||||||
|
setVisible &= parent->hasRadar;
|
||||||
|
}
|
||||||
|
|
||||||
else if (key == "MapGears") {
|
else if (key == "MapGears") {
|
||||||
setVisible &= parent->isGM || parent->isHKGCanFd || parent->isToyota;
|
setVisible &= parent->isGM || parent->isHKGCanFd || parent->isToyota;
|
||||||
setVisible &= !parent->isTSK;
|
setVisible &= !parent->isTSK;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void openSubPanel();
|
void openSubPanel();
|
||||||
void openSubSubPanel();
|
void openSubSubPanel();
|
||||||
|
void openSubSubSubPanel();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void showEvent(QShowEvent *event) override;
|
void showEvent(QShowEvent *event) override;
|
||||||
@ -21,17 +22,19 @@ private:
|
|||||||
|
|
||||||
bool customPersonalityOpen;
|
bool customPersonalityOpen;
|
||||||
bool forceOpenDescriptions;
|
bool forceOpenDescriptions;
|
||||||
|
bool qolOpen;
|
||||||
bool slcOpen;
|
bool slcOpen;
|
||||||
|
bool weatherOpen;
|
||||||
|
|
||||||
std::map<QString, AbstractControl*> toggles;
|
std::map<QString, AbstractControl*> toggles;
|
||||||
|
|
||||||
QSet<QString> advancedLongitudinalTuneKeys = {"LongitudinalActuatorDelay", "MaxDesiredAcceleration", "StartAccel", "StopAccel", "StoppingDecelRate", "VEgoStarting", "VEgoStopping"};
|
QSet<QString> advancedLongitudinalTuneKeys = {"LongitudinalActuatorDelay", "MaxDesiredAcceleration", "StartAccel", "StopAccel", "StoppingDecelRate", "VEgoStarting", "VEgoStopping"};
|
||||||
QSet<QString> aggressivePersonalityKeys = {"AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", "ResetAggressivePersonality"};
|
QSet<QString> aggressivePersonalityKeys = {"AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", "ResetAggressivePersonality"};
|
||||||
QSet<QString> conditionalExperimentalKeys = {"CESpeed", "CESpeedLead", "CECurves", "CELead", "CEModelStopTime", "CENavigation", "CESignalSpeed", "ShowCEMStatus"};
|
QSet<QString> conditionalExperimentalKeys = {"CESpeed", "CESpeedLead", "CECurves", "CELead", "CEModelStopTime", "CENavigation", "CESignalSpeed", "CEStopLights", "ShowCEMStatus"};
|
||||||
QSet<QString> curveSpeedKeys = {"CalibratedLateralAcceleration", "CalibrationProgress", "ResetCurveData", "ShowCSCStatus"};
|
QSet<QString> curveSpeedKeys = {"CalibratedLateralAcceleration", "CalibrationProgress", "ResetCurveData", "ShowCSCStatus"};
|
||||||
QSet<QString> customDrivingPersonalityKeys = {"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", "TrafficPersonalityProfile"};
|
QSet<QString> customDrivingPersonalityKeys = {"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", "TrafficPersonalityProfile"};
|
||||||
QSet<QString> longitudinalTuneKeys = {"AccelerationProfile", "DecelerationProfile", "HumanAcceleration", "HumanFollowing", "LeadDetectionThreshold", "TacoTune"};
|
QSet<QString> longitudinalTuneKeys = {"AccelerationProfile", "DecelerationProfile", "HumanAcceleration", "HumanFollowing", "HumanLaneChanges", "LeadDetectionThreshold", "TacoTune"};
|
||||||
QSet<QString> qolKeys = {"CustomCruise", "CustomCruiseLong", "ForceStops", "IncreasedStoppedDistance", "MapGears", "ReverseCruise", "SetSpeedOffset"};
|
QSet<QString> qolKeys = {"CustomCruise", "CustomCruiseLong", "ForceStops", "IncreasedStoppedDistance", "MapGears", "ReverseCruise", "SetSpeedOffset", "WeatherPresets"};
|
||||||
QSet<QString> relaxedPersonalityKeys = {"RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration", "RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease", "ResetRelaxedPersonality"};
|
QSet<QString> relaxedPersonalityKeys = {"RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration", "RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease", "ResetRelaxedPersonality"};
|
||||||
QSet<QString> speedLimitControllerKeys = {"SLCOffsets", "SLCFallback", "SLCOverride", "SLCPriority", "SLCQOL", "SLCVisuals"};
|
QSet<QString> speedLimitControllerKeys = {"SLCOffsets", "SLCFallback", "SLCOverride", "SLCPriority", "SLCQOL", "SLCVisuals"};
|
||||||
QSet<QString> speedLimitControllerOffsetsKeys = {"Offset1", "Offset2", "Offset3", "Offset4", "Offset5", "Offset6", "Offset7"};
|
QSet<QString> speedLimitControllerOffsetsKeys = {"Offset1", "Offset2", "Offset3", "Offset4", "Offset5", "Offset6", "Offset7"};
|
||||||
@ -39,9 +42,16 @@ private:
|
|||||||
QSet<QString> speedLimitControllerVisualKeys = {"ShowSLCOffset", "SpeedLimitSources"};
|
QSet<QString> speedLimitControllerVisualKeys = {"ShowSLCOffset", "SpeedLimitSources"};
|
||||||
QSet<QString> standardPersonalityKeys = {"StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration", "StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease", "ResetStandardPersonality"};
|
QSet<QString> standardPersonalityKeys = {"StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration", "StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease", "ResetStandardPersonality"};
|
||||||
QSet<QString> trafficPersonalityKeys = {"TrafficFollow", "TrafficJerkAcceleration", "TrafficJerkDeceleration", "TrafficJerkDanger", "TrafficJerkSpeed", "TrafficJerkSpeedDecrease", "ResetTrafficPersonality"};
|
QSet<QString> trafficPersonalityKeys = {"TrafficFollow", "TrafficJerkAcceleration", "TrafficJerkDeceleration", "TrafficJerkDanger", "TrafficJerkSpeed", "TrafficJerkSpeedDecrease", "ResetTrafficPersonality"};
|
||||||
|
QSet<QString> weatherKeys = {"LowVisibilityOffsets", "RainOffsets", "RainStormOffsets", "SetWeatherKey", "SnowOffsets"};
|
||||||
|
QSet<QString> weatherLowVisibilityKeys = {"IncreaseFollowingLowVisibility", "IncreasedStoppedDistanceLowVisibility", "ReduceAccelerationLowVisibility", "ReduceLateralAccelerationLowVisibility"};
|
||||||
|
QSet<QString> weatherRainKeys = {"IncreaseFollowingRain", "IncreasedStoppedDistanceRain", "ReduceAccelerationRain", "ReduceLateralAccelerationRain"};
|
||||||
|
QSet<QString> weatherRainStormKeys = {"IncreaseFollowingRainStorm", "IncreasedStoppedDistanceRainStorm", "ReduceAccelerationRainStorm", "ReduceLateralAccelerationRainStorm"};
|
||||||
|
QSet<QString> weatherSnowKeys = {"IncreaseFollowingSnow", "IncreasedStoppedDistanceSnow", "ReduceAccelerationSnow", "ReduceLateralAccelerationSnow"};
|
||||||
|
|
||||||
QSet<QString> parentKeys;
|
QSet<QString> parentKeys;
|
||||||
|
|
||||||
|
FrogPilotButtonsControl *weatherKeyControl;
|
||||||
|
|
||||||
FrogPilotParamValueControl *longitudinalActuatorDelayToggle;
|
FrogPilotParamValueControl *longitudinalActuatorDelayToggle;
|
||||||
FrogPilotParamValueControl *startAccelToggle;
|
FrogPilotParamValueControl *startAccelToggle;
|
||||||
FrogPilotParamValueControl *stopAccelToggle;
|
FrogPilotParamValueControl *stopAccelToggle;
|
||||||
@ -60,4 +70,6 @@ private:
|
|||||||
Params params_cache{"/cache/params"};
|
Params params_cache{"/cache/params"};
|
||||||
Params params_default{"/dev/shm/params_default"};
|
Params params_default{"/dev/shm/params_default"};
|
||||||
Params params_memory{"/dev/shm/params"};
|
Params params_memory{"/dev/shm/params"};
|
||||||
|
|
||||||
|
QNetworkAccessManager *networkManager;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -63,7 +63,7 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent) : FrogPi
|
|||||||
QObject::connect(removeMapsButton, &ButtonControl::clicked, [this] {
|
QObject::connect(removeMapsButton, &ButtonControl::clicked, [this] {
|
||||||
if (FrogPilotConfirmationDialog::yesorno(tr("Delete all downloaded maps?"), this)) {
|
if (FrogPilotConfirmationDialog::yesorno(tr("Delete all downloaded maps?"), this)) {
|
||||||
std::thread([this] {
|
std::thread([this] {
|
||||||
mapsSize->setText("0 MB");
|
mapsSize->setText(tr("0 MB"));
|
||||||
|
|
||||||
mapsFolderPath.removeRecursively();
|
mapsFolderPath.removeRecursively();
|
||||||
}).detach();
|
}).detach();
|
||||||
@ -181,7 +181,7 @@ void FrogPilotMapsPanel::showEvent(QShowEvent *event) {
|
|||||||
std::string osmDownloadProgress = params.get("OSMDownloadProgress");
|
std::string osmDownloadProgress = params.get("OSMDownloadProgress");
|
||||||
if (!osmDownloadProgress.empty()) {
|
if (!osmDownloadProgress.empty()) {
|
||||||
downloadMapsButton->setText(tr("CANCEL"));
|
downloadMapsButton->setText(tr("CANCEL"));
|
||||||
downloadStatus->setText("Calculating...");
|
downloadStatus->setText(tr("Calculating..."));
|
||||||
|
|
||||||
downloadStatus->setVisible(true);
|
downloadStatus->setVisible(true);
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ void FrogPilotMapsPanel::showEvent(QShowEvent *event) {
|
|||||||
updateDownloadLabels(osmDownloadProgress);
|
updateDownloadLabels(osmDownloadProgress);
|
||||||
} else {
|
} else {
|
||||||
downloadMapsButton->setEnabled(!cancellingDownload && hasMapsSelected && fs.frogpilot_scene.online && parked);
|
downloadMapsButton->setEnabled(!cancellingDownload && hasMapsSelected && fs.frogpilot_scene.online && parked);
|
||||||
downloadMapsButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : "Not parked") : tr("Offline..."));
|
downloadMapsButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : tr("Not parked")) : tr("Offline..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +209,7 @@ void FrogPilotMapsPanel::updateState(const UIState &s, const FrogPilotUIState &f
|
|||||||
updateDownloadLabels(osmDownloadProgress);
|
updateDownloadLabels(osmDownloadProgress);
|
||||||
} else {
|
} else {
|
||||||
downloadMapsButton->setEnabled(!cancellingDownload && hasMapsSelected && fs.frogpilot_scene.online && parked);
|
downloadMapsButton->setEnabled(!cancellingDownload && hasMapsSelected && fs.frogpilot_scene.online && parked);
|
||||||
downloadMapsButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : "Not parked") : tr("Offline..."));
|
downloadMapsButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : tr("Not parked")) : tr("Offline..."));
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->keepScreenOn = !osmDownloadProgress.empty();
|
parent->keepScreenOn = !osmDownloadProgress.empty();
|
||||||
@ -220,10 +220,10 @@ void FrogPilotMapsPanel::cancelDownload() {
|
|||||||
|
|
||||||
downloadMapsButton->setEnabled(false);
|
downloadMapsButton->setEnabled(false);
|
||||||
|
|
||||||
downloadETA->setText("Cancelling...");
|
downloadETA->setText(tr("Calculating..."));
|
||||||
downloadMapsButton->setText(tr("CANCELLED"));
|
downloadMapsButton->setText(tr("CANCEL"));
|
||||||
downloadStatus->setText("Cancelling...");
|
downloadStatus->setText(tr("Calculating..."));
|
||||||
downloadTimeElapsed->setText("Cancelling...");
|
downloadTimeElapsed->setText(tr("Calculating..."));
|
||||||
|
|
||||||
params.remove("OSMDownloadProgress");
|
params.remove("OSMDownloadProgress");
|
||||||
params_memory.remove("OSMDownloadLocations");
|
params_memory.remove("OSMDownloadLocations");
|
||||||
@ -250,10 +250,10 @@ void FrogPilotMapsPanel::cancelDownload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FrogPilotMapsPanel::startDownload() {
|
void FrogPilotMapsPanel::startDownload() {
|
||||||
downloadETA->setText("Calculating...");
|
downloadETA->setText(tr("Calculating..."));
|
||||||
downloadMapsButton->setText(tr("CANCEL"));
|
downloadMapsButton->setText(tr("CANCEL"));
|
||||||
downloadStatus->setText("Calculating...");
|
downloadStatus->setText(tr("Calculating..."));
|
||||||
downloadTimeElapsed->setText("Calculating...");
|
downloadTimeElapsed->setText(tr("Calculating..."));
|
||||||
|
|
||||||
downloadETA->setVisible(true);
|
downloadETA->setVisible(true);
|
||||||
downloadStatus->setVisible(true);
|
downloadStatus->setVisible(true);
|
||||||
|
|||||||
@ -151,7 +151,7 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
|||||||
|
|
||||||
downloadModelButton->setText(0, tr("CANCEL"));
|
downloadModelButton->setText(0, tr("CANCEL"));
|
||||||
|
|
||||||
downloadModelButton->setValue("Downloading...");
|
downloadModelButton->setValue(tr("Downloading..."));
|
||||||
|
|
||||||
downloadModelButton->setVisibleButton(1, false);
|
downloadModelButton->setVisibleButton(1, false);
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
|||||||
|
|
||||||
downloadModelButton->setText(1, tr("CANCEL"));
|
downloadModelButton->setText(1, tr("CANCEL"));
|
||||||
|
|
||||||
downloadModelButton->setValue("Downloading...");
|
downloadModelButton->setValue(tr("Downloading..."));
|
||||||
|
|
||||||
downloadModelButton->setVisibleButton(0, false);
|
downloadModelButton->setVisibleButton(0, false);
|
||||||
|
|
||||||
@ -346,7 +346,7 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
|||||||
params_memory.putBool("DownloadAllModels", true);
|
params_memory.putBool("DownloadAllModels", true);
|
||||||
params_memory.put("ModelDownloadProgress", "Downloading...");
|
params_memory.put("ModelDownloadProgress", "Downloading...");
|
||||||
|
|
||||||
downloadModelButton->setValue("Downloading...");
|
downloadModelButton->setValue(tr("Downloading..."));
|
||||||
|
|
||||||
allModelsDownloading = true;
|
allModelsDownloading = true;
|
||||||
}
|
}
|
||||||
@ -422,7 +422,7 @@ void FrogPilotModelPanel::showEvent(QShowEvent *event) {
|
|||||||
downloadModelButton->setEnabledButtons(0, !allModelsDownloaded && !allModelsDownloading && !cancellingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
downloadModelButton->setEnabledButtons(0, !allModelsDownloaded && !allModelsDownloading && !cancellingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
||||||
downloadModelButton->setEnabledButtons(1, !allModelsDownloaded && !modelDownloading && !cancellingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
downloadModelButton->setEnabledButtons(1, !allModelsDownloaded && !modelDownloading && !cancellingDownload && !updatingTinygrad && fs.frogpilot_scene.online && parked);
|
||||||
|
|
||||||
downloadModelButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : "Not parked") : tr("Offline..."));
|
downloadModelButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : tr("Not parked")) : tr("Offline..."));
|
||||||
|
|
||||||
updateTinygradButton->setEnabled(!modelDownloading && !cancellingDownload && fs.frogpilot_scene.online && parked && tinygradUpdate);
|
updateTinygradButton->setEnabled(!modelDownloading && !cancellingDownload && fs.frogpilot_scene.online && parked && tinygradUpdate);
|
||||||
updateTinygradButton->setValue(tinygradUpdate ? tr("Update available!") : tr("Up to date!"));
|
updateTinygradButton->setValue(tinygradUpdate ? tr("Update available!") : tr("Up to date!"));
|
||||||
@ -443,8 +443,26 @@ void FrogPilotModelPanel::updateState(const UIState &s, const FrogPilotUIState &
|
|||||||
QString progress = QString::fromStdString(params_memory.get("ModelDownloadProgress"));
|
QString progress = QString::fromStdString(params_memory.get("ModelDownloadProgress"));
|
||||||
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|missing|offline", QRegularExpression::CaseInsensitiveOption));
|
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|missing|offline", QRegularExpression::CaseInsensitiveOption));
|
||||||
|
|
||||||
if (progress != "Downloading...") {
|
{
|
||||||
downloadModelButton->setValue(progress);
|
QString translatedProgress;
|
||||||
|
if (progress == "Downloading...") {
|
||||||
|
translatedProgress = tr("Downloading...");
|
||||||
|
} else if (progress == "Downloaded!") {
|
||||||
|
translatedProgress = tr("Downloaded!");
|
||||||
|
} else if (progress == "All models downloaded!") {
|
||||||
|
translatedProgress = tr("All models downloaded!");
|
||||||
|
} else if (progress.contains("cancelled", Qt::CaseInsensitive)) {
|
||||||
|
translatedProgress = tr("Download cancelled...");
|
||||||
|
} else if (progress.contains("failed", Qt::CaseInsensitive)) {
|
||||||
|
translatedProgress = tr("Download failed...");
|
||||||
|
} else if (progress.contains("offline", Qt::CaseInsensitive)) {
|
||||||
|
translatedProgress = tr("GitHub and GitLab are offline...");
|
||||||
|
} else if (progress == "Repository unavailable") {
|
||||||
|
translatedProgress = tr("Repository unavailable");
|
||||||
|
} else {
|
||||||
|
translatedProgress = progress;
|
||||||
|
}
|
||||||
|
downloadModelButton->setValue(translatedProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progress == "All models downloaded!" || progress == "Downloaded!" && !allModelsDownloading || downloadFailed) {
|
if (progress == "All models downloaded!" || progress == "Downloaded!" && !allModelsDownloading || downloadFailed) {
|
||||||
@ -473,15 +491,33 @@ void FrogPilotModelPanel::updateState(const UIState &s, const FrogPilotUIState &
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
downloadModelButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : "Not parked") : tr("Offline..."));
|
downloadModelButton->setValue(fs.frogpilot_scene.online ? (parked ? "" : tr("Not parked")) : tr("Offline..."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updatingTinygrad) {
|
if (updatingTinygrad) {
|
||||||
QString progress = QString::fromStdString(params_memory.get("ModelDownloadProgress"));
|
QString progress = QString::fromStdString(params_memory.get("ModelDownloadProgress"));
|
||||||
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|missing|offline", QRegularExpression::CaseInsensitiveOption));
|
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|missing|offline", QRegularExpression::CaseInsensitiveOption));
|
||||||
|
|
||||||
if (progress != "Downloading...") {
|
{
|
||||||
updateTinygradButton->setValue(progress);
|
QString translatedProgress;
|
||||||
|
if (progress == "Downloading...") {
|
||||||
|
translatedProgress = tr("Downloading...");
|
||||||
|
} else if (progress == "Downloaded!") {
|
||||||
|
translatedProgress = tr("Downloaded!");
|
||||||
|
} else if (progress == "All models downloaded!") {
|
||||||
|
translatedProgress = tr("All models downloaded!");
|
||||||
|
} else if (progress.contains("cancelled", Qt::CaseInsensitive)) {
|
||||||
|
translatedProgress = tr("Download cancelled...");
|
||||||
|
} else if (progress.contains("failed", Qt::CaseInsensitive)) {
|
||||||
|
translatedProgress = tr("Download failed...");
|
||||||
|
} else if (progress.contains("offline", Qt::CaseInsensitive)) {
|
||||||
|
translatedProgress = tr("GitHub and GitLab are offline...");
|
||||||
|
} else if (progress == "Repository unavailable") {
|
||||||
|
translatedProgress = tr("Repository unavailable");
|
||||||
|
} else {
|
||||||
|
translatedProgress = progress;
|
||||||
|
}
|
||||||
|
updateTinygradButton->setValue(translatedProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progress == "Updated!" && updatingTinygrad || downloadFailed) {
|
if (progress == "Updated!" && updatingTinygrad || downloadFailed) {
|
||||||
@ -493,7 +529,7 @@ void FrogPilotModelPanel::updateState(const UIState &s, const FrogPilotUIState &
|
|||||||
if (modelDownloading) {
|
if (modelDownloading) {
|
||||||
downloadModelButton->setText(1, tr("CANCEL"));
|
downloadModelButton->setText(1, tr("CANCEL"));
|
||||||
|
|
||||||
downloadModelButton->setValue("Downloading...");
|
downloadModelButton->setValue(tr("Downloading..."));
|
||||||
|
|
||||||
downloadModelButton->setVisibleButton(0, false);
|
downloadModelButton->setVisibleButton(0, false);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#include "frogpilot/ui/qt/offroad/navigation_settings.h"
|
#include "frogpilot/ui/qt/offroad/navigation_settings.h"
|
||||||
|
|
||||||
FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||||
|
networkManager = new QNetworkAccessManager(this);
|
||||||
|
|
||||||
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
QJsonObject shownDescriptions = QJsonDocument::fromJson(QString::fromStdString(params.get("ShownToggleDescriptions")).toUtf8()).object();
|
||||||
QString className = this->metaObject()->className();
|
QString className = this->metaObject()->className();
|
||||||
|
|
||||||
@ -25,6 +27,9 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
|
|||||||
QObject::connect(searchInput, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
QObject::connect(searchInput, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||||
amapKeyControl1->setVisible(id == 1);
|
amapKeyControl1->setVisible(id == 1);
|
||||||
amapKeyControl2->setVisible(id == 1);
|
amapKeyControl2->setVisible(id == 1);
|
||||||
|
publicMapboxKeyControl->setVisible(id == 0);
|
||||||
|
secretMapboxKeyControl->setVisible(id == 0);
|
||||||
|
setupButton->setVisible(id == 0);
|
||||||
|
|
||||||
params.putInt("SearchInput", id);
|
params.putInt("SearchInput", id);
|
||||||
|
|
||||||
@ -36,8 +41,107 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
|
|||||||
createKeyControl(amapKeyControl1, tr("Amap Key #1"), "AMapKey1", "", 39, settingsList);
|
createKeyControl(amapKeyControl1, tr("Amap Key #1"), "AMapKey1", "", 39, settingsList);
|
||||||
createKeyControl(amapKeyControl2, tr("Amap Key #2"), "AMapKey2", "", 39, settingsList);
|
createKeyControl(amapKeyControl2, tr("Amap Key #2"), "AMapKey2", "", 39, settingsList);
|
||||||
|
|
||||||
createKeyControl(publicMapboxKeyControl, tr("Public Mapbox Key"), "MapboxPublicKey", "pk.", 80, settingsList);
|
publicMapboxKeyControl = new FrogPilotButtonsControl(tr("Public Mapbox Key"), tr("<b>Manage your Public Mapbox Key.</b>"), "", {tr("ADD"), tr("TEST")});
|
||||||
createKeyControl(secretMapboxKeyControl, tr("Secret Mapbox Key"), "MapboxSecretKey", "sk.", 80, settingsList);
|
QObject::connect(publicMapboxKeyControl, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||||
|
if (id == 0) {
|
||||||
|
if (mapboxPublicKeySet) {
|
||||||
|
if (FrogPilotConfirmationDialog::yesorno(tr("Remove your Public Mapbox Key?"), this)) {
|
||||||
|
params.remove("MapboxPublicKey");
|
||||||
|
params_cache.remove("MapboxPublicKey");
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QString key = InputDialog::getText(tr("Enter your Public Mapbox Key"), this).trimmed();
|
||||||
|
if (!key.isEmpty()) {
|
||||||
|
if (!key.startsWith("pk.")) {
|
||||||
|
key = "pk." + key;
|
||||||
|
}
|
||||||
|
if (key.length() >= 80) {
|
||||||
|
params.put("MapboxPublicKey", key.toStdString());
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
} else {
|
||||||
|
ConfirmationDialog::alert(tr("Inputted key is invalid or too short!"), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
publicMapboxKeyControl->setValue(tr("Testing..."));
|
||||||
|
|
||||||
|
QString key = QString::fromStdString(params.get("MapboxPublicKey"));
|
||||||
|
QString url = QString("https://api.mapbox.com/geocoding/v5/mapbox.places/mapbox.json?access_token=%1").arg(key);
|
||||||
|
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
QNetworkReply *reply = networkManager->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, [=]() {
|
||||||
|
publicMapboxKeyControl->setValue("");
|
||||||
|
|
||||||
|
QString message;
|
||||||
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
|
message = tr("Key is valid!");
|
||||||
|
} else if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 401) {
|
||||||
|
message = tr("Key is invalid!");
|
||||||
|
} else {
|
||||||
|
message = tr("An error occurred: %1").arg(reply->errorString());
|
||||||
|
}
|
||||||
|
ConfirmationDialog::alert(message, this);
|
||||||
|
reply->deleteLater();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
settingsList->addItem(publicMapboxKeyControl);
|
||||||
|
|
||||||
|
secretMapboxKeyControl = new FrogPilotButtonsControl(tr("Secret Mapbox Key"), tr("<b>Manage your Secret Mapbox Key.</b>"), "", {tr("ADD"), tr("TEST")});
|
||||||
|
QObject::connect(secretMapboxKeyControl, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||||
|
if (id == 0) {
|
||||||
|
if (mapboxSecretKeySet) {
|
||||||
|
if (FrogPilotConfirmationDialog::yesorno(tr("Remove your Secret Mapbox Key?"), this)) {
|
||||||
|
params.remove("MapboxSecretKey");
|
||||||
|
params_cache.remove("MapboxSecretKey");
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QString key = InputDialog::getText(tr("Enter your Secret Mapbox Key"), this).trimmed();
|
||||||
|
if (!key.isEmpty()) {
|
||||||
|
if (!key.startsWith("sk.")) {
|
||||||
|
key = "sk." + key;
|
||||||
|
}
|
||||||
|
if (key.length() >= 80) {
|
||||||
|
params.put("MapboxSecretKey", key.toStdString());
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
} else {
|
||||||
|
ConfirmationDialog::alert(tr("Inputted key is invalid or too short!"), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
secretMapboxKeyControl->setValue(tr("Testing..."));
|
||||||
|
|
||||||
|
QString key = QString::fromStdString(params.get("MapboxSecretKey"));
|
||||||
|
QString url = QString("https://api.mapbox.com/directions/v5/mapbox/driving/-73.989,40.733;-74,40.733?access_token=%1").arg(key);
|
||||||
|
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
QNetworkReply *reply = networkManager->get(request);
|
||||||
|
connect(reply, &QNetworkReply::finished, [=]() {
|
||||||
|
secretMapboxKeyControl->setValue("");
|
||||||
|
|
||||||
|
QString message;
|
||||||
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
|
message = tr("Key is valid!");
|
||||||
|
} else if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 401) {
|
||||||
|
message = tr("Key is invalid!");
|
||||||
|
} else {
|
||||||
|
message = tr("An error occurred: %1").arg(reply->errorString());
|
||||||
|
}
|
||||||
|
ConfirmationDialog::alert(message, this);
|
||||||
|
reply->deleteLater();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
settingsList->addItem(secretMapboxKeyControl);
|
||||||
|
|
||||||
setupButton = new ButtonControl(tr("Mapbox Setup Instructions"), tr("VIEW"), tr("<b>Instructions on how to set up Mapbox</b> for \"Primeless Navigation\"."), this);
|
setupButton = new ButtonControl(tr("Mapbox Setup Instructions"), tr("VIEW"), tr("<b>Instructions on how to set up Mapbox</b> for \"Primeless Navigation\"."), this);
|
||||||
QObject::connect(setupButton, &ButtonControl::clicked, [this]() {
|
QObject::connect(setupButton, &ButtonControl::clicked, [this]() {
|
||||||
@ -179,6 +283,9 @@ void FrogPilotNavigationPanel::showEvent(QShowEvent *event) {
|
|||||||
|
|
||||||
amapKeyControl1->setVisible(selectedSearchInput == 1);
|
amapKeyControl1->setVisible(selectedSearchInput == 1);
|
||||||
amapKeyControl2->setVisible(selectedSearchInput == 1);
|
amapKeyControl2->setVisible(selectedSearchInput == 1);
|
||||||
|
publicMapboxKeyControl->setVisible(selectedSearchInput == 0);
|
||||||
|
secretMapboxKeyControl->setVisible(selectedSearchInput == 0);
|
||||||
|
setupButton->setVisible(selectedSearchInput == 0);
|
||||||
|
|
||||||
updateSpeedLimitsToggle->setVisibleButton(0, updatingLimits);
|
updateSpeedLimitsToggle->setVisibleButton(0, updatingLimits);
|
||||||
updateSpeedLimitsToggle->setVisibleButton(1, !updatingLimits);
|
updateSpeedLimitsToggle->setVisibleButton(1, !updatingLimits);
|
||||||
@ -245,14 +352,18 @@ void FrogPilotNavigationPanel::createKeyControl(ButtonControl *&control, const Q
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FrogPilotNavigationPanel::updateButtons() {
|
void FrogPilotNavigationPanel::updateButtons() {
|
||||||
|
FrogPilotUIState &fs = *frogpilotUIState();
|
||||||
|
|
||||||
amapKeyControl1->setText(params.get("AMapKey1").empty() ? tr("ADD") : tr("REMOVE"));
|
amapKeyControl1->setText(params.get("AMapKey1").empty() ? tr("ADD") : tr("REMOVE"));
|
||||||
amapKeyControl2->setText(params.get("AMapKey2").empty() ? tr("ADD") : tr("REMOVE"));
|
amapKeyControl2->setText(params.get("AMapKey2").empty() ? tr("ADD") : tr("REMOVE"));
|
||||||
|
|
||||||
mapboxPublicKeySet = QString::fromStdString(params.get("MapboxPublicKey")).startsWith("pk");
|
mapboxPublicKeySet = QString::fromStdString(params.get("MapboxPublicKey")).startsWith("pk");
|
||||||
mapboxSecretKeySet = QString::fromStdString(params.get("MapboxSecretKey")).startsWith("sk");
|
mapboxSecretKeySet = QString::fromStdString(params.get("MapboxSecretKey")).startsWith("sk");
|
||||||
|
|
||||||
publicMapboxKeyControl->setText(mapboxPublicKeySet ? tr("REMOVE") : tr("ADD"));
|
publicMapboxKeyControl->setText(0, mapboxPublicKeySet ? tr("REMOVE") : tr("ADD"));
|
||||||
secretMapboxKeyControl->setText(mapboxSecretKeySet ? tr("REMOVE") : tr("ADD"));
|
publicMapboxKeyControl->setVisibleButton(1, mapboxPublicKeySet && fs.frogpilot_scene.online);
|
||||||
|
secretMapboxKeyControl->setText(0, mapboxSecretKeySet ? tr("REMOVE") : tr("ADD"));
|
||||||
|
secretMapboxKeyControl->setVisibleButton(1, mapboxSecretKeySet && fs.frogpilot_scene.online);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrogPilotNavigationPanel::updateState(const UIState &s, const FrogPilotUIState &fs) {
|
void FrogPilotNavigationPanel::updateState(const UIState &s, const FrogPilotUIState &fs) {
|
||||||
|
|||||||
@ -31,8 +31,8 @@ private:
|
|||||||
|
|
||||||
ButtonControl *amapKeyControl1;
|
ButtonControl *amapKeyControl1;
|
||||||
ButtonControl *amapKeyControl2;
|
ButtonControl *amapKeyControl2;
|
||||||
ButtonControl *publicMapboxKeyControl;
|
FrogPilotButtonsControl *publicMapboxKeyControl;
|
||||||
ButtonControl *secretMapboxKeyControl;
|
FrogPilotButtonsControl *secretMapboxKeyControl;
|
||||||
ButtonControl *setupButton;
|
ButtonControl *setupButton;
|
||||||
|
|
||||||
FrogPilotButtonControl *updateSpeedLimitsToggle;
|
FrogPilotButtonControl *updateSpeedLimitsToggle;
|
||||||
@ -49,5 +49,7 @@ private:
|
|||||||
|
|
||||||
QLabel *imageLabel;
|
QLabel *imageLabel;
|
||||||
|
|
||||||
|
QNetworkAccessManager *networkManager;
|
||||||
|
|
||||||
QStackedLayout *primelessLayout;
|
QStackedLayout *primelessLayout;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -288,7 +288,7 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
|||||||
|
|
||||||
downloadThemeAsset(colorSchemeToDownload, "ColorToDownload", "DownloadableColors", params, params_memory);
|
downloadThemeAsset(colorSchemeToDownload, "ColorToDownload", "DownloadableColors", params, params_memory);
|
||||||
|
|
||||||
downloadStatusLabel->setText("Downloading...");
|
downloadStatusLabel->setText(tr("Downloading..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (id == 2) {
|
} else if (id == 2) {
|
||||||
@ -340,7 +340,7 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
|||||||
|
|
||||||
downloadThemeAsset(distanceIconPackToDownload, "DistanceIconToDownload", "DownloadableDistanceIcons", params, params_memory);
|
downloadThemeAsset(distanceIconPackToDownload, "DistanceIconToDownload", "DownloadableDistanceIcons", params, params_memory);
|
||||||
|
|
||||||
downloadStatusLabel->setText("Downloading...");
|
downloadStatusLabel->setText(tr("Downloading..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (id == 2) {
|
} else if (id == 2) {
|
||||||
@ -392,7 +392,7 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
|||||||
|
|
||||||
downloadThemeAsset(iconPackToDownload, "IconToDownload", "DownloadableIcons", params, params_memory);
|
downloadThemeAsset(iconPackToDownload, "IconToDownload", "DownloadableIcons", params, params_memory);
|
||||||
|
|
||||||
downloadStatusLabel->setText("Downloading...");
|
downloadStatusLabel->setText(tr("Downloading..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (id == 2) {
|
} else if (id == 2) {
|
||||||
@ -444,7 +444,7 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
|||||||
|
|
||||||
downloadThemeAsset(signalAnimationToDownload, "SignalToDownload", "DownloadableSignals", params, params_memory);
|
downloadThemeAsset(signalAnimationToDownload, "SignalToDownload", "DownloadableSignals", params, params_memory);
|
||||||
|
|
||||||
downloadStatusLabel->setText("Downloading...");
|
downloadStatusLabel->setText(tr("Downloading..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (id == 2) {
|
} else if (id == 2) {
|
||||||
@ -496,7 +496,7 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
|||||||
|
|
||||||
downloadThemeAsset(soundPackToDownload, "SoundToDownload", "DownloadableSounds", params, params_memory);
|
downloadThemeAsset(soundPackToDownload, "SoundToDownload", "DownloadableSounds", params, params_memory);
|
||||||
|
|
||||||
downloadStatusLabel->setText("Downloading...");
|
downloadStatusLabel->setText(tr("Downloading..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (id == 2) {
|
} else if (id == 2) {
|
||||||
@ -548,7 +548,7 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
|||||||
|
|
||||||
downloadThemeAsset(wheelToDownload, "WheelToDownload", "DownloadableWheels", params, params_memory);
|
downloadThemeAsset(wheelToDownload, "WheelToDownload", "DownloadableWheels", params, params_memory);
|
||||||
|
|
||||||
downloadStatusLabel->setText("Downloading...");
|
downloadStatusLabel->setText(tr("Downloading..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (id == 2) {
|
} else if (id == 2) {
|
||||||
@ -566,7 +566,7 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
|
|||||||
manageWheelIconsButton->setValue(getThemeName(param.toStdString(), params));
|
manageWheelIconsButton->setValue(getThemeName(param.toStdString(), params));
|
||||||
themeToggle = manageWheelIconsButton;
|
themeToggle = manageWheelIconsButton;
|
||||||
} else if (param == "DownloadStatusLabel") {
|
} else if (param == "DownloadStatusLabel") {
|
||||||
downloadStatusLabel = new LabelControl(title, "Idle");
|
downloadStatusLabel = new LabelControl(title, tr("Idle"));
|
||||||
themeToggle = downloadStatusLabel;
|
themeToggle = downloadStatusLabel;
|
||||||
} else if (param == "StartupAlert") {
|
} else if (param == "StartupAlert") {
|
||||||
FrogPilotButtonsControl *startupAlertButton = new FrogPilotButtonsControl(title, desc, icon, {tr("STOCK"), tr("FROGPILOT"), tr("CUSTOM"), tr("CLEAR")}, true);
|
FrogPilotButtonsControl *startupAlertButton = new FrogPilotButtonsControl(title, desc, icon, {tr("STOCK"), tr("FROGPILOT"), tr("CUSTOM"), tr("CLEAR")}, true);
|
||||||
@ -748,7 +748,15 @@ void FrogPilotThemesPanel::updateState(const UIState &s, const FrogPilotUIState
|
|||||||
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|offline", QRegularExpression::CaseInsensitiveOption));
|
bool downloadFailed = progress.contains(QRegularExpression("cancelled|exists|failed|offline", QRegularExpression::CaseInsensitiveOption));
|
||||||
|
|
||||||
if (progress != "Downloading...") {
|
if (progress != "Downloading...") {
|
||||||
downloadStatusLabel->setText(progress);
|
static const QMap<QString, QString> progressTranslations = {
|
||||||
|
{"Unpacking theme...", tr("Unpacking theme...")},
|
||||||
|
{"Downloaded!", tr("Downloaded!")},
|
||||||
|
{"Download cancelled...", tr("Download cancelled...")},
|
||||||
|
{"Download failed...", tr("Download failed...")},
|
||||||
|
{"Repository unavailable", tr("Repository unavailable")},
|
||||||
|
{"GitHub and GitLab are offline...", tr("GitHub and GitLab are offline...")}
|
||||||
|
};
|
||||||
|
downloadStatusLabel->setText(progressTranslations.value(progress, tr("Idle")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (progress == "Downloaded!" || downloadFailed) {
|
if (progress == "Downloaded!" || downloadFailed) {
|
||||||
@ -774,7 +782,7 @@ void FrogPilotThemesPanel::updateState(const UIState &s, const FrogPilotUIState
|
|||||||
params_memory.remove("CancelThemeDownload");
|
params_memory.remove("CancelThemeDownload");
|
||||||
params_memory.remove("ThemeDownloadProgress");
|
params_memory.remove("ThemeDownloadProgress");
|
||||||
|
|
||||||
downloadStatusLabel->setText("Idle");
|
downloadStatusLabel->setText(tr("Idle"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -150,16 +150,22 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
|||||||
|
|
||||||
FrogPilotListWidget *gmList = new FrogPilotListWidget(this);
|
FrogPilotListWidget *gmList = new FrogPilotListWidget(this);
|
||||||
FrogPilotListWidget *hkgList = new FrogPilotListWidget(this);
|
FrogPilotListWidget *hkgList = new FrogPilotListWidget(this);
|
||||||
|
FrogPilotListWidget *hondaList = new FrogPilotListWidget(this);
|
||||||
|
FrogPilotListWidget *subaruList = new FrogPilotListWidget(this);
|
||||||
FrogPilotListWidget *toyotaList = new FrogPilotListWidget(this);
|
FrogPilotListWidget *toyotaList = new FrogPilotListWidget(this);
|
||||||
FrogPilotListWidget *vehicleInfoList = new FrogPilotListWidget(this);
|
FrogPilotListWidget *vehicleInfoList = new FrogPilotListWidget(this);
|
||||||
|
|
||||||
ScrollView *gmPanel = new ScrollView(gmList, this);
|
ScrollView *gmPanel = new ScrollView(gmList, this);
|
||||||
ScrollView *hkgPanel = new ScrollView(hkgList, this);
|
ScrollView *hkgPanel = new ScrollView(hkgList, this);
|
||||||
|
ScrollView *hondaPanel = new ScrollView(hondaList, this);
|
||||||
|
ScrollView *subaruPanel = new ScrollView(subaruList, this);
|
||||||
ScrollView *toyotaPanel = new ScrollView(toyotaList, this);
|
ScrollView *toyotaPanel = new ScrollView(toyotaList, this);
|
||||||
ScrollView *vehicleInfoPanel = new ScrollView(vehicleInfoList, this);
|
ScrollView *vehicleInfoPanel = new ScrollView(vehicleInfoList, this);
|
||||||
|
|
||||||
vehiclesLayout->addWidget(gmPanel);
|
vehiclesLayout->addWidget(gmPanel);
|
||||||
vehiclesLayout->addWidget(hkgPanel);
|
vehiclesLayout->addWidget(hkgPanel);
|
||||||
|
vehiclesLayout->addWidget(hondaPanel);
|
||||||
|
vehiclesLayout->addWidget(subaruPanel);
|
||||||
vehiclesLayout->addWidget(toyotaPanel);
|
vehiclesLayout->addWidget(toyotaPanel);
|
||||||
vehiclesLayout->addWidget(vehicleInfoPanel);
|
vehiclesLayout->addWidget(vehicleInfoPanel);
|
||||||
|
|
||||||
@ -173,6 +179,14 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
|||||||
{"NewLongAPI", tr("comma's New Longitudinal API"), tr("<b>comma's new gas and brake control system</b> that improves acceleration and braking but may cause issues on some Genesis/Hyundai/Kia vehicles."), ""},
|
{"NewLongAPI", tr("comma's New Longitudinal API"), tr("<b>comma's new gas and brake control system</b> that improves acceleration and braking but may cause issues on some Genesis/Hyundai/Kia vehicles."), ""},
|
||||||
{"TacoTuneHacks", tr("\"Taco Bell Run\" Torque Hack"), tr("<b>The steering torque hack from comma's 2022 \"Taco Bell Run\".</b> Designed to increase steering torque at low speeds for left and right turns."), ""},
|
{"TacoTuneHacks", tr("\"Taco Bell Run\" Torque Hack"), tr("<b>The steering torque hack from comma's 2022 \"Taco Bell Run\".</b> Designed to increase steering torque at low speeds for left and right turns."), ""},
|
||||||
|
|
||||||
|
{"HondaToggles", tr("Acura/Honda Settings"), tr("<b>FrogPilot features for Acura and Honda vehicles.</b>"), ""},
|
||||||
|
{"HondaAltTune", tr("Gentle Following"), tr("<b>Reduces jerky acceleration and braking when following a lead vehicle.</b> Ideal for stop-and-go traffic."), ""},
|
||||||
|
{"HondaMaxBrake", tr("Increased Braking Force"), tr("<b>Increases the maximum braking force for improved stopping performance.</b>"), ""},
|
||||||
|
{"HondaLowSpeedPedal", tr("Responsive Pedal at Low Speeds"), tr("<b>Improves acceleration from a standstill for a more responsive throttle feel in city driving.</b>"), ""},
|
||||||
|
|
||||||
|
{"SubaruToggles", tr("Subaru Settings"), tr("<b>FrogPilot features for Subaru vehicles.</b>"), ""},
|
||||||
|
{"SubaruSNG", tr("Stop and Go"), tr("Stop and go for supported Subaru vehicles."), ""},
|
||||||
|
|
||||||
{"ToyotaToggles", tr("Toyota/Lexus Settings"), tr("<b>FrogPilot features for Lexus and Toyota vehicles.</b>"), ""},
|
{"ToyotaToggles", tr("Toyota/Lexus Settings"), tr("<b>FrogPilot features for Lexus and Toyota vehicles.</b>"), ""},
|
||||||
{"ToyotaDoors", tr("Automatically Lock/Unlock Doors"), tr("<b>Automatically lock/unlock doors</b> when shifting in and out of drive."), ""},
|
{"ToyotaDoors", tr("Automatically Lock/Unlock Doors"), tr("<b>Automatically lock/unlock doors</b> when shifting in and out of drive."), ""},
|
||||||
{"ClusterOffset", tr("Dashboard Speed Offset"), tr("<b>The speed offset openpilot uses to match the speed on the dashboard display.</b>"), ""},
|
{"ClusterOffset", tr("Dashboard Speed Offset"), tr("<b>The speed offset openpilot uses to match the speed on the dashboard display.</b>"), ""},
|
||||||
@ -209,6 +223,22 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
|||||||
});
|
});
|
||||||
vehicleToggle = hkgButton;
|
vehicleToggle = hkgButton;
|
||||||
|
|
||||||
|
} else if (param == "HondaToggles") {
|
||||||
|
ButtonControl *hondaButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||||
|
QObject::connect(hondaButton, &ButtonControl::clicked, [vehiclesLayout, hondaPanel, this]() {
|
||||||
|
openDescriptions(forceOpenDescriptions, toggles);
|
||||||
|
vehiclesLayout->setCurrentWidget(hondaPanel);
|
||||||
|
});
|
||||||
|
vehicleToggle = hondaButton;
|
||||||
|
|
||||||
|
} else if (param == "SubaruToggles") {
|
||||||
|
ButtonControl *subaruButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||||
|
QObject::connect(subaruButton, &ButtonControl::clicked, [vehiclesLayout, subaruPanel, this]() {
|
||||||
|
openDescriptions(forceOpenDescriptions, toggles);
|
||||||
|
vehiclesLayout->setCurrentWidget(subaruPanel);
|
||||||
|
});
|
||||||
|
vehicleToggle = subaruButton;
|
||||||
|
|
||||||
} else if (param == "ToyotaToggles") {
|
} else if (param == "ToyotaToggles") {
|
||||||
ButtonControl *toyotaButton = new ButtonControl(title, tr("MANAGE"), desc);
|
ButtonControl *toyotaButton = new ButtonControl(title, tr("MANAGE"), desc);
|
||||||
QObject::connect(toyotaButton, &ButtonControl::clicked, [vehiclesLayout, toyotaPanel, this]() {
|
QObject::connect(toyotaButton, &ButtonControl::clicked, [vehiclesLayout, toyotaPanel, this]() {
|
||||||
@ -255,6 +285,10 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
|||||||
gmList->addItem(vehicleToggle);
|
gmList->addItem(vehicleToggle);
|
||||||
} else if (hkgKeys.contains(param)) {
|
} else if (hkgKeys.contains(param)) {
|
||||||
hkgList->addItem(vehicleToggle);
|
hkgList->addItem(vehicleToggle);
|
||||||
|
} else if (hondaKeys.contains(param)) {
|
||||||
|
hondaList->addItem(vehicleToggle);
|
||||||
|
} else if (subaruKeys.contains(param)) {
|
||||||
|
subaruList->addItem(vehicleToggle);
|
||||||
} else if (toyotaKeys.contains(param)) {
|
} else if (toyotaKeys.contains(param)) {
|
||||||
toyotaList->addItem(vehicleToggle);
|
toyotaList->addItem(vehicleToggle);
|
||||||
} else if (vehicleInfoKeys.contains(param)) {
|
} else if (vehicleInfoKeys.contains(param)) {
|
||||||
@ -279,11 +313,11 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
|||||||
|
|
||||||
static_cast<FrogPilotParamValueControl*>(toggles["LockDoorsTimer"])->setWarning("<b>Warning:</b> openpilot can't detect if keys are still inside the car, so ensure you have a spare key to prevent accidental lockouts!");
|
static_cast<FrogPilotParamValueControl*>(toggles["LockDoorsTimer"])->setWarning("<b>Warning:</b> openpilot can't detect if keys are still inside the car, so ensure you have a spare key to prevent accidental lockouts!");
|
||||||
|
|
||||||
QSet<QString> rebootKeys = {"NewLongAPI", "TacoTuneHacks"};
|
QSet<QString> rebootKeys = {"HondaAltTune", "NewLongAPI", "TacoTuneHacks"};
|
||||||
for (const QString &key : rebootKeys) {
|
for (const QString &key : rebootKeys) {
|
||||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [key, this](bool state) {
|
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [key, this](bool state) {
|
||||||
if (started) {
|
if (started) {
|
||||||
if (key == "TacoTuneHacks" && state) {
|
if (key == "HondaAltTune" || key == "TacoTuneHacks" && state) {
|
||||||
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
||||||
Hardware::reboot();
|
Hardware::reboot();
|
||||||
}
|
}
|
||||||
@ -367,6 +401,10 @@ void FrogPilotVehiclesPanel::updateToggles() {
|
|||||||
setVisible &= parent->isGM;
|
setVisible &= parent->isGM;
|
||||||
} else if (hkgKeys.contains(key)) {
|
} else if (hkgKeys.contains(key)) {
|
||||||
setVisible &= parent->isHKG;
|
setVisible &= parent->isHKG;
|
||||||
|
} else if (hondaKeys.contains(key)) {
|
||||||
|
setVisible &= parent->isHonda;
|
||||||
|
} else if (subaruKeys.contains(key)) {
|
||||||
|
setVisible &= parent->isSubaru;
|
||||||
} else if (toyotaKeys.contains(key)) {
|
} else if (toyotaKeys.contains(key)) {
|
||||||
setVisible &= parent->isToyota;
|
setVisible &= parent->isToyota;
|
||||||
} else if (vehicleInfoKeys.contains(key)) {
|
} else if (vehicleInfoKeys.contains(key)) {
|
||||||
@ -377,7 +415,19 @@ void FrogPilotVehiclesPanel::updateToggles() {
|
|||||||
setVisible &= parent->hasOpenpilotLongitudinal;
|
setVisible &= parent->hasOpenpilotLongitudinal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == "LockDoorsTimer") {
|
if (key == "HondaAltTune") {
|
||||||
|
setVisible &= parent->isHondaNidec;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (key == "HondaLowSpeedPedal") {
|
||||||
|
setVisible &= parent->hasPedal;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (key == "HondaMaxBrake") {
|
||||||
|
setVisible &= parent->isHondaNidec;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (key == "LockDoorsTimer") {
|
||||||
setVisible &= !parent->isC3;
|
setVisible &= !parent->isC3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,6 +435,10 @@ void FrogPilotVehiclesPanel::updateToggles() {
|
|||||||
setVisible &= !parent->hasPedal && !parent->hasSNG;
|
setVisible &= !parent->hasPedal && !parent->hasSNG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (key == "SubaruSNG") {
|
||||||
|
setVisible &= parent->hasSNG;
|
||||||
|
}
|
||||||
|
|
||||||
else if (key == "TacoTuneHacks") {
|
else if (key == "TacoTuneHacks") {
|
||||||
setVisible &= parent->isHKGCanFd;
|
setVisible &= parent->isHKGCanFd;
|
||||||
}
|
}
|
||||||
@ -400,6 +454,10 @@ void FrogPilotVehiclesPanel::updateToggles() {
|
|||||||
toggles["GMToggles"]->setVisible(true);
|
toggles["GMToggles"]->setVisible(true);
|
||||||
} else if (hkgKeys.contains(key)) {
|
} else if (hkgKeys.contains(key)) {
|
||||||
toggles["HKGToggles"]->setVisible(true);
|
toggles["HKGToggles"]->setVisible(true);
|
||||||
|
} else if (hondaKeys.contains(key)) {
|
||||||
|
toggles["HondaToggles"]->setVisible(true);
|
||||||
|
} else if (subaruKeys.contains(key)) {
|
||||||
|
toggles["SubaruToggles"]->setVisible(true);
|
||||||
} else if (toyotaKeys.contains(key)) {
|
} else if (toyotaKeys.contains(key)) {
|
||||||
toggles["ToyotaToggles"]->setVisible(true);
|
toggles["ToyotaToggles"]->setVisible(true);
|
||||||
} else if (vehicleInfoKeys.contains(key)) {
|
} else if (vehicleInfoKeys.contains(key)) {
|
||||||
|
|||||||
@ -25,7 +25,9 @@ private:
|
|||||||
|
|
||||||
QSet<QString> gmKeys = {"ExperimentalGMTune", "LongPitch", "VoltSNG"};
|
QSet<QString> gmKeys = {"ExperimentalGMTune", "LongPitch", "VoltSNG"};
|
||||||
QSet<QString> hkgKeys = {"NewLongAPI", "TacoTuneHacks"};
|
QSet<QString> hkgKeys = {"NewLongAPI", "TacoTuneHacks"};
|
||||||
QSet<QString> longitudinalKeys = {"ExperimentalGMTune", "FrogsGoMoosTweak", "LongPitch", "NewLongAPI", "SNGHack", "VoltSNG"};
|
QSet<QString> hondaKeys = {"HondaAltTune", "HondaLowSpeedPedal", "HondaMaxBrake"};
|
||||||
|
QSet<QString> longitudinalKeys = {"ExperimentalGMTune", "FrogsGoMoosTweak", "HondaAltTune", "HondaMaxBrake", "HondaLowSpeedPedal", "LongPitch", "NewLongAPI", "SNGHack", "SubaruSNG", "VoltSNG"};
|
||||||
|
QSet<QString> subaruKeys = {"SubaruSNG"};
|
||||||
QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
|
QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
|
||||||
QSet<QString> vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SDSUSupport", "SNGSupport"};
|
QSet<QString> vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SDSUSupport", "SNGSupport"};
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,10 @@ FrogPilotAnnotatedCameraWidget::FrogPilotAnnotatedCameraWidget(QWidget *parent)
|
|||||||
loadGif("../../frogpilot/assets/other_images/turn_icon.gif", cemTurnIcon, QSize(btn_size / 2, btn_size / 2), this);
|
loadGif("../../frogpilot/assets/other_images/turn_icon.gif", cemTurnIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||||
loadGif("../../frogpilot/assets/other_images/chill_mode_icon.gif", chillModeIcon, QSize(btn_size / 2, btn_size / 2), this);
|
loadGif("../../frogpilot/assets/other_images/chill_mode_icon.gif", chillModeIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||||
loadGif("../../frogpilot/assets/other_images/experimental_mode_icon.gif", experimentalModeIcon, QSize(btn_size / 2, btn_size / 2), this);
|
loadGif("../../frogpilot/assets/other_images/experimental_mode_icon.gif", experimentalModeIcon, QSize(btn_size / 2, btn_size / 2), this);
|
||||||
|
loadGif("../../frogpilot/assets/other_images/weather_clear_day.gif", weatherClearDay, QSize(btn_size / 2, btn_size / 2), this);
|
||||||
|
loadGif("../../frogpilot/assets/other_images/weather_clear_night.gif", weatherClearNight, QSize(btn_size / 2, btn_size / 2), this);
|
||||||
|
loadGif("../../frogpilot/assets/other_images/weather_rain.gif", weatherRain, QSize(btn_size / 2, btn_size / 2), this);
|
||||||
|
loadGif("../../frogpilot/assets/other_images/weather_snow.gif", weatherSnow, QSize(btn_size / 2, btn_size / 2), this);
|
||||||
|
|
||||||
QObject::connect(animationTimer, &QTimer::timeout, [this] {
|
QObject::connect(animationTimer, &QTimer::timeout, [this] {
|
||||||
animationFrameIndex = (animationFrameIndex + 1) % totalFrames;
|
animationFrameIndex = (animationFrameIndex + 1) % totalFrames;
|
||||||
@ -252,6 +256,10 @@ void FrogPilotAnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &p, UIState
|
|||||||
} else if (animationTimer->isActive()) {
|
} else if (animationTimer->isActive()) {
|
||||||
animationTimer->stop();
|
animationTimer->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!frogpilot_scene.map_open && !hideBottomIcons) {
|
||||||
|
paintWeather(p, frogpilotPlan, frogpilot_scene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrogPilotAnnotatedCameraWidget::paintAdjacentPaths(QPainter &p, const cereal::CarState::Reader &carState, const FrogPilotUIScene &frogpilot_scene, const QJsonObject &frogpilot_toggles) {
|
void FrogPilotAnnotatedCameraWidget::paintAdjacentPaths(QPainter &p, const cereal::CarState::Reader &carState, const FrogPilotUIScene &frogpilot_scene, const QJsonObject &frogpilot_toggles) {
|
||||||
@ -540,11 +548,11 @@ void FrogPilotAnnotatedCameraWidget::paintLeadMetrics(QPainter &p, bool adjacent
|
|||||||
text = QString("%1 %2 (%3) | %4 %5 | %6 %7")
|
text = QString("%1 %2 (%3) | %4 %5 | %6 %7")
|
||||||
.arg(qRound(leadDistance * distanceConversion))
|
.arg(qRound(leadDistance * distanceConversion))
|
||||||
.arg(leadDistanceUnit)
|
.arg(leadDistanceUnit)
|
||||||
.arg(QString("Desired: %1").arg(frogpilotPlan.getDesiredFollowDistance() * distanceConversion))
|
.arg(QString(tr("Desired: %1")).arg(frogpilotPlan.getDesiredFollowDistance() * distanceConversion))
|
||||||
.arg(qRound(leadSpeed * speedConversionMetrics))
|
.arg(qRound(leadSpeed * speedConversionMetrics))
|
||||||
.arg(leadSpeedUnit)
|
.arg(leadSpeedUnit)
|
||||||
.arg(QString::number(leadDistance / std::max(speed / speedConversion, 1.0f), 'f', 2))
|
.arg(QString::number(leadDistance / std::max(speed / speedConversion, 1.0f), 'f', 2))
|
||||||
.arg("s");
|
.arg(tr("s"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QFontMetrics metrics(p.font());
|
QFontMetrics metrics(p.font());
|
||||||
@ -899,7 +907,7 @@ void FrogPilotAnnotatedCameraWidget::paintStandstillTimer(QPainter &p) {
|
|||||||
|
|
||||||
p.setFont(InterFont(176, QFont::Bold));
|
p.setFont(InterFont(176, QFont::Bold));
|
||||||
{
|
{
|
||||||
QString minuteStr = (minutes == 1) ? "1 minute" : QString("%1 minutes").arg(minutes);
|
QString minuteStr = (minutes == 1) ? tr("1 minute") : QString(tr("%1 minutes")).arg(minutes);
|
||||||
QRect textRect = p.fontMetrics().boundingRect(minuteStr);
|
QRect textRect = p.fontMetrics().boundingRect(minuteStr);
|
||||||
textRect.moveCenter({rect().center().x(), 210 - textRect.height() / 2});
|
textRect.moveCenter({rect().center().x(), 210 - textRect.height() / 2});
|
||||||
p.setPen(QPen(blendedColor));
|
p.setPen(QPen(blendedColor));
|
||||||
@ -908,7 +916,7 @@ void FrogPilotAnnotatedCameraWidget::paintStandstillTimer(QPainter &p) {
|
|||||||
|
|
||||||
p.setFont(InterFont(66));
|
p.setFont(InterFont(66));
|
||||||
{
|
{
|
||||||
QString secondStr = (seconds == 1) ? "1 second" : QString("%1 seconds").arg(seconds);
|
QString secondStr = (seconds == 1) ? tr("1 second") : QString(tr("%1 seconds")).arg(seconds);
|
||||||
QRect textRect = p.fontMetrics().boundingRect(secondStr);
|
QRect textRect = p.fontMetrics().boundingRect(secondStr);
|
||||||
textRect.moveCenter({rect().center().x(), 290 - textRect.height() / 2});
|
textRect.moveCenter({rect().center().x(), 290 - textRect.height() / 2});
|
||||||
p.setPen(QPen(whiteColor()));
|
p.setPen(QPen(whiteColor()));
|
||||||
@ -972,3 +980,47 @@ void FrogPilotAnnotatedCameraWidget::paintTurnSignals(QPainter &p, const cereal:
|
|||||||
|
|
||||||
p.restore();
|
p.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FrogPilotAnnotatedCameraWidget::paintWeather(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan, FrogPilotUIScene &frogpilot_scene) {
|
||||||
|
int weatherId = frogpilotPlan.getWeatherId();
|
||||||
|
if (weatherId == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.save();
|
||||||
|
|
||||||
|
QPoint weatherIconPosition;
|
||||||
|
if (compassPosition != QPoint(0, 0)) {
|
||||||
|
weatherIconPosition = compassPosition;
|
||||||
|
weatherIconPosition.rx() += (rightHandDM ? UI_BORDER_SIZE + widget_size + UI_BORDER_SIZE : -UI_BORDER_SIZE - widget_size - UI_BORDER_SIZE) / (frogpilot_scene.map_open ? 1.25 : 1);
|
||||||
|
} else {
|
||||||
|
weatherIconPosition.rx() = rightHandDM ? UI_BORDER_SIZE + widget_size / 2 : width() - UI_BORDER_SIZE - btn_size;
|
||||||
|
if (mapButtonVisible) {
|
||||||
|
if (rightHandDM) {
|
||||||
|
weatherIconPosition.rx() += btn_size - UI_BORDER_SIZE;
|
||||||
|
} else {
|
||||||
|
weatherIconPosition.rx() -= btn_size + UI_BORDER_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
weatherIconPosition.ry() = dmIconPosition.y() - widget_size / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect weatherRect(weatherIconPosition, QSize(widget_size, widget_size));
|
||||||
|
|
||||||
|
p.setBrush(blackColor(166));
|
||||||
|
p.setPen(QPen(blackColor(), 10));
|
||||||
|
p.drawRoundedRect(weatherRect, 24, 24);
|
||||||
|
|
||||||
|
QSharedPointer<QMovie> icon = weatherClearDay;
|
||||||
|
if ((weatherId >= 200 && weatherId <= 232) || (weatherId >= 300 && weatherId <= 321) || (weatherId >= 500 && weatherId <= 531)) {
|
||||||
|
icon = weatherRain;
|
||||||
|
} else if (weatherId >= 600 && weatherId <= 622) {
|
||||||
|
icon = weatherSnow;
|
||||||
|
} else if (weatherId == 800) {
|
||||||
|
icon = frogpilotPlan.getWeatherDaytime() ? weatherClearDay : weatherClearNight;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.drawPixmap(weatherRect, icon->currentPixmap());
|
||||||
|
|
||||||
|
p.restore();
|
||||||
|
}
|
||||||
|
|||||||
@ -79,6 +79,7 @@ private:
|
|||||||
void paintStandstillTimer(QPainter &p);
|
void paintStandstillTimer(QPainter &p);
|
||||||
void paintStoppingPoint(QPainter &p, UIScene &scene, FrogPilotUIScene &frogpilot_scene, QJsonObject &frogpilot_toggles);
|
void paintStoppingPoint(QPainter &p, UIScene &scene, FrogPilotUIScene &frogpilot_scene, QJsonObject &frogpilot_toggles);
|
||||||
void paintTurnSignals(QPainter &p, const cereal::CarState::Reader &carState);
|
void paintTurnSignals(QPainter &p, const cereal::CarState::Reader &carState);
|
||||||
|
void paintWeather(QPainter &p, const cereal::FrogPilotPlan::Reader &frogpilotPlan, FrogPilotUIScene &frogpilot_scene);
|
||||||
void updateSignals();
|
void updateSignals();
|
||||||
|
|
||||||
int animationFrameIndex;
|
int animationFrameIndex;
|
||||||
@ -123,6 +124,10 @@ private:
|
|||||||
QSharedPointer<QMovie> cemTurnIcon;
|
QSharedPointer<QMovie> cemTurnIcon;
|
||||||
QSharedPointer<QMovie> chillModeIcon;
|
QSharedPointer<QMovie> chillModeIcon;
|
||||||
QSharedPointer<QMovie> experimentalModeIcon;
|
QSharedPointer<QMovie> experimentalModeIcon;
|
||||||
|
QSharedPointer<QMovie> weatherClearDay;
|
||||||
|
QSharedPointer<QMovie> weatherClearNight;
|
||||||
|
QSharedPointer<QMovie> weatherRain;
|
||||||
|
QSharedPointer<QMovie> weatherSnow;
|
||||||
|
|
||||||
QString cscSpeedStr;
|
QString cscSpeedStr;
|
||||||
|
|
||||||
|
|||||||
@ -92,7 +92,7 @@ void FrogPilotOnroadWindow::paintFPS(QPainter &p, const QRect &rect) {
|
|||||||
minFPS = std::min(minFPS, fps);
|
minFPS = std::min(minFPS, fps);
|
||||||
maxFPS = std::max(maxFPS, fps);
|
maxFPS = std::max(maxFPS, fps);
|
||||||
|
|
||||||
QString fpsDisplayString = QString("FPS: %1 | Min: %2 | Max: %3 | Avg: %4")
|
QString fpsDisplayString = QString(tr("FPS: %1 | Min: %2 | Max: %3 | Avg: %4"))
|
||||||
.arg(qRound(fps))
|
.arg(qRound(fps))
|
||||||
.arg(qRound(minFPS))
|
.arg(qRound(minFPS))
|
||||||
.arg(qRound(maxFPS))
|
.arg(qRound(maxFPS))
|
||||||
|
|||||||
@ -15,8 +15,8 @@ DriveStats::DriveStats(QWidget *parent) : QFrame(parent) {
|
|||||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||||
main_layout->setContentsMargins(50, 25, 50, 20);
|
main_layout->setContentsMargins(50, 25, 50, 20);
|
||||||
|
|
||||||
addStatsLayouts(tr(konik ? "ALL TIME (KONIK)" : "ALL TIME"), all);
|
addStatsLayouts(konik ? tr("ALL TIME (KONIK)") : tr("ALL TIME"), all);
|
||||||
addStatsLayouts(tr(konik ? "PAST WEEK (KONIK)" : "PAST WEEK"), week);
|
addStatsLayouts(konik ? tr("PAST WEEK (KONIK)") : tr("PAST WEEK"), week);
|
||||||
addStatsLayouts(tr("FROGPILOT"), frogPilot, true);
|
addStatsLayouts(tr("FROGPILOT"), frogPilot, true);
|
||||||
|
|
||||||
std::optional<QString> dongleId = getDongleId();
|
std::optional<QString> dongleId = getDongleId();
|
||||||
|
|||||||
225
frogpilot/ui/qt/widgets/drive_summary.cc
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||||
|
|
||||||
|
#include "frogpilot/ui/qt/widgets/drive_summary.h"
|
||||||
|
|
||||||
|
FrogPilotDriveSummary::FrogPilotDriveSummary(QWidget *parent, bool randomEvents) : QFrame(parent), displayRandomEvents(randomEvents) {
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||||
|
mainLayout->setContentsMargins(20, 20, 20, 20);
|
||||||
|
mainLayout->setSpacing(15);
|
||||||
|
|
||||||
|
titleLabel = new QLabel(randomEvents ? tr("Random Events Summary") : tr("Drive Summary"), this);
|
||||||
|
titleLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
titleLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||||
|
titleLabel->setStyleSheet(R"(
|
||||||
|
QLabel {
|
||||||
|
background-color: #444444;
|
||||||
|
border-radius: 12px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-size: 50px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 12px 28px;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
titleLabel->setMaximumHeight(titleLabel->sizeHint().height());
|
||||||
|
|
||||||
|
mainLayout->addWidget(titleLabel);
|
||||||
|
mainLayout->addSpacing(10);
|
||||||
|
|
||||||
|
QWidget *containerWidget = new QWidget(this);
|
||||||
|
QVBoxLayout *listLayout = new QVBoxLayout(containerWidget);
|
||||||
|
listLayout->setAlignment(Qt::AlignTop);
|
||||||
|
listLayout->setSpacing(20);
|
||||||
|
|
||||||
|
if (displayRandomEvents) {
|
||||||
|
randomEventsMap.insert("accel30", tr("UwUs"));
|
||||||
|
randomEventsMap.insert("accel35", tr("Loch Ness Encounters"));
|
||||||
|
randomEventsMap.insert("accel40", tr("Visits to 1955"));
|
||||||
|
randomEventsMap.insert("dejaVuCurve", tr("Deja Vu Moments"));
|
||||||
|
randomEventsMap.insert("firefoxSteerSaturated", tr("Internet Explorer Weeeeeeees"));
|
||||||
|
randomEventsMap.insert("hal9000", tr("HAL 9000 Denials"));
|
||||||
|
randomEventsMap.insert("openpilotCrashedRandomEvent", tr("openpilot Crashes"));
|
||||||
|
randomEventsMap.insert("thisIsFineSteerSaturated", tr("This Is Fine Moments"));
|
||||||
|
randomEventsMap.insert("toBeContinued", tr("To Be Continued Moments"));
|
||||||
|
randomEventsMap.insert("vCruise69", tr("Noices"));
|
||||||
|
randomEventsMap.insert("yourFrogTriedToKillMe", tr("Attempted Frog Murders"));
|
||||||
|
randomEventsMap.insert("youveGotMail", tr("Total Mail Received"));
|
||||||
|
} else {
|
||||||
|
listLayout->addWidget(createStatBox(tr("% of Drive With openpilot Engaged"), &engagementValue, this));
|
||||||
|
listLayout->addWidget(createStatBox(tr("Drive Distance"), &frogPilotMetersValue, this));
|
||||||
|
listLayout->addWidget(createStatBox(tr("Drive Time"), &trackedTimeValue, this));
|
||||||
|
listLayout->addWidget(createStatBox(tr("% of Drive In \"Experimental Mode\""), &experimentalModeTimeValue, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayRandomEvents) {
|
||||||
|
eventsListLayout = listLayout;
|
||||||
|
mainLayout->addWidget(new ScrollView(containerWidget, this), 1);
|
||||||
|
} else {
|
||||||
|
mainLayout->addWidget(containerWidget, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
setStyleSheet(R"(
|
||||||
|
QFrame {
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
QObject::connect(device(), &Device::interactiveTimeout, [this]() {
|
||||||
|
emit panelClosed();
|
||||||
|
});
|
||||||
|
QObject::connect(uiState(), &UIState::offroadTransition, [this](bool offroad) {
|
||||||
|
if (!offroad) {
|
||||||
|
previousStats = QJsonDocument::fromJson(QString::fromStdString(params.get("FrogPilotStats")).toUtf8()).object();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotDriveSummary::mousePressEvent(QMouseEvent *e) {
|
||||||
|
emit panelClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotDriveSummary::showEvent(QShowEvent *event) {
|
||||||
|
bool isMetric = params.getBool("IsMetric");
|
||||||
|
|
||||||
|
QJsonObject currentStats = QJsonDocument::fromJson(QString::fromStdString(params.get("FrogPilotStats")).toUtf8()).object();
|
||||||
|
|
||||||
|
if (displayRandomEvents) {
|
||||||
|
QJsonObject currentRandomEvents = currentStats.value("RandomEvents").toObject();
|
||||||
|
QJsonObject previousRandomEvents = previousStats.value("RandomEvents").toObject();
|
||||||
|
|
||||||
|
QList<QPair<QString, int>> eventsList;
|
||||||
|
for (QMap<QString, QString>::const_iterator it = randomEventsMap.constBegin(); it != randomEventsMap.constEnd(); ++it) {
|
||||||
|
int currentValue = currentRandomEvents.value(it.key()).toInt();
|
||||||
|
int previousValue = previousRandomEvents.value(it.key()).toInt();
|
||||||
|
int diffValue = currentValue - previousValue;
|
||||||
|
|
||||||
|
if (diffValue > 0) {
|
||||||
|
eventsList.append(qMakePair(it.value(), diffValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(eventsList.begin(), eventsList.end(), [](const QPair<QString, int> &a, const QPair<QString, int> &b) {
|
||||||
|
if (a.second != b.second) {
|
||||||
|
return a.second > b.second;
|
||||||
|
} else {
|
||||||
|
return a.first.localeAwareCompare(b.first) < 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QLayoutItem *child;
|
||||||
|
while ((child = eventsListLayout->takeAt(0)) != nullptr) {
|
||||||
|
if (QWidget *widget = child->widget()) {
|
||||||
|
widget->deleteLater();
|
||||||
|
}
|
||||||
|
delete child;
|
||||||
|
}
|
||||||
|
randomEventLabels.clear();
|
||||||
|
|
||||||
|
if (eventsList.isEmpty()) {
|
||||||
|
eventsListLayout->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
QLabel *noEventsLabel = new QLabel(tr("No Random Events Played!"), this);
|
||||||
|
noEventsLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
noEventsLabel->setStyleSheet(R"(
|
||||||
|
QLabel {
|
||||||
|
font-size: 50px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
eventsListLayout->addWidget(noEventsLabel);
|
||||||
|
} else {
|
||||||
|
eventsListLayout->setAlignment(Qt::AlignTop);
|
||||||
|
|
||||||
|
for (QList<QPair<QString, int>>::const_iterator it = eventsList.constBegin(); it != eventsList.constEnd(); ++it) {
|
||||||
|
QLabel *valueLabel = nullptr;
|
||||||
|
eventsListLayout->addWidget(createStatBox(it->first, &valueLabel, this));
|
||||||
|
randomEventLabels.insert(it->first, valueLabel);
|
||||||
|
valueLabel->setText(QLocale().toString(it->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::function<double(const QString &)> diffDouble = [currentStats, this](const QString &key) -> double {
|
||||||
|
return currentStats.value(key).toDouble() - previousStats.value(key).toDouble();
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<QString(double)> formatDistance = [&](double meters) {
|
||||||
|
double value;
|
||||||
|
QString unit;
|
||||||
|
if (isMetric) {
|
||||||
|
value = meters / 1000.0;
|
||||||
|
unit = (qRound(value) == 1) ? tr(" kilometer") : tr(" kilometers");
|
||||||
|
} else {
|
||||||
|
value = meters * METER_TO_MILE;
|
||||||
|
unit = (qRound(value) == 1) ? tr(" mile") : tr(" miles");
|
||||||
|
}
|
||||||
|
return QLocale().toString(qRound(value)) + unit;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::function<QString(int)> formatTime = [&](int seconds) {
|
||||||
|
static int secondsInDay = 60 * 60 * 24;
|
||||||
|
static int secondsInHour = 60 * 60;
|
||||||
|
|
||||||
|
int days = seconds / secondsInDay;
|
||||||
|
int hours = (seconds % secondsInDay) / secondsInHour;
|
||||||
|
int minutes = (seconds % secondsInHour) / 60;
|
||||||
|
|
||||||
|
QString result;
|
||||||
|
if (days > 0) result += QLocale().toString(days) + (days == 1 ? tr(" day ") : tr(" days "));
|
||||||
|
if (hours > 0 || days > 0) result += QLocale().toString(hours) + (hours == 1 ? tr(" hour ") : tr(" hours "));
|
||||||
|
result += QLocale().toString(minutes) + (minutes == 1 ? tr(" minute") : tr(" minutes"));
|
||||||
|
return result.trimmed();
|
||||||
|
};
|
||||||
|
|
||||||
|
int engagedTime = diffDouble("AOLTime") + diffDouble("LongitudinalTime");
|
||||||
|
int experimentalTime = diffDouble("ExperimentalModeTime");
|
||||||
|
int trackedTime = diffDouble("TrackedTime");
|
||||||
|
|
||||||
|
engagementValue->setText(QLocale().toString((trackedTime > 0) ? (engagedTime * 100 / trackedTime) : 0) + "%");
|
||||||
|
experimentalModeTimeValue->setText(QLocale().toString((trackedTime > 0) ? (experimentalTime * 100 / trackedTime) : 0) + "%");
|
||||||
|
frogPilotMetersValue->setText(formatDistance(diffDouble("FrogPilotMeters")));
|
||||||
|
trackedTimeValue->setText(formatTime(trackedTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotDriveSummary::hideEvent(QHideEvent *event) {
|
||||||
|
emit panelClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *FrogPilotDriveSummary::createStatBox(const QString &title, QLabel **valueLabel, QWidget *parent) {
|
||||||
|
QWidget *box = new QWidget(parent);
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout(box);
|
||||||
|
layout->setAlignment(Qt::AlignCenter);
|
||||||
|
layout->setContentsMargins(10, 10, 10, 10);
|
||||||
|
layout->setSpacing(8);
|
||||||
|
|
||||||
|
QLabel *statTitleLabel = new QLabel(title, box);
|
||||||
|
statTitleLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
statTitleLabel->setStyleSheet(R"(
|
||||||
|
QLabel {
|
||||||
|
color: #AAAAAA;
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
QLabel *value = new QLabel("-", box);
|
||||||
|
value->setAlignment(Qt::AlignCenter);
|
||||||
|
value->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||||
|
value->setStyleSheet(R"(
|
||||||
|
QLabel {
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-size: 75px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
*valueLabel = value;
|
||||||
|
|
||||||
|
layout->addWidget(statTitleLabel);
|
||||||
|
layout->addWidget(value);
|
||||||
|
|
||||||
|
return box;
|
||||||
|
}
|
||||||
39
frogpilot/ui/qt/widgets/drive_summary.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
class FrogPilotDriveSummary : public QFrame {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FrogPilotDriveSummary(QWidget *parent = nullptr, bool random_events = false);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void panelClosed();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
|
void hideEvent(QHideEvent *event) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget *createStatBox(const QString &title, QLabel **valueLabel, QWidget *parent);
|
||||||
|
|
||||||
|
bool displayRandomEvents;
|
||||||
|
|
||||||
|
Params params;
|
||||||
|
|
||||||
|
QJsonObject previousStats;
|
||||||
|
|
||||||
|
QLabel *experimentalModeTimeValue;
|
||||||
|
QLabel *frogPilotMetersValue;
|
||||||
|
QLabel *engagementValue;
|
||||||
|
QLabel *titleLabel;
|
||||||
|
QLabel *trackedTimeValue;
|
||||||
|
|
||||||
|
QMap<QString, QLabel*> randomEventLabels;
|
||||||
|
|
||||||
|
QMap<QString, QString> randomEventsMap;
|
||||||
|
|
||||||
|
QVBoxLayout *eventsListLayout;
|
||||||
|
};
|
||||||
@ -130,7 +130,7 @@ inline QString calculateDirectorySize(const QDir &directory) {
|
|||||||
constexpr double GB = 1024.0 * MB;
|
constexpr double GB = 1024.0 * MB;
|
||||||
|
|
||||||
if (!directory.exists()) {
|
if (!directory.exists()) {
|
||||||
return QStringLiteral("0 MB");
|
return QObject::tr("0 MB");
|
||||||
}
|
}
|
||||||
|
|
||||||
double totalSize = 0;
|
double totalSize = 0;
|
||||||
@ -141,9 +141,9 @@ inline QString calculateDirectorySize(const QDir &directory) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (totalSize >= GB) {
|
if (totalSize >= GB) {
|
||||||
return QString::number(totalSize / GB, 'f', 2) + QStringLiteral(" GB");
|
return QString::number(totalSize / GB, 'f', 2) + QObject::tr(" GB");
|
||||||
}
|
}
|
||||||
return QString::number(totalSize / MB, 'f', 2) + QStringLiteral(" MB");
|
return QString::number(totalSize / MB, 'f', 2) + QObject::tr(" MB");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QString daySuffix(int day) {
|
inline QString daySuffix(int day) {
|
||||||
@ -166,12 +166,12 @@ inline QString formatElapsedTime(float elapsedMilliseconds) {
|
|||||||
|
|
||||||
QString formattedTime;
|
QString formattedTime;
|
||||||
if (hours > 0) {
|
if (hours > 0) {
|
||||||
formattedTime += QString::number(hours) + (hours == 1 ? " hour " : " hours ");
|
formattedTime += QString::number(hours) + (hours == 1 ? QObject::tr(" hour ") : QObject::tr(" hours "));
|
||||||
}
|
}
|
||||||
if (minutes > 0) {
|
if (minutes > 0) {
|
||||||
formattedTime += QString::number(minutes) + (minutes == 1 ? " minute " : " minutes ");
|
formattedTime += QString::number(minutes) + (minutes == 1 ? QObject::tr(" minute ") : QObject::tr(" minutes "));
|
||||||
}
|
}
|
||||||
formattedTime += QString::number(seconds) + (seconds == 1 ? " second" : " seconds");
|
formattedTime += QString::number(seconds) + (seconds == 1 ? QObject::tr(" second") : QObject::tr(" seconds"));
|
||||||
|
|
||||||
return formattedTime.trimmed();
|
return formattedTime.trimmed();
|
||||||
}
|
}
|
||||||
|
|||||||