November 1st, 2025 Update

This commit is contained in:
James 2025-11-01 12:00:00 -07:00
parent 2d115c7882
commit ac7eb28792
161 changed files with 21281 additions and 686 deletions

1
.github/update_date vendored Normal file
View File

@ -0,0 +1 @@
2025-11-01

View File

@ -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

View File

@ -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:

View File

@ -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);
} }

View File

@ -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 {

View File

@ -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 {

View File

@ -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},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 630 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -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)

View 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"}]}

View 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"}]}

View File

@ -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"}]}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 KiB

View File

@ -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

View File

@ -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")

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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,

View 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)

View File

@ -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)

View File

@ -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)

View File

@ -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();

View File

@ -74,7 +74,6 @@ public:
WifiManager *wifi; WifiManager *wifi;
signals: signals:
void reviewModel();
void themeUpdated(); void themeUpdated();
}; };

View File

@ -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));
}
}
}
} }

View File

@ -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"};
}; };

View File

@ -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();

View File

@ -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:

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;
}; };

View File

@ -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);

View File

@ -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 {

View File

@ -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) {

View File

@ -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;
}; };

View File

@ -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"));
}); });
} }
} }

View File

@ -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)) {

View File

@ -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"};

View File

@ -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();
}

View File

@ -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;

View File

@ -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))

View File

@ -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();

View 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;
}

View 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;
};

View File

@ -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();
} }

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