November 15th, 2025 Patch

This commit is contained in:
James
2025-11-15 12:00:00 -07:00
parent 090208d482
commit 2309424dfe
54 changed files with 692 additions and 354 deletions
+45 -60
View File
@@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
runner:
description: "Select the runner"
description: "Select runner"
required: true
default: "c3"
type: choice
@@ -14,22 +14,22 @@ on:
not_vetted:
description: "This branch is not vetted"
required: false
default: "false"
default: false
type: boolean
publish_frogpilot:
description: "Push to FrogPilot"
required: false
default: "false"
default: false
type: boolean
publish_staging:
description: "Push to FrogPilot-Staging"
required: false
default: "false"
default: false
type: boolean
publish_testing:
description: "Push to FrogPilot-Testing"
required: false
default: "false"
default: false
type: boolean
publish_custom_branch:
description: "Push to custom branch:"
@@ -39,18 +39,18 @@ on:
update_translations:
description: "Update missing/outdated translations"
required: false
default: "false"
default: false
type: boolean
vet_existing_translations:
description: "Vet existing translations"
required: false
default: "false"
default: false
type: boolean
env:
BASEDIR: "${{ github.workspace }}"
BASEDIR: ${{ github.workspace }}
BUILD_DIR: /data/openpilot
OPENAI_API_KEY: "${{ secrets.OPENAI_API_KEY }}"
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
jobs:
get_branch:
@@ -61,19 +61,16 @@ jobs:
branch: ${{ steps.get_branch.outputs.branch }}
python_version: ${{ steps.get_python_version.outputs.python_version }}
steps:
- name: Determine Current Branch on Runner
- name: Get Current Branch
id: get_branch
run: |
cd $BUILD_DIR
echo "branch=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_OUTPUT
BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
- name: Get Python Version from Runner
- name: Get Python Version
id: get_python_version
run: |
PYTHON_VERSION=$(tr -d '[:space:]' < "$BUILD_DIR/.python-version")
echo "python_version=$PYTHON_VERSION" >> $GITHUB_OUTPUT
echo "python_version=$(tr -d '[:space:]' < "$BUILD_DIR/.python-version")" >> $GITHUB_OUTPUT
translate:
if: inputs.update_translations
@@ -100,29 +97,28 @@ jobs:
- name: Set Up Python
uses: actions/setup-python@v4
with:
python-version: "${{ needs.get_branch.outputs.python_version }}"
python-version: ${{ needs.get_branch.outputs.python_version }}
- name: Install Dependencies
run: pip install requests
- name: Install Qt5 Tools
run: sudo apt update && sudo apt install -y qttools5-dev-tools
run: |
pip install requests
sudo apt update && sudo apt install -y qttools5-dev-tools
- name: Update Translations
run: python selfdrive/ui/update_translations.py --vanish
- name: Update Missing Translations
continue-on-error: true
run: python selfdrive/ui/translations/auto_translate.py --all-files
timeout-minutes: 300
run: python selfdrive/ui/translations/auto_translate.py --all-files
- name: Vet Existing Translations
if: github.event.inputs.vet_existing_translations == 'true'
if: inputs.vet_existing_translations
continue-on-error: true
run: python selfdrive/ui/translations/auto_translate.py --all-files --vet-translations
timeout-minutes: 300
run: python selfdrive/ui/translations/auto_translate.py --all-files --vet-translations
- name: Commit and Push Translation Updates
- name: Commit and Push Translations
run: |
if git diff --quiet selfdrive/ui/translations/*.ts; then
echo "No translation updates detected."
@@ -136,9 +132,7 @@ jobs:
git push --force origin ${{ needs.get_branch.outputs.branch }}
build_and_push:
needs:
- get_branch
- translate
needs: [get_branch, translate]
if: always()
runs-on:
- self-hosted
@@ -149,27 +143,23 @@ jobs:
run:
working-directory: ${{ env.BUILD_DIR }}
steps:
- name: Configure Git Identity
- name: Configure Git
run: |
git config --global http.postBuffer 104857600
git config --global user.name "James"
git config --global user.email "91348155+FrogAi@users.noreply.github.com"
- name: Update Repository
run: |
git remote set-url origin https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/FrogAi/FrogPilot.git
if [ "${{ github.event.inputs.update_translations }}" = "true" ]; then
git fetch origin ${{ needs.get_branch.outputs.branch }}
git reset --hard FETCH_HEAD
fi
- name: Take Ownership of Build
- name: Sync Translation Updates
if: inputs.update_translations
run: |
sudo chown -R $(whoami):$(whoami) .
git fetch origin ${{ needs.get_branch.outputs.branch }}
git reset --hard FETCH_HEAD
- name: Finalize Build
- name: Take Ownership of Build Directory
run: sudo chown -R $(whoami):$(whoami) .
- name: Clean Build Artifacts
run: |
rm -f .clang-tidy
rm -f .dockerignore
@@ -215,7 +205,6 @@ jobs:
rm -rf teleoprtc_repo/
find .github -mindepth 1 -maxdepth 1 ! -name 'workflows' -exec rm -rf {} +
find .github/workflows -mindepth 1 ! \( \
-type f \( \
-name 'compile_frogpilot.yaml' -o \
@@ -233,8 +222,6 @@ jobs:
find third_party/ -name '*x86*' -exec rm -rf {} +
find third_party/ -name '*Darwin*' -exec rm -rf {} +
find tools/ -mindepth 1 -maxdepth 1 ! \( -name '__init__.py' -o -name 'bodyteleop' -o -name 'lib' -o -name 'scripts' \) -exec rm -rf {} +
find . -name 'SConstruct' -delete
find . -name 'SConscript' -delete
@@ -244,34 +231,32 @@ jobs:
find . -type f -regex '.*matlab.*\.md' -delete
touch prebuilt
[ "${{ inputs.not_vetted }}" = "true" ] && touch not_vetted || true
if [ "${{ github.event.inputs.not_vetted }}" = "true" ]; then
touch not_vetted
fi
- name: Add the update_date file
if: github.event.inputs.publish_staging == 'true'
- name: Add Update Date File
if: inputs.publish_staging
continue-on-error: true
run: |
curl -fLsS https://raw.githubusercontent.com/FrogAi/FrogPilot/FrogPilot-Staging/.github/update_date -o .github/update_date || echo "No update_date found, skipping."
curl -fLsS https://raw.githubusercontent.com/FrogAi/FrogPilot/FrogPilot-Staging/.github/update_date -o .github/update_date || echo "No update_date found, skipping..."
- name: Commit Build
- name: Commit and Push Build
run: |
git add -f .
git commit -m "Compile FrogPilot"
git push --force origin HEAD
if [ "${{ github.event.inputs.publish_frogpilot }}" = "true" ]; then
git push --force origin HEAD:"FrogPilot"
if [ "${{ inputs.publish_frogpilot }}" = "true" ]; then
git push --force origin HEAD:FrogPilot
fi
if [ "${{ github.event.inputs.publish_staging }}" = "true" ]; then
git push --force origin HEAD:"FrogPilot-Staging"
if [ "${{ inputs.publish_staging }}" = "true" ]; then
git push --force origin HEAD:FrogPilot-Staging
fi
if [ "${{ github.event.inputs.publish_testing }}" = "true" ]; then
git push --force origin HEAD:"FrogPilot-Testing"
if [ "${{ inputs.publish_testing }}" = "true" ]; then
git push --force origin HEAD:FrogPilot-Testing
fi
if [ -n "${{ github.event.inputs.publish_custom_branch }}" ]; then
git push --force origin HEAD:"${{ github.event.inputs.publish_custom_branch }}"
if [ -n "${{ inputs.publish_custom_branch }}" ]; then
git push --force origin HEAD:"${{ inputs.publish_custom_branch }}"
fi
+1 -1
View File
@@ -57,7 +57,7 @@ We have detailed instructions for [how to install the harness and device in a ca
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/FrogAi/FrogPilot)
[![Discord](https://img.shields.io/discord/1137853399715549214?label=Discord)](https://discord.frogpilot.download)
[![Last Updated](https://img.shields.io/badge/Last%20Updated-October%2018th%2C%202025-brightgreen)](https://github.com/FrogAi/FrogPilot/releases/latest)
[![Last Updated](https://img.shields.io/badge/Last%20Updated-November%2015th%2C%202025-brightgreen)](https://github.com/FrogAi/FrogPilot/releases/latest)
[![Wiki](https://img.shields.io/badge/Wiki-FrogPilot-blue?logo=wiki)](https://frogpilot.wiki.gg/)
</div>
+3 -3
View File
@@ -530,14 +530,14 @@ struct CarParams {
struct LateralTorqueTuning {
useSteeringAngle @0 :Bool;
kp @1 :Float32;
ki @2 :Float32;
kd @8 : Float32;
friction @3 :Float32;
steeringAngleDeadzoneDeg @5 :Float32;
latAccelFactor @6 :Float32;
latAccelOffset @7 :Float32;
kpDEPRECATED @1 :Float32;
kiDEPRECATED @2 :Float32;
kfDEPRECATED @4 :Float32;
kdDEPRECATED @8 : Float32;
}
struct LongitudinalPIDTuning {
+33 -32
View File
@@ -186,38 +186,39 @@ struct FrogPilotPlan @0xa1680744031fdb2d {
cscControllingSpeed @2 :Bool;
cscSpeed @3 :Float32;
cscTraining @4 :Bool;
dangerJerk @5 :Float32;
desiredFollowDistance @6 :Int64;
experimentalMode @7 :Bool;
forcingStop @8 :Bool;
forcingStopLength @9 :Float32;
frogpilotEvents @10 :List(FrogPilotCarEvent);
increasedStoppedDistance @11 :Float32;
lateralCheck @12 :Bool;
laneWidthLeft @13 :Float32;
laneWidthRight @14 :Float32;
maxAcceleration @15 :Float32;
minAcceleration @16 :Float32;
redLight @17 :Bool;
roadCurvature @18 :Float32;
slcMapSpeedLimit @19 :Float32;
slcMapboxSpeedLimit @20 :Float32;
slcNextSpeedLimit @21 :Float32;
slcOverriddenSpeed @22 :Float32;
slcSpeedLimit @23 :Float32;
slcSpeedLimitOffset @24 :Float32;
slcSpeedLimitSource @25 :Text;
speedJerk @26 :Float32;
speedJerkStock @27 :Float32;
speedLimitChanged @28 :Bool;
tFollow @29 :Float32;
themeUpdated @30 :Bool;
togglesUpdated @31 :Bool;
trackingLead @32 :Bool;
unconfirmedSlcSpeedLimit @33 :Float32;
vCruise @34 :Float32;
weatherDaytime @35 :Bool;
weatherId @36 :Int16;
dangerFactor @5 :Float32;
dangerJerk @6 :Float32;
desiredFollowDistance @7 :Int64;
experimentalMode @8 :Bool;
forcingStop @9 :Bool;
forcingStopLength @10 :Float32;
frogpilotEvents @11 :List(FrogPilotCarEvent);
increasedStoppedDistance @12 :Float32;
lateralCheck @13 :Bool;
laneWidthLeft @14 :Float32;
laneWidthRight @15 :Float32;
maxAcceleration @16 :Float32;
minAcceleration @17 :Float32;
redLight @18 :Bool;
roadCurvature @19 :Float32;
slcMapSpeedLimit @20 :Float32;
slcMapboxSpeedLimit @21 :Float32;
slcNextSpeedLimit @22 :Float32;
slcOverriddenSpeed @23 :Float32;
slcSpeedLimit @24 :Float32;
slcSpeedLimitOffset @25 :Float32;
slcSpeedLimitSource @26 :Text;
speedJerk @27 :Float32;
speedJerkStock @28 :Float32;
speedLimitChanged @29 :Bool;
tFollow @30 :Float32;
themeUpdated @31 :Bool;
togglesUpdated @32 :Bool;
trackingLead @33 :Bool;
unconfirmedSlcSpeedLimit @34 :Float32;
vCruise @35 :Float32;
weatherDaytime @36 :Bool;
weatherId @37 :Int16;
}
struct FrogPilotRadarState @0xcb9fd56c7057593a {
+33 -14
View File
@@ -22,7 +22,6 @@ 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.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.system.hardware import HARDWARE
from openpilot.system.hardware.power_monitoring import VBATT_PAUSE_CHARGING
@@ -90,6 +89,26 @@ BUTTON_FUNCTIONS = {
"TRAFFIC_MODE": 6
}
DEVELOPER_SIDEBAR_METRICS = {
"NONE": 0,
"ACCELERATION_CURRENT": 1,
"ACCELERATION_MAX": 2,
"AUTOTUNE_ACTUATOR_DELAY": 3,
"AUTOTUNE_FRICTION": 4,
"AUTOTUNE_LATERAL_ACCELERATION": 5,
"AUTOTUNE_STEER_RATIO": 6,
"AUTOTUNE_STIFFNESS_FACTOR": 7,
"ENGAGEMENT_LATERAL": 8,
"ENGAGEMENT_LONGITUDINAL": 9,
"LATERAL_STEERING_ANGLE": 10,
"LATERAL_TORQUE_USED": 11,
"LONGITUDINAL_ACTUATOR_ACCELERATION": 12,
"LONGITUDINAL_MPC_DANGER_FACTOR": 13,
"LONGITUDINAL_MPC_JERK_ACCELERATION": 14,
"LONGITUDINAL_MPC_JERK_DANGER_ZONE": 15,
"LONGITUDINAL_MPC_JERK_SPEED_CONTROL": 16
}
EXCLUDED_KEYS = {
"AvailableModels", "AvailableModelNames", "CalibratedLateralAcceleration", "CalibrationProgress", "CarParamsPersistent",
"CurvatureData", "ExperimentalLongitudinalEnabled", "KonikMinutes", "MapBoxRequests", "ModelDrivesAndScores", "ModelVersions",
@@ -608,7 +627,7 @@ class FrogPilotVariables:
startAccel = CP.startAccel
stopAccel = CP.stopAccel
steerActuatorDelay = CP.steerActuatorDelay
steerKp = CP.lateralTuning.pid.kp if CP.lateralTuning.which() == "pid" else KP
steerKp = CP.lateralTuning.torque.kp
steerRatio = CP.steerRatio
toggle.stoppingDecelRate = CP.stoppingDecelRate
taco_hacks_allowed = CP.safetyConfigs[0].safetyModel == SafetyModel.hyundaiCanfd
@@ -649,7 +668,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.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.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
@@ -768,13 +787,13 @@ class FrogPilotVariables:
toggle.storage_used_metrics = developer_metrics and (params.get_bool("ShowStorageUsed") if tuning_level >= level["ShowStorageUsed"] else default.get_bool("ShowStorageUsed")) and not toggle.debug_mode
toggle.use_si_metrics = developer_metrics and (params.get_bool("UseSI") if tuning_level >= level["UseSI"] else default.get_bool("UseSI")) or toggle.debug_mode
toggle.developer_sidebar = toggle.developer_ui and (params.get_bool("DeveloperSidebar") if tuning_level >= level["DeveloperSidebar"] else default.get_bool("DeveloperSidebar")) or toggle.debug_mode
toggle.developer_sidebar_metric1 = params.get_int("DeveloperSidebarMetric1") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric1"] else 1 if toggle.debug_mode else default.get_int("DeveloperSidebarMetric1")
toggle.developer_sidebar_metric2 = params.get_int("DeveloperSidebarMetric2") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric2"] else 3 if toggle.debug_mode else default.get_int("DeveloperSidebarMetric2")
toggle.developer_sidebar_metric3 = params.get_int("DeveloperSidebarMetric3") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric3"] else 4 if toggle.debug_mode else default.get_int("DeveloperSidebarMetric3")
toggle.developer_sidebar_metric4 = params.get_int("DeveloperSidebarMetric4") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric4"] else 5 if toggle.debug_mode else default.get_int("DeveloperSidebarMetric4")
toggle.developer_sidebar_metric5 = params.get_int("DeveloperSidebarMetric5") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric5"] else 6 if toggle.debug_mode else default.get_int("DeveloperSidebarMetric5")
toggle.developer_sidebar_metric6 = params.get_int("DeveloperSidebarMetric6") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric6"] else 7 if toggle.debug_mode else default.get_int("DeveloperSidebarMetric6")
toggle.developer_sidebar_metric7 = params.get_int("DeveloperSidebarMetric7") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric7"] else 11 if toggle.debug_mode else default.get_int("DeveloperSidebarMetric7")
toggle.developer_sidebar_metric1 = params.get_int("DeveloperSidebarMetric1") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric1"] else DEVELOPER_SIDEBAR_METRICS["ACCELERATION_CURRENT"] if toggle.debug_mode else default.get_int("DeveloperSidebarMetric1")
toggle.developer_sidebar_metric2 = params.get_int("DeveloperSidebarMetric2") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric2"] else DEVELOPER_SIDEBAR_METRICS["AUTOTUNE_ACTUATOR_DELAY"] if toggle.debug_mode else default.get_int("DeveloperSidebarMetric2")
toggle.developer_sidebar_metric3 = params.get_int("DeveloperSidebarMetric3") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric3"] else DEVELOPER_SIDEBAR_METRICS["AUTOTUNE_FRICTION"] if toggle.debug_mode else default.get_int("DeveloperSidebarMetric3")
toggle.developer_sidebar_metric4 = params.get_int("DeveloperSidebarMetric4") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric4"] else DEVELOPER_SIDEBAR_METRICS["AUTOTUNE_LATERAL_ACCELERATION"] if toggle.debug_mode else default.get_int("DeveloperSidebarMetric4")
toggle.developer_sidebar_metric5 = params.get_int("DeveloperSidebarMetric5") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric5"] else DEVELOPER_SIDEBAR_METRICS["AUTOTUNE_STEER_RATIO"] if toggle.debug_mode else default.get_int("DeveloperSidebarMetric5")
toggle.developer_sidebar_metric6 = params.get_int("DeveloperSidebarMetric6") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric6"] else DEVELOPER_SIDEBAR_METRICS["AUTOTUNE_STIFFNESS_FACTOR"] if toggle.debug_mode else default.get_int("DeveloperSidebarMetric6")
toggle.developer_sidebar_metric7 = params.get_int("DeveloperSidebarMetric7") if toggle.developer_sidebar and tuning_level >= level["DeveloperSidebarMetric7"] else DEVELOPER_SIDEBAR_METRICS["LATERAL_TORQUE_USED"] if toggle.debug_mode else default.get_int("DeveloperSidebarMetric7")
developer_widgets = toggle.developer_ui and params.get_bool("DeveloperWidgets") if tuning_level >= level["DeveloperWidgets"] else default.get_bool("DeveloperWidgets")
toggle.adjacent_lead_tracking = has_radar and ((developer_widgets and params.get_bool("AdjacentLeadsUI") if tuning_level >= level["AdjacentLeadsUI"] else default.get_bool("AdjacentLeadsUI")) or toggle.debug_mode)
toggle.radar_tracks = has_radar and ((developer_widgets and params.get_bool("RadarTracksUI") if tuning_level >= level["RadarTracksUI"] else default.get_bool("RadarTracksUI")) or toggle.debug_mode)
@@ -832,9 +851,9 @@ class FrogPilotVariables:
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.honda_alt_Tune = 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.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.car_make == "honda" and honda_nidec and (params.get_bool("HondaMaxBrake") if tuning_level >= level["HondaMaxBrake"] else default.get_bool("HondaMaxBrake"))
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_change_delay = params.get_float("LaneChangeTime") if toggle.lane_changes and tuning_level >= level["LaneChangeTime"] else default.get_float("LaneChangeTime")
@@ -934,7 +953,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_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_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"))
+8 -8
View File
@@ -36,7 +36,7 @@ class FrogPilotCard:
self.gap_counter = 0
def update_distance_button(self, sm):
if self.car.frogpilot_toggles.experimental_mode_via_distance and sm["carControl"].longActive:
if sm["carControl"].longActive and self.car.frogpilot_toggles.experimental_mode_via_distance:
handle_experimental_mode(self.car.frogpilot_toggles.conditional_experimental_mode)
elif self.car.frogpilot_toggles.force_coast_via_distance:
self.force_coast = not self.force_coast
@@ -44,11 +44,11 @@ class FrogPilotCard:
self.pause_lateral = not self.pause_lateral
elif self.car.frogpilot_toggles.pause_longitudinal_via_distance:
self.pause_longitudinal = not self.pause_longitudinal
elif self.car.frogpilot_toggles.traffic_mode_via_distance and sm["carControl"].longActive:
elif sm["carControl"].longActive and self.car.frogpilot_toggles.traffic_mode_via_distance:
self.traffic_mode_enabled = not self.traffic_mode_enabled
def update_distance_button_long(self, sm):
if self.car.frogpilot_toggles.experimental_mode_via_distance_long and sm["carControl"].longActive:
if sm["carControl"].longActive and self.car.frogpilot_toggles.experimental_mode_via_distance_long:
handle_experimental_mode(self.car.frogpilot_toggles.conditional_experimental_mode)
elif self.car.frogpilot_toggles.force_coast_via_distance_long:
self.force_coast = not self.force_coast
@@ -56,13 +56,13 @@ class FrogPilotCard:
self.pause_lateral = not self.pause_lateral
elif self.car.frogpilot_toggles.pause_longitudinal_via_distance_long:
self.pause_longitudinal = not self.pause_longitudinal
elif self.car.frogpilot_toggles.traffic_mode_via_distance_long and sm["carControl"].longActive:
elif sm["carControl"].longActive and self.car.frogpilot_toggles.traffic_mode_via_distance_long:
self.traffic_mode_enabled = not self.traffic_mode_enabled
def update_distance_button_very_long(self, sm):
self.update_distance_button_long(sm)
if self.car.frogpilot_toggles.experimental_mode_via_distance_very_long and sm["carControl"].longActive:
if sm["carControl"].longActive and self.car.frogpilot_toggles.experimental_mode_via_distance_very_long:
handle_experimental_mode(self.car.frogpilot_toggles.conditional_experimental_mode)
elif self.car.frogpilot_toggles.force_coast_via_distance_very_long:
self.force_coast = not self.force_coast
@@ -70,11 +70,11 @@ class FrogPilotCard:
self.pause_lateral = not self.pause_lateral
elif self.car.frogpilot_toggles.pause_longitudinal_via_distance_very_long:
self.pause_longitudinal = not self.pause_longitudinal
elif self.car.frogpilot_toggles.traffic_mode_via_distance_very_long and sm["carControl"].longActive:
elif sm["carControl"].longActive and self.car.frogpilot_toggles.traffic_mode_via_distance_very_long:
self.traffic_mode_enabled = not self.traffic_mode_enabled
def update_lkas_button(self, sm):
if self.car.frogpilot_toggles.experimental_mode_via_lkas and sm["carControl"].longActive:
if sm["carControl"].longActive and self.car.frogpilot_toggles.experimental_mode_via_lkas:
handle_experimental_mode(self.car.frogpilot_toggles.conditional_experimental_mode)
elif self.car.frogpilot_toggles.force_coast_via_lkas:
self.force_coast = not self.force_coast
@@ -82,7 +82,7 @@ class FrogPilotCard:
self.pause_lateral = not self.pause_lateral
elif self.car.frogpilot_toggles.pause_longitudinal_via_lkas:
self.pause_longitudinal = not self.pause_longitudinal
elif self.car.frogpilot_toggles.traffic_mode_via_lkas and sm["carControl"].longActive:
elif sm["carControl"].longActive and self.car.frogpilot_toggles.traffic_mode_via_lkas:
self.traffic_mode_enabled = not self.traffic_mode_enabled
def update(self, carState, frogpilotCarState, sm):
+4 -6
View File
@@ -4,7 +4,7 @@ import math
import cereal.messaging as messaging
from cereal import car, log
from cereal import log
from openpilot.common.conversions import Conversions as CV
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.realtime import DT_MDL
@@ -29,9 +29,6 @@ class FrogPilotPlanner:
self.frogpilot_vcruise = FrogPilotVCruise(self)
self.frogpilot_weather = WeatherChecker()
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg:
self.CP = msg
self.tracking_lead_filter = FirstOrderFilter(0, 0.5, DT_MDL)
self.driving_in_curve = False
@@ -87,8 +84,6 @@ class FrogPilotPlanner:
params_memory.remove("LastGPSPosition")
self.lateral_acceleration = v_ego**2 * (sm["carState"].steeringAngleDeg - sm["liveParameters"].angleOffsetDeg) * CV.DEG_TO_RAD / (self.CP.steerRatio * self.CP.wheelbase)
check_lane_width = frogpilot_toggles.adjacent_paths or frogpilot_toggles.adjacent_path_metrics or frogpilot_toggles.blind_spot_path or frogpilot_toggles.lane_detection
if check_lane_width and v_ego >= frogpilot_toggles.minimum_lane_change_speed:
self.lane_width_left = calculate_lane_width(sm["modelV2"].laneLines[0], sm["modelV2"].laneLines[1], sm["modelV2"].roadEdges[0])
@@ -97,6 +92,8 @@ class FrogPilotPlanner:
self.lane_width_left = 0
self.lane_width_right = 0
self.lateral_acceleration = v_ego**2 * sm["controlsState"].curvature
self.lateral_check = v_ego >= frogpilot_toggles.pause_lateral_below_speed
self.lateral_check |= not (sm["carState"].leftBlinker or sm["carState"].rightBlinker) and frogpilot_toggles.pause_lateral_below_signal
self.lateral_check |= sm["carState"].standstill
@@ -134,6 +131,7 @@ class FrogPilotPlanner:
frogpilotPlan.accelerationJerk = A_CHANGE_COST * self.frogpilot_following.acceleration_jerk
frogpilotPlan.accelerationJerkStock = A_CHANGE_COST * self.frogpilot_following.base_acceleration_jerk
frogpilotPlan.dangerFactor = self.frogpilot_following.danger_factor
frogpilotPlan.dangerJerk = DANGER_ZONE_COST * self.frogpilot_following.danger_jerk
frogpilotPlan.speedJerk = J_EGO_COST * self.frogpilot_following.speed_jerk
frogpilotPlan.speedJerkStock = J_EGO_COST * self.frogpilot_following.base_speed_jerk
@@ -22,7 +22,7 @@ class ConditionalExperimentalMode:
else:
self.status_value = 0
if self.status_value not in {1, 2} and not sm["carState"].standstill:
if self.status_value not in (1, 2) and not sm["carState"].standstill:
self.update_conditions(v_ego, sm, frogpilot_toggles)
self.experimental_mode = self.check_conditions(v_ego, sm, frogpilot_toggles)
@@ -30,12 +30,12 @@ class ConditionalExperimentalMode:
params_memory.put_int("CEStatus", self.status_value if self.experimental_mode else 0)
else:
self.experimental_mode = self.status_value == 2 or sm["carState"].standstill and self.experimental_mode and self.frogpilot_planner.model_stopped
self.stop_light_detected &= self.status_value not in {1, 2}
self.stop_light_detected &= self.status_value not in (1, 2)
self.stop_light_filter.x = 0
def check_conditions(self, v_ego, sm, frogpilot_toggles):
below_speed = frogpilot_toggles.conditional_limit > v_ego >= 1 and not self.frogpilot_planner.frogpilot_following.following_lead
below_speed_with_lead = frogpilot_toggles.conditional_limit_lead > v_ego >= 1 and self.frogpilot_planner.frogpilot_following.following_lead
below_speed = not self.frogpilot_planner.frogpilot_following.following_lead and 1 <= v_ego < frogpilot_toggles.conditional_limit
below_speed_with_lead = self.frogpilot_planner.frogpilot_following.following_lead and 1 <= v_ego < frogpilot_toggles.conditional_limit_lead
if below_speed or below_speed_with_lead:
self.status_value = 3 if self.frogpilot_planner.frogpilot_following.following_lead else 4
return True
@@ -47,19 +47,19 @@ class ConditionalExperimentalMode:
return True
approaching_maneuver = sm["frogpilotNavigation"].approachingIntersection or sm["frogpilotNavigation"].approachingTurn
if frogpilot_toggles.conditional_navigation and approaching_maneuver and (frogpilot_toggles.conditional_navigation_lead or not self.frogpilot_planner.frogpilot_following.following_lead):
if approaching_maneuver and (not self.frogpilot_planner.frogpilot_following.following_lead or frogpilot_toggles.conditional_navigation_lead) and frogpilot_toggles.conditional_navigation:
self.status_value = 6 if sm["frogpilotNavigation"].approachingIntersection else 7
return True
if frogpilot_toggles.conditional_curves and self.curve_detected and (frogpilot_toggles.conditional_curves_lead or not self.frogpilot_planner.frogpilot_following.following_lead):
if self.curve_detected and (not self.frogpilot_planner.frogpilot_following.following_lead or frogpilot_toggles.conditional_curves_lead) and frogpilot_toggles.conditional_curves:
self.status_value = 8
return True
if frogpilot_toggles.conditional_lead and self.slow_lead_detected:
if self.slow_lead_detected and frogpilot_toggles.conditional_lead:
self.status_value = 9 if self.frogpilot_planner.lead_one.vLead < 1 else 10
return True
if frogpilot_toggles.conditional_model_stop_time != 0 and self.stop_light_detected:
if self.stop_light_detected and frogpilot_toggles.conditional_model_stop_time != 0:
self.status_value = 11 if not self.frogpilot_planner.frogpilot_vcruise.forcing_stop else 12
return True
@@ -71,17 +71,17 @@ class ConditionalExperimentalMode:
def update_conditions(self, v_ego, sm, frogpilot_toggles):
self.curve_detection(v_ego, frogpilot_toggles)
self.slow_lead(frogpilot_toggles)
self.slow_lead(v_ego, frogpilot_toggles)
self.stop_sign_and_light(v_ego, sm, frogpilot_toggles.conditional_model_stop_time)
def curve_detection(self, v_ego, frogpilot_toggles):
self.curvature_filter.update(self.frogpilot_planner.road_curvature_detected or self.frogpilot_planner.driving_in_curve)
self.curve_detected = self.curvature_filter.x >= THRESHOLD and v_ego > CRUISING_SPEED
def slow_lead(self, frogpilot_toggles):
def slow_lead(self, v_ego, frogpilot_toggles):
if self.frogpilot_planner.tracking_lead:
slower_lead = frogpilot_toggles.conditional_slower_lead and self.frogpilot_planner.frogpilot_following.slower_lead
stopped_lead = frogpilot_toggles.conditional_stopped_lead and self.frogpilot_planner.lead_one.vLead < 1
slower_lead = (v_ego - self.frogpilot_planner.lead_one.vLead) > CRUISING_SPEED and frogpilot_toggles.conditional_slower_lead
stopped_lead = self.frogpilot_planner.lead_one.vLead < 1 and frogpilot_toggles.conditional_stopped_lead
self.slow_lead_filter.update(slower_lead or stopped_lead)
self.slow_lead_detected = self.slow_lead_filter.x >= THRESHOLD
@@ -42,7 +42,7 @@ class FrogPilotAcceleration:
if sm["frogpilotCarState"].trafficModeEnabled:
self.max_accel = get_max_accel(v_ego)
elif frogpilot_toggles.map_acceleration and (eco_gear or sport_gear):
elif (eco_gear or sport_gear) and frogpilot_toggles.map_acceleration:
if eco_gear:
self.max_accel = get_max_accel_eco(v_ego)
else:
@@ -71,7 +71,7 @@ class FrogPilotAcceleration:
self.min_accel = ACCEL_MIN
elif sm["frogpilotCarState"].forceCoast:
self.min_accel = A_CRUISE_MIN_ECO
elif frogpilot_toggles.map_deceleration and (eco_gear or sport_gear):
elif (eco_gear or sport_gear) and frogpilot_toggles.map_deceleration:
if eco_gear:
self.min_accel = A_CRUISE_MIN_ECO
else:
+16 -15
View File
@@ -4,7 +4,7 @@ import random
from openpilot.common.conversions import Conversions as CV
from openpilot.common.realtime import DT_MDL
from openpilot.selfdrive.controls.lib.desire_helper import TurnDirection
from openpilot.selfdrive.controls.lib.events import ET, EventName, FrogPilotEventName, Events
from openpilot.selfdrive.controls.lib.events import ET, EVENT_NAME, FROGPILOT_EVENT_NAME, EventName, FrogPilotEventName, Events
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
from openpilot.frogpilot.common.frogpilot_variables import CRUISING_SPEED, NON_DRIVING_GEARS, params, params_memory
@@ -34,8 +34,8 @@ class FrogPilotEvents:
self.played_events = set()
def update(self, v_cruise, sm, frogpilot_toggles):
self.event_names = {event.name for event in sm["onroadEvents"]}
self.frogpilot_event_names = {event.name for event in sm["frogpilotOnroadEvents"]}
current_alert = sm["controlsState"].alertType
current_frogpilot_alert = sm["frogpilotControlsState"].alertType
alerts_empty = all(sm[state].alertText1 == "" and sm[state].alertText2 == "" for state in ["controlsState", "frogpilotControlsState"])
@@ -75,7 +75,7 @@ class FrogPilotEvents:
else:
self.stopped_for_light = False
if "holidayActive" not in self.played_events and self.startup_seen and alerts_empty and frogpilot_toggles.current_holiday_theme != "stock" and len(self.events) == 0:
if "holidayActive" not in self.played_events and self.startup_seen and alerts_empty and len(self.events) == 0 and frogpilot_toggles.current_holiday_theme != "stock":
self.events.add(FrogPilotEventName.holidayActive)
self.played_events.add("holidayActive")
@@ -135,13 +135,13 @@ class FrogPilotEvents:
self.random_event_playing = True
self.played_events.add("dejaVuCurve")
if "hal9000" not in self.played_events and (sm["controlsState"].alertType == ET.NO_ENTRY or sm["frogpilotControlsState"].alertType == ET.NO_ENTRY):
if "hal9000" not in self.played_events and (ET.NO_ENTRY in current_alert or ET.NO_ENTRY in current_frogpilot_alert):
self.events.add(FrogPilotEventName.hal9000)
self.random_event_playing = True
self.played_events.add("hal9000")
if (EventName.steerSaturated in self.event_names or FrogPilotEventName.goatSteerSaturated in self.frogpilot_event_names):
if f"{EVENT_NAME[EventName.steerSaturated]}/" in current_alert or f"{FROGPILOT_EVENT_NAME[FrogPilotEventName.goatSteerSaturated]}/" in current_frogpilot_alert:
event_choices = []
if "firefoxSteerSaturated" not in self.played_events:
event_choices.append("firefoxSteerSaturated")
@@ -178,21 +178,22 @@ class FrogPilotEvents:
self.random_event_playing = True
self.played_events.add("vCruise69")
if (EventName.fcw in self.event_names or EventName.stockAeb in self.event_names):
if f"{EVENT_NAME[EventName.fcw]}/" in current_alert or f"{EVENT_NAME[EventName.stockAeb]}/" in current_alert:
event_choices = []
if "toBeContinued" not in self.played_events:
event_choices.append("toBeContinued")
if "yourFrogTriedToKillMe" not in self.played_events:
event_choices.append("yourFrogTriedToKillMe")
event_choice = random.choice(event_choices)
if event_choice == "toBeContinued":
self.events.add(FrogPilotEventName.toBeContinued)
elif event_choice == "yourFrogTriedToKillMe":
self.events.add(FrogPilotEventName.yourFrogTriedToKillMe)
if event_choices:
event_choice = random.choice(event_choices)
if event_choice == "toBeContinued":
self.events.add(FrogPilotEventName.toBeContinued)
elif event_choice == "yourFrogTriedToKillMe":
self.events.add(FrogPilotEventName.yourFrogTriedToKillMe)
self.random_event_playing = True
self.played_events.add(event_choice)
self.random_event_playing = True
self.played_events.add(event_choice)
if "youveGotMail" not in self.played_events and sm["frogpilotCarState"].alwaysOnLateralEnabled and not self.always_on_lateral_enabled_previously:
if random.random() < RANDOM_EVENTS_CHANCE:
@@ -203,7 +204,7 @@ class FrogPilotEvents:
self.always_on_lateral_enabled_previously = sm["frogpilotCarState"].alwaysOnLateralEnabled
if frogpilot_toggles.speed_limit_changed_alert and self.frogpilot_planner.frogpilot_vcruise.slc.speed_limit_changed_timer == DT_MDL:
if self.frogpilot_planner.frogpilot_vcruise.slc.speed_limit_changed_timer == DT_MDL and frogpilot_toggles.speed_limit_changed_alert:
self.events.add(FrogPilotEventName.speedLimitChanged)
self.startup_seen |= sm["frogpilotControlsState"].alertText1 == frogpilot_toggles.startup_alert_top and sm["frogpilotControlsState"].alertText2 == frogpilot_toggles.startup_alert_bottom
+13 -13
View File
@@ -1,9 +1,9 @@
#!/usr/bin/env python3
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, LEAD_DANGER_FACTOR, STOP_DISTANCE, desired_follow_distance, get_jerk_factor, get_T_FOLLOW
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT, MAX_T_FOLLOW
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT, CRUISING_SPEED, MAX_T_FOLLOW
TRAFFIC_MODE_BP = [0., CITY_SPEED_LIMIT]
@@ -12,7 +12,6 @@ class FrogPilotFollowing:
self.frogpilot_planner = FrogPilotPlanner
self.following_lead = False
self.slower_lead = False
self.acceleration_jerk = 0
self.danger_jerk = 0
@@ -60,6 +59,7 @@ class FrogPilotFollowing:
self.t_follow = 0
self.acceleration_jerk = self.base_acceleration_jerk
self.danger_factor = LEAD_DANGER_FACTOR
self.danger_jerk = self.base_danger_jerk
self.speed_jerk = self.base_speed_jerk
@@ -69,7 +69,7 @@ class FrogPilotFollowing:
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 not sm["frogpilotCarState"].trafficModeEnabled:
if not sm["frogpilotCarState"].trafficModeEnabled and frogpilot_toggles.human_following:
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))
else:
@@ -77,7 +77,7 @@ class FrogPilotFollowing:
def update_follow_values(self, lead_distance, v_ego, v_lead, frogpilot_toggles):
# Offset by FrogAi for FrogPilot for a more natural approach to a faster lead
if frogpilot_toggles.human_following and v_lead > v_ego:
if v_lead > v_ego:
distance_factor = max(lead_distance - (v_ego * self.t_follow), 1)
accelerating_offset = float(np.clip(STOP_DISTANCE - v_ego, 1, distance_factor))
@@ -86,14 +86,14 @@ class FrogPilotFollowing:
self.t_follow /= accelerating_offset
# Offset by FrogAi for FrogPilot for a more natural approach to a slower lead
if (frogpilot_toggles.conditional_slower_lead or frogpilot_toggles.human_following) and v_lead < v_ego:
if v_lead < v_ego:
distance_factor = max(lead_distance - (v_lead * self.t_follow), 1)
braking_offset = float(np.clip(min(v_ego - v_lead, v_lead) - COMFORT_BRAKE, 1, distance_factor))
if frogpilot_toggles.human_following:
if not self.following_lead and v_lead > CITY_SPEED_LIMIT:
far_lead_offset = max(lead_distance - (v_ego * self.t_follow) - STOP_DISTANCE, 0)
else:
far_lead_offset = 0
self.t_follow /= braking_offset + far_lead_offset
self.slower_lead = braking_offset > 1
self.danger_factor += (braking_offset / 100)
if lead_distance >= 100:
far_lead_offset = max(lead_distance - (v_ego * self.t_follow) - STOP_DISTANCE, 0)
braking_offset += far_lead_offset
self.t_follow /= braking_offset
@@ -14,7 +14,6 @@ from openpilot.common.numpy_fast import interp
from openpilot.common.params import Params
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
from openpilot.selfdrive.controls.lib.latcontrol_torque import KD, KI, KP
from openpilot.selfdrive.controls.lib.pid import PIDController
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
from openpilot.selfdrive.modeld.constants import ModelConstants
@@ -175,7 +174,7 @@ class LatControlNNFF(LatControl):
self.nnff_loaded = self.lat_torque_nn_model is not None
self.torque_params = CP.lateralTuning.torque
self.pid = PIDController(KP, KI, k_d=KD,
self.pid = PIDController(self.torque_params.kp, self.torque_params.ki,
pos_limit=self.steer_max, neg_limit=-self.steer_max)
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
self.use_steering_angle = self.torque_params.useSteeringAngle
@@ -51,7 +51,7 @@ class SpeedLimitController:
@property
def experimental_mode(self):
return self.frogpilot_toggles.slc_fallback_experimental_mode and self.target == 0
return self.target == 0 and self.frogpilot_toggles.slc_fallback_experimental_mode
@property
def offset(self):
@@ -42,6 +42,8 @@ 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
@@ -147,10 +149,12 @@ class WeatherChecker:
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()
+1 -1
View File
@@ -14,8 +14,8 @@ from openpilot.frogpilot.common.frogpilot_functions import backup_toggles
from openpilot.frogpilot.common.frogpilot_utilities import capture_report, flash_panda, is_url_pingable, lock_doors, run_thread_with_lock, update_maps, update_openpilot
from openpilot.frogpilot.common.frogpilot_variables import ERROR_LOGS_PATH, FrogPilotVariables, get_frogpilot_toggles, params, params_cache, params_memory
from openpilot.frogpilot.controls.frogpilot_planner import FrogPilotPlanner
from openpilot.frogpilot.controls.lib.frogpilot_tracking import FrogPilotTracking
from openpilot.frogpilot.system.frogpilot_stats import send_stats
from openpilot.frogpilot.system.frogpilot_tracking import FrogPilotTracking
ASSET_CHECK_RATE = (1 / DT_MDL)
@@ -1,14 +1,17 @@
#!/usr/bin/env python3
import json
from cereal import log
from openpilot.common.conversions import Conversions as CV
from openpilot.common.realtime import DT_MDL
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.events import EVENT_NAME
from openpilot.selfdrive.ui.soundd import FrogPilotAudibleAlert
from openpilot.frogpilot.common.frogpilot_utilities import clean_model_name
from openpilot.frogpilot.common.frogpilot_variables import params
from openpilot.frogpilot.controls.lib.weather_checker import WEATHER_CATEGORIES
RANDOM_EVENTS = {
FrogPilotEventName.accel30: "accel30",
@@ -28,6 +31,7 @@ RANDOM_EVENTS = {
class FrogPilotTracking:
def __init__(self, frogpilot_planner, frogpilot_toggles):
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.setdefault("AOLTime", self.frogpilot_stats.get("TotalAOLTime", 0))
@@ -35,7 +39,14 @@ class FrogPilotTracking:
self.frogpilot_stats.setdefault("LongitudinalTime", self.frogpilot_stats.get("TotalLongitudinalTime", 0))
self.frogpilot_stats.setdefault("TrackedTime", self.frogpilot_stats.get("TotalTrackedTime", 0))
self.frogpilot_stats = {key: value for key, value in self.frogpilot_stats.items() if not key.startswith("Total")}
self.frogpilot_stats = {
key: (
{sub_key: sub_value for sub_key, sub_value in value.items() if sub_key.lower() != "unknown"}
if isinstance(value, dict) else value
)
for key, value in self.frogpilot_stats.items()
if not key.startswith("Total") and key.lower() != "unknown"
}
if "ResetStats" not in self.frogpilot_stats:
self.frogpilot_stats["Disengages"] = 0
@@ -53,9 +64,11 @@ class FrogPilotTracking:
self.distance_since_override = 0
self.tracked_time = 0
self.previous_events = set()
self.previous_random_events = set()
self.personality_map = {key: key.capitalize() for key in log.LongitudinalPersonality.schema.enumerants.keys()}
self.previous_alert_type = ""
self.previous_state = State.disabled
self.sound = FrogPilotAudibleAlert.none
@@ -91,6 +104,11 @@ class FrogPilotTracking:
self.frogpilot_stats["LateralTime"] = self.frogpilot_stats.get("LateralTime", 0) + DT_MDL
if sm["carControl"].longActive:
self.frogpilot_stats["LongitudinalTime"] = self.frogpilot_stats.get("LongitudinalTime", 0) + DT_MDL
personality_name = self.personality_map.get(str(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:
self.frogpilot_stats["AOLTime"] = self.frogpilot_stats.get("AOLTime", 0) + DT_MDL
@@ -125,15 +143,13 @@ class FrogPilotTracking:
self.previous_state = sm["controlsState"].state
current_events = {event for event in self.frogpilot_events.event_names}
if len(current_events) > 0:
new_events = current_events - self.previous_events
if sm["controlsState"].alertType not in (self.previous_alert_type, ""):
alert_name = sm["controlsState"].alertType.split('/')[0]
total_events = self.frogpilot_stats.get("TotalEvents", {})
total_events[alert_name] = total_events.get(alert_name, 0) + 1
self.frogpilot_stats["TotalEvents"] = total_events
if new_events:
if (EventName.fcw in self.frogpilot_events.event_names or EventName.stockAeb in self.frogpilot_events.event_names):
self.frogpilot_stats["AEBEvents"] = self.frogpilot_stats.get("AEBEvents", 0) + 1
self.previous_events = current_events
self.previous_alert_type = sm["controlsState"].alertType
current_random_events = {event for event in self.frogpilot_events.events.names if event in RANDOM_EVENTS}
if len(current_random_events) > 0:
@@ -148,6 +164,30 @@ class FrogPilotTracking:
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 time_validated:
current_month = now.month
+28 -4
View File
@@ -660,15 +660,19 @@ void FrogPilotDataPanel::updateStatsLabels(FrogPilotListWidget *labelsList) {
{"Month", {tr("Month"), "other"}},
{"Overrides", {tr("Total Overrides"), "count"}},
{"OverrideTime", {tr("Time Overriding openpilot"), "time"}},
{"PersonalityTimes", {tr("Driving Personalities:"), "other"}},
{"RandomEvents", {tr("Random Events:"), "other"}},
{"StandstillTime", {tr("Time Stopped"), "time"}},
{"StopLightTime", {tr("Time Spent at Stoplights"), "time"}},
{"TrackedTime", {tr("Total Time Tracked"), "time"}}
{"TrackedTime", {tr("Total Time Tracked"), "time"}},
{"WeatherTimes", {tr("Time Spent in Weather:"), "other"}}
};
static QSet<QString> parent_keys = {
"ModelTimes",
"RandomEvents"
"PersonalityTimes",
"RandomEvents",
"WeatherTimes"
};
static QSet<QString> percentage_keys = {
@@ -742,7 +746,18 @@ void FrogPilotDataPanel::updateStatsLabels(FrogPilotListWidget *labelsList) {
QString label_text = key_map.value(key).first;
QString type = key_map.value(key).second;
if (key == "CruiseSpeedTimes" && value.isObject()) {
if (key == "AEBEvents") {
QJsonObject totalEvents = stats.value("TotalEvents").toObject();
QString trimmed_label = label_text;
if (trimmed_label.startsWith(tr("Total "))) {
trimmed_label = trimmed_label.mid(6);
}
QString display_value = format_number(totalEvents.value("stockAeb").toInt(0) + totalEvents.value("fcw").toInt(0)) + " " + trimmed_label;
labelsList->addItem(new LabelControl(label_text, display_value, "", this));
} else if (key == "CruiseSpeedTimes" && value.isObject()) {
QJsonObject speeds = value.toObject();
double max_time = -1.0;
@@ -783,6 +798,9 @@ void FrogPilotDataPanel::updateStatsLabels(FrogPilotListWidget *labelsList) {
} else if (key == "RandomEvents") {
display_a = random_events_map.value(a, a);
display_b = random_events_map.value(b, b);
} else if (key == "WeatherTimes") {
display_a = a.left(1).toUpper() + a.mid(1);
display_b = b.left(1).toUpper() + b.mid(1);
} else {
display_a = a;
display_b = b;
@@ -791,17 +809,23 @@ void FrogPilotDataPanel::updateStatsLabels(FrogPilotListWidget *labelsList) {
});
for (const QString &subkey : subkeys) {
if (subkey == "Unknown") {
continue;
}
QString display_subkey;
if (key == "ModelTimes") {
display_subkey = processModelName(subkey);
} else if (key == "RandomEvents") {
display_subkey = random_events_map.value(subkey, subkey);
} else if (key == "WeatherTimes") {
display_subkey = subkey.left(1).toUpper() + subkey.mid(1);
} else {
display_subkey = subkey;
}
QString subvalue;
if (key == "ModelTimes") {
if (key == "ModelTimes" || key == "PersonalityTimes" || key == "WeatherTimes") {
subvalue = format_time(subobj.value(subkey).toDouble());
} else {
subvalue = subobj.value(subkey).toVariant().toString().isEmpty() ? "0" : format_number(subobj.value(subkey).toInt());
@@ -304,7 +304,7 @@ void FrogPilotSettingsWindow::updateVariables() {
hasPedal = CP.getEnableGasInterceptor();
hasRadar = !CP.getRadarUnavailable();
hasSDSU = frogpilot_toggles.value("has_sdsu").toBool();
hasSNG = hasOpenpilotLongitudinal && CP.getAutoResumeSng();
hasSNG = CP.getAutoResumeSng();
hasZSS = frogpilot_toggles.value("has_zss").toBool();
isAngleCar = CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE;
isBolt = carFingerprint == "CHEVROLET_BOLT_CC" || carFingerprint == "CHEVROLET_BOLT_EUV";
@@ -322,7 +322,7 @@ void FrogPilotSettingsWindow::updateVariables() {
longitudinalActuatorDelay = CP.getLongitudinalActuatorDelay();
startAccel = CP.getStartAccel();
steerActuatorDelay = CP.getSteerActuatorDelay();
steerKp = CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::PID ? CP.getLateralTuning().getPid().getKpV()[0] : 1.0;
steerKp = 1.0;
steerRatio = CP.getSteerRatio();
stopAccel = CP.getStopAccel();
stoppingDecelRate = CP.getStoppingDecelRate();
+4 -3
View File
@@ -365,7 +365,7 @@ void FrogPilotLateralPanel::updateToggles() {
else if (key == "ForceAutoTune") {
setVisible &= !parent->hasAutoTune;
setVisible &= !parent->isAngleCar;
setVisible &= parent->isTorqueCar || forcingTorqueController;
setVisible &= parent->isTorqueCar || forcingTorqueController || usingNNFF;
}
else if (key == "ForceAutoTuneOff") {
@@ -402,19 +402,20 @@ void FrogPilotLateralPanel::updateToggles() {
else if (key == "SteerFriction") {
setVisible &= parent->friction != 0;
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
setVisible &= parent->isTorqueCar || forcingTorqueController;
setVisible &= parent->isTorqueCar || forcingTorqueController || usingNNFF;
setVisible &= !usingNNFF;
}
else if (key == "SteerKP") {
setVisible &= parent->steerKp != 0;
setVisible &= parent->isTorqueCar || forcingTorqueController || usingNNFF;
setVisible &= !parent->isAngleCar;
}
else if (key == "SteerLatAccel") {
setVisible &= parent->latAccelFactor != 0;
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
setVisible &= parent->isTorqueCar || forcingTorqueController;
setVisible &= parent->isTorqueCar || forcingTorqueController || usingNNFF;
setVisible &= !usingNNFF;
}
@@ -430,14 +430,14 @@ FrogPilotLongitudinalPanel::FrogPilotLongitudinalPanel(FrogPilotSettingsWindow *
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());
int keyLength = 32;
QString currentKey = QString::fromStdString(params.get("WeatherToken"));
QString newKey = InputDialog::getText(tr("Enter your \"OpenWeatherMap\" key"), this, tr("Characters: 0/%1").arg(keyLength), false, -1, currentKey, keyLength).trimmed();
if (!newKey.isEmpty()) {
params.put("WeatherToken", newKey.toStdString());
weatherKeyControl->setText(0, tr("REMOVE"));
weatherKeyControl->setVisibleButton(1, true);
} else if (!key.isEmpty()) {
ConfirmationDialog::alert(tr("Invalid key!"), this);
}
}
} else {
+13 -25
View File
@@ -52,18 +52,14 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
updateButtons();
}
} else {
QString key = InputDialog::getText(tr("Enter your Public Mapbox Key"), this).trimmed();
int minKeyLength = 80;
QString key = InputDialog::getText(tr("Enter your Public Mapbox Key"), this, "", false, minKeyLength).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);
}
params.put("MapboxPublicKey", key.toStdString());
updateButtons();
}
}
} else {
@@ -103,18 +99,14 @@ FrogPilotNavigationPanel::FrogPilotNavigationPanel(FrogPilotSettingsWindow *pare
updateButtons();
}
} else {
QString key = InputDialog::getText(tr("Enter your Secret Mapbox Key"), this).trimmed();
int minKeyLength = 80;
QString key = InputDialog::getText(tr("Enter your Secret Mapbox Key"), this, "", false, minKeyLength).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);
}
params.put("MapboxSecretKey", key.toStdString());
updateButtons();
}
}
} else {
@@ -325,16 +317,12 @@ void FrogPilotNavigationPanel::createKeyControl(ButtonControl *&control, const Q
control = new ButtonControl(label, "", tr("<b>Manage your \"%1\".</b>").arg(label));
QObject::connect(control, &ButtonControl::clicked, [=] {
if (control->text() == tr("ADD")) {
QString key = InputDialog::getText(tr("Enter your %1").arg(label), this).trimmed();
if (!key.startsWith(prefix)) {
key = prefix + key;
}
if (key.length() >= minLength) {
QString key = InputDialog::getText(tr("Enter your %1").arg(label), this, "", false, minLength).trimmed();
if (!key.isEmpty()) {
if (!key.startsWith(prefix)) {
key = prefix + key;
}
params.put(paramKey, key.toStdString());
} else {
ConfirmationDialog::alert(tr("Inputted key is invalid or too short!"), this);
}
} else {
if (FrogPilotConfirmationDialog::yesorno(tr("Remove your %1?").arg(label), this)) {
@@ -599,9 +599,12 @@ FrogPilotThemesPanel::FrogPilotThemesPanel(FrogPilotSettingsWindow *parent) : Fr
params.put("StartupMessageTop", frogpilotTop.toStdString());
params.put("StartupMessageBottom", frogpilotBottom.toStdString());
} else if (id == 2) {
QString currentTop = QString::fromStdString(params.get("StartupMessageTop"));
QString newTop = InputDialog::getText(tr("Enter the text for the top half"), this, tr("Characters: 0/%1").arg(maxLengthTop), false, -1, currentTop, maxLengthTop).trimmed();
if (!newTop.isEmpty()) {
params.put("StartupMessageTop", newTop.toStdString());
QString currentBottom = QString::fromStdString(params.get("StartupMessageBottom"));
QString newBottom = InputDialog::getText(tr("Enter the text for the bottom half"), this, tr("Characters: 0/%1").arg(maxLengthBottom), false, -1, currentBottom, maxLengthBottom).trimmed();
if (!newBottom.isEmpty()) {
params.put("StartupMessageBottom", newBottom.toStdString());
+1 -1
View File
@@ -313,7 +313,7 @@ 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!");
QSet<QString> rebootKeys = {"HondaAltTune", "NewLongAPI", "SubaruSNG", "TacoTuneHacks"};
QSet<QString> rebootKeys = {"HondaAltTune", "NewLongAPI", "TacoTuneHacks"};
for (const QString &key : rebootKeys) {
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [key, this](bool state) {
if (started) {
+4 -3
View File
@@ -211,9 +211,10 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(FrogPilotSettingsWindow *parent) :
{10, tr("Lateral Control: Steering Angle")},
{11, tr("Lateral Control: Torque % Used")},
{12, tr("Longitudinal Control: Actuator Acceleration Output")},
{13, tr("Longitudinal MPC Jerk: Acceleration")},
{14, tr("Longitudinal MPC Jerk: Danger Zone")},
{15, tr("Longitudinal MPC Jerk: Speed Control")},
{13, tr("Longitudinal MPC: Danger Factor")},
{14, tr("Longitudinal MPC Jerk: Acceleration")},
{15, tr("Longitudinal MPC Jerk: Danger Zone")},
{16, tr("Longitudinal MPC Jerk: Speed Control")},
};
ButtonControl *metricToggle = new ButtonControl(title, tr("SELECT"), desc);
+1 -3
View File
@@ -26,9 +26,7 @@ void FrogPilotOnroadWindow::updateState(const UIState &s, const FrogPilotUIState
showSignal = (turnSignalLeft || turnSignalRight) && frogpilot_toggles.value("signal_metrics").toBool();
showSteering = frogpilot_toggles.value("steering_metrics").toBool();
if (showBlindspot || showFPS || showSignal || showSteering) {
update();
}
update();
}
void FrogPilotOnroadWindow::paintEvent(QPaintEvent *event) {
+5 -3
View File
@@ -117,6 +117,7 @@ void DeveloperSidebar::updateState(const UIState &s, const FrogPilotUIState &fs)
accelerationStatus = ItemStatus(QPair<QString, QString>(tr("ACCEL"), QString::number(acceleration, 'f', 2) + accelerationUnit), metricColor);
accelerationJerkStatus = ItemStatus(QPair<QString, QString>(tr("ACCEL JERK"), QString::number(frogpilotPlan.getAccelerationJerk())), metricColor);
actuatorAccelerationStatus = ItemStatus(QPair<QString, QString>(tr("ACT ACCEL"), QString::number(carControl.getActuators().getAccel() * accelerationConversion, 'f', 2) + accelerationUnit), metricColor);
dangerFactorStatus = ItemStatus(QPair<QString, QString>(tr("DANGER %"), QString::number(frogpilotPlan.getDangerFactor(), 'f', 2)), metricColor);
dangerJerkStatus = ItemStatus(QPair<QString, QString>(tr("DANGER JERK"), QString::number(frogpilotPlan.getDangerJerk())), metricColor);
delayStatus = ItemStatus(QPair<QString, QString>(tr("STEER DELAY"), QString::number(liveDelay.getLateralDelay(), 'f', 5)), metricColor);
frictionStatus = ItemStatus(QPair<QString, QString>(tr("FRICTION"), QString::number(liveTorqueParameters.getFrictionCoefficientFiltered(), 'f', 5)), metricColor);
@@ -153,9 +154,10 @@ void DeveloperSidebar::paintEvent(QPaintEvent *event) {
metricMap.insert(10, &steerAngleStatus);
metricMap.insert(11, &torqueStatus);
metricMap.insert(12, &actuatorAccelerationStatus);
metricMap.insert(13, &accelerationJerkStatus);
metricMap.insert(14, &dangerJerkStatus);
metricMap.insert(15, &speedJerkStatus);
metricMap.insert(13, &dangerFactorStatus);
metricMap.insert(14, &accelerationJerkStatus);
metricMap.insert(15, &dangerJerkStatus);
metricMap.insert(16, &speedJerkStatus);
int count = 0;
for (size_t i = 0; i < metricAssignments.size(); ++i) {
@@ -28,6 +28,7 @@ private:
ItemStatus accelerationJerkStatus;
ItemStatus accelerationStatus;
ItemStatus actuatorAccelerationStatus;
ItemStatus dangerFactorStatus;
ItemStatus dangerJerkStatus;
ItemStatus delayStatus;
ItemStatus frictionStatus;
+1
View File
@@ -273,6 +273,7 @@ class CarInterface(CarInterfaceBase):
# Note: Low speed, stop and go not tested. Should be fairly smooth on highway
ret.longitudinalTuning.kiBP = [0.0, 5., 35.]
ret.longitudinalTuning.kiV = [0.0, 0.35, 0.5]
ret.longitudinalTuning.kfDEPRECATED = 0.15
ret.stoppingDecelRate = 0.8
else: # Pedal used for SNG, ACC for longitudinal control otherwise
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
+4
View File
@@ -287,6 +287,7 @@ class CarInterfaceBase(ABC):
ret.vEgoStopping = 0.5
ret.vEgoStarting = 0.5
ret.stoppingControl = True
ret.longitudinalTuning.kfDEPRECATED = 1.
ret.longitudinalTuning.kpBP = [0.]
ret.longitudinalTuning.kpV = [0.]
ret.longitudinalTuning.kiBP = [0.]
@@ -302,6 +303,9 @@ class CarInterfaceBase(ABC):
tune.init('torque')
tune.torque.useSteeringAngle = use_steering_angle
tune.torque.kp = 1.0
tune.torque.ki = 0.3
tune.torque.kd = 0.0
tune.torque.friction = params['FRICTION']
tune.torque.latAccelFactor = params['LAT_ACCEL_FACTOR']
tune.torque.latAccelOffset = 0.0
+1 -1
View File
@@ -770,7 +770,7 @@ class Controls:
if self.frogpilot_toggles.conditional_experimental_mode or self.frogpilot_toggles.slc_fallback_experimental_mode:
self.experimental_mode = self.sm['frogpilotPlan'].experimentalMode
if hasattr(self.LaC, "pid"):
if hasattr(self.LaC, "pid") and self.CP.lateralTuning.which() != "pid":
self.LaC.pid._k_p = self.frogpilot_toggles.steerKp
# Update FrogPilot variables
+28 -33
View File
@@ -16,22 +16,15 @@ from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_G
# wheel slip, or to speed.
# This controller applies torque to achieve desired lateral
# accelerations. To compensate for the low speed effects the
# proportional gain is increased at low speeds by the PID controller.
# Additionally, there is friction in the steering wheel that needs
# to be overcome to move it at all, this is compensated for too.
# accelerations. To compensate for the low speed effects we
# use a LOW_SPEED_FACTOR in the error. Additionally, there is
# friction in the steering wheel that needs to be overcome to
# move it at all, this is compensated for too.
KP = 1.0
KI = 0.1
KD = 0.3
INTERP_SPEEDS = [1, 1.5, 2.0, 3.0, 5, 7.5, 10, 15, 30]
KP_INTERP = [250, 120, 65, 30, 11.5, 5.5, 3.5, 2.0, KP]
LOW_SPEED_X = [0, 10, 20, 30]
LOW_SPEED_Y = [15, 13, 10, 5]
LP_FILTER_CUTOFF_HZ = 1.2
JERK_LOOKAHEAD_SECONDS = 0.19
JERK_GAIN = 0.3
LAT_ACCEL_REQUEST_BUFFER_SECONDS = 1.0
VERSION = 1 # bump this when changing controller
MAX_LAT_JERK_UP = 2.5 # m/s^3
class LatControlTorque(LatControl):
def __init__(self, CP, CI, dt):
@@ -39,15 +32,13 @@ class LatControlTorque(LatControl):
self.torque_params = CP.lateralTuning.torque
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
self.lateral_accel_from_torque = CI.lateral_accel_from_torque()
self.pid = PIDController([INTERP_SPEEDS, KP_INTERP], KI, KD, rate=1/self.dt)
self.pid = PIDController(self.torque_params.kp, self.torque_params.ki, rate=1/self.dt)
self.update_limits()
self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg
self.lookahead_frames = int(JERK_LOOKAHEAD_SECONDS / self.dt)
self.lat_accel_request_buffer_len = int(LAT_ACCEL_REQUEST_BUFFER_SECONDS / self.dt)
self.lat_accel_request_buffer = deque([0.] * self.lat_accel_request_buffer_len , maxlen=self.lat_accel_request_buffer_len)
self.jerk_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * LP_FILTER_CUTOFF_HZ), self.dt)
self.measurement_rate_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * LP_FILTER_CUTOFF_HZ), self.dt)
self.LATACCEL_REQUEST_BUFFER_NUM_FRAMES = int(1 / self.dt)
self.requested_lateral_accel_buffer = deque([0.] * self.LATACCEL_REQUEST_BUFFER_NUM_FRAMES , maxlen=self.LATACCEL_REQUEST_BUFFER_NUM_FRAMES)
self.previous_measurement = 0.0
self.measurement_rate_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * (MAX_LAT_JERK_UP - 0.5)), self.dt)
def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
self.torque_params.latAccelFactor = latAccelFactor
@@ -61,7 +52,6 @@ class LatControlTorque(LatControl):
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, curvature_limited, lat_delay, llk, model_data, frogpilot_toggles):
pid_log = log.ControlsState.LateralTorqueState.new_message()
pid_log.version = VERSION
if not active:
output_torque = 0.0
pid_log.active = False
@@ -71,31 +61,37 @@ class LatControlTorque(LatControl):
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2
delay_frames = int(np.clip(lat_delay / self.dt, 1, self.lat_accel_request_buffer_len))
expected_lateral_accel = self.lat_accel_request_buffer[-delay_frames]
lookahead_idx = int(np.clip(-delay_frames + self.lookahead_frames, -self.lat_accel_request_buffer_len+1, -2))
raw_lateral_jerk = (self.lat_accel_request_buffer[lookahead_idx+1] - self.lat_accel_request_buffer[lookahead_idx-1]) / (2 * self.dt)
desired_lateral_jerk = self.jerk_filter.update(raw_lateral_jerk)
delay_frames = int(np.clip(lat_delay / self.dt, 1, self.LATACCEL_REQUEST_BUFFER_NUM_FRAMES))
expected_lateral_accel = self.requested_lateral_accel_buffer[-delay_frames]
# TODO factor out lateral jerk from error to later replace it with delay independent alternative
future_desired_lateral_accel = desired_curvature * CS.vEgo ** 2
self.lat_accel_request_buffer.append(future_desired_lateral_accel)
self.requested_lateral_accel_buffer.append(future_desired_lateral_accel)
gravity_adjusted_future_lateral_accel = future_desired_lateral_accel - roll_compensation
setpoint = expected_lateral_accel
desired_lateral_jerk = (future_desired_lateral_accel - expected_lateral_accel) / lat_delay
measurement = measured_curvature * CS.vEgo ** 2
measurement_rate = self.measurement_rate_filter.update((measurement - self.previous_measurement) / self.dt)
self.previous_measurement = measurement
low_speed_factor = (np.interp(CS.vEgo, LOW_SPEED_X, LOW_SPEED_Y) / max(CS.vEgo, MIN_SPEED)) ** 2
setpoint = lat_delay * desired_lateral_jerk + expected_lateral_accel
error = setpoint - measurement
error_lsf = error + low_speed_factor / self.torque_params.kp * error
# do error correction in lateral acceleration space, convert at end to handle non-linear torque responses correctly
pid_log.error = float(error)
pid_log.error = float(error_lsf)
ff = gravity_adjusted_future_lateral_accel
# latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll
ff -= self.torque_params.latAccelOffset
ff += get_friction(error + JERK_GAIN * desired_lateral_jerk, lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params)
# TODO jerk is weighted by lat_delay for legacy reasons, but should be made independent of it
ff += get_friction(error, lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params)
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
output_lataccel = self.pid.update(pid_log.error, -measurement_rate, CS.vEgo, ff, freeze_integrator)
output_lataccel = self.pid.update(pid_log.error,
-measurement_rate,
feedforward=ff,
speed=CS.vEgo,
freeze_integrator=freeze_integrator)
output_torque = self.torque_from_lateral_accel(output_lataccel, self.torque_params)
pid_log.active = True
@@ -103,10 +99,9 @@ class LatControlTorque(LatControl):
pid_log.i = float(self.pid.i)
pid_log.d = float(self.pid.d)
pid_log.f = float(self.pid.f)
pid_log.output = float(-output_torque) # TODO: log lat accel?
pid_log.output = float(-output_torque) # TODO: log lat accel?
pid_log.actualLateralAccel = float(measurement)
pid_log.desiredLateralAccel = float(setpoint)
pid_log.desiredLateralJerk = float(desired_lateral_jerk)
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited))
# TODO left is positive in this convention
+1 -1
View File
@@ -92,7 +92,7 @@ class LongControl:
self.long_control_state = LongCtrlState.off
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
rate=1 / DT_CTRL)
k_f=CP.longitudinalTuning.kfDEPRECATED, rate=1 / DT_CTRL)
self.v_pid = 0.0
self.last_output_accel = 0.0
@@ -350,7 +350,7 @@ class LongitudinalMpc:
lead_xv = self.extrapolate_lead(x_lead, v_lead, a_lead, a_lead_tau)
return lead_xv
def update(self, radarstate, v_cruise, x, v, a, j, t_follow, personality=log.LongitudinalPersonality.standard):
def update(self, radarstate, v_cruise, x, v, a, j, danger_factor, t_follow, personality=log.LongitudinalPersonality.standard):
v_ego = self.x0[1]
self.status = radarstate.leadOne.status or radarstate.leadTwo.status
@@ -368,7 +368,7 @@ class LongitudinalMpc:
# Update in ACC mode or ACC/e2e blend
if self.mode == 'acc':
self.params[:,5] = LEAD_DANGER_FACTOR
self.params[:,5] = danger_factor
# Fake an obstacle for cruise, this ensures smooth acceleration to set speed
# when the leads are no factor.
@@ -155,7 +155,7 @@ class LongitudinalPlanner:
self.mpc.set_weights(sm['frogpilotPlan'].accelerationJerk, sm['frogpilotPlan'].dangerJerk, sm['frogpilotPlan'].speedJerk, prev_accel_constraint, personality=sm['controlsState'].personality)
self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired)
self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, sm['frogpilotPlan'].tFollow, personality=sm['controlsState'].personality)
self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, sm['frogpilotPlan'].dangerFactor, sm['frogpilotPlan'].tFollow, personality=sm['controlsState'].personality)
self.a_desired_trajectory_full = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.a_solution)
self.v_desired_trajectory = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.v_solution)
+3 -2
View File
@@ -2,10 +2,11 @@ import numpy as np
from numbers import Number
class PIDController:
def __init__(self, k_p, k_i, k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100):
def __init__(self, k_p, k_i, k_f=1., k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100):
self._k_p = k_p
self._k_i = k_i
self._k_d = k_d
self.k_f = k_f # feedforward gain
if isinstance(self._k_p, Number):
self._k_p = [[0], [self._k_p]]
if isinstance(self._k_i, Number):
@@ -47,7 +48,7 @@ class PIDController:
self.speed = speed
self.p = self.k_p * float(error)
self.d = self.k_d * error_rate
self.f = feedforward
self.f = self.k_f * feedforward
if not freeze_integrator:
i = self.i + self.k_i * self.i_dt * error
+14 -17
View File
@@ -110,8 +110,8 @@ class Track:
"radarTrackId": self.identifier,
}
def potential_adjacent_lead(self, left: bool, standstill: bool, model_data: capnp._DynamicStructReader):
if standstill or self.vLead < 1 or self.leadTrackID == self.identifier:
def potential_adjacent_lead(self, left: bool, model_data: capnp._DynamicStructReader):
if self.vLeadK < 1 or self.leadTrackID == self.identifier:
return False
far_left_lane = interp(self.dRel, model_data.laneLines[0].x, model_data.laneLines[0].y)
@@ -119,22 +119,19 @@ class Track:
right_lane = interp(self.dRel, model_data.laneLines[2].x, model_data.laneLines[2].y)
far_right_lane = interp(self.dRel, model_data.laneLines[3].x, model_data.laneLines[3].y)
self.leadLeft = far_left_lane < -self.yRel < left_lane
self.leadRight = right_lane < -self.yRel < far_right_lane
self.leadLeft = far_left_lane < -self.yRel < left_lane and self.dRel < model_data.position.x[-1]
self.leadRight = right_lane < -self.yRel < far_right_lane and self.dRel < model_data.position.x[-1]
if left:
return self.leadLeft
else:
return self.leadRight
def potential_far_lead(self, standstill: bool, model_data: capnp._DynamicStructReader):
if standstill or self.vLead < 1:
return False
def potential_far_lead(self, lead_msg: capnp._DynamicStructReader, model_data: capnp._DynamicStructReader):
left_lane = interp(self.dRel, model_data.laneLines[1].x, model_data.laneLines[1].y)
right_lane = interp(self.dRel, model_data.laneLines[2].x, model_data.laneLines[2].y)
if left_lane < -self.yRel < right_lane:
if left_lane < -self.yRel < right_lane and self.dRel < model_data.position.x[-1] and (self.vLeadK > 1 or lead_msg.prob > 0.25):
self.radarfulFilter.update(1)
return True
else:
@@ -214,7 +211,7 @@ def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: floa
def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capnp._DynamicStructReader,
model_v_ego: float, model_data: capnp._DynamicStructReader, standstill: bool,
model_v_ego: float, model_data: capnp._DynamicStructReader,
frogpilot_plan: capnp._DynamicStructReader, frogpilot_toggles: SimpleNamespace,
low_speed_override: bool = True) -> dict[str, Any]:
# Determine leads, this is where the essential logic happens
@@ -239,7 +236,7 @@ def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capn
lead_dict = closest_track.get_RadarState()
if not lead_dict['status'] and len(tracks) > 0:
far_lead_tracks = [c for c in tracks.values() if c.potential_far_lead(standstill, model_data) and c.radarfulFilter.x >= THRESHOLD]
far_lead_tracks = [c for c in tracks.values() if c.potential_far_lead(lead_msg, model_data) and c.radarfulFilter.x >= THRESHOLD]
if len(far_lead_tracks) > 0:
closest_track = min(far_lead_tracks, key=lambda c: c.dRel)
lead_dict = closest_track.get_RadarState()
@@ -253,10 +250,10 @@ def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capn
return lead_dict
def get_adjacent_lead(tracks: dict[int, Track], standstill: bool, model_data: capnp._DynamicStructReader, left: bool = True) -> dict[str, Any]:
def get_adjacent_lead(tracks: dict[int, Track], model_data: capnp._DynamicStructReader, left: bool = True) -> dict[str, Any]:
lead_dict = {'status': False}
adjacent_tracks = [c for c in tracks.values() if c.potential_adjacent_lead(left, standstill, model_data)]
adjacent_tracks = [c for c in tracks.values() if c.potential_adjacent_lead(left, model_data)]
if len(adjacent_tracks) > 0:
closest_track = min(adjacent_tracks, key=lambda c: c.dRel)
lead_dict = closest_track.get_RadarState()
@@ -336,12 +333,12 @@ class RadarD:
model_v_ego = self.v_ego
leads_v3 = sm['modelV2'].leadsV3
if len(leads_v3) > 1:
self.radar_state.leadOne = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[0], model_v_ego, sm['modelV2'], sm['carState'].standstill, sm['frogpilotPlan'], self.frogpilot_toggles, low_speed_override=True)
self.radar_state.leadTwo = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[1], model_v_ego, sm['modelV2'], sm['carState'].standstill, sm['frogpilotPlan'], self.frogpilot_toggles, low_speed_override=False)
self.radar_state.leadOne = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[0], model_v_ego, sm['modelV2'], sm['frogpilotPlan'], self.frogpilot_toggles, low_speed_override=True)
self.radar_state.leadTwo = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[1], model_v_ego, sm['modelV2'], sm['frogpilotPlan'], self.frogpilot_toggles, low_speed_override=False)
if (self.frogpilot_toggles.adjacent_lead_tracking or self.frogpilot_toggles.human_lane_changes) and self.ready:
self.frogpilot_radar_state.leadLeft = get_adjacent_lead(self.tracks, sm['carState'].standstill, sm['modelV2'], left=True)
self.frogpilot_radar_state.leadRight = get_adjacent_lead(self.tracks, sm['carState'].standstill, sm['modelV2'], left=False)
self.frogpilot_radar_state.leadLeft = get_adjacent_lead(self.tracks, sm['modelV2'], left=True)
self.frogpilot_radar_state.leadRight = get_adjacent_lead(self.tracks, sm['modelV2'], left=False)
# Update FrogPilot variables
if sm['frogpilotPlan'].togglesUpdated:
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">عزم</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">عامل الخطر</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% من</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">شخصيات القيادة</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">الوقت المستغرق في الطقس</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">حدث خطأ: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">عدد الأحرف: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3217,10 +3233,6 @@ It will reset in %1 hours and %2 minutes.</source>
<source>Enter your %1</source>
<translation type="gpt-5-generated">أدخل %1 الخاص بك</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">المفتاح المُدخل غير صالح أو قصير جدًا!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">هل تريد إزالة %1؟</translation>
@@ -5024,6 +5036,10 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;اضبط سماكة حافة الطريق.&lt;/b&gt;&lt;br&gt;&lt;br&gt;القيمة الافتراضية تطابق نصف معيار MUTCD لعرض خط المسار وهو 10 سنتيمترات.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">عامل الخطر لمنظّم الحركة الطولي (MPC)</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -254,6 +254,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">TORQUE %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">DANGER FACTOR</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -967,6 +971,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% of</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Drive Personality:</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Time Spent in Sky Mood:</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2608,6 +2620,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Error happen: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Marks: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3219,10 +3235,6 @@ It reset in %1 hour and %2 minute.</translation>
<source>Enter your %1</source>
<translation type="gpt-5-generated">You put %1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">Key bad or too short!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">You remove %1?</translation>
@@ -5030,6 +5042,10 @@ Developer - Many custom setting for seasoned enthusiast</translation>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Set road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default same as half MUTCD lane-line width standard, 10 centimeters.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">Longitudinal MPC: Danger Factor</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">DREHMOMENT %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">GEFAHRENFAKTOR</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% von</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Fahrprofile:</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Verbrachte Zeit bei Wetterbedingungen:</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Ein Fehler ist aufgetreten: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Zeichen: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3217,10 +3233,6 @@ Es wird in %1 Stunden und %2 Minuten zurückgesetzt.</translation>
<source>Enter your %1</source>
<translation type="gpt-5-generated">Geben Sie Ihr %1 ein</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">Eingegebener Schlüssel ist ungültig oder zu kurz!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">Entfernen Sie Ihr %1?</translation>
@@ -5024,6 +5036,10 @@ Entwickler Hochgradig anpassbare Einstellungen für versierte Enthusiasten</
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Stellen Sie die Randstreifendicke ein.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Standard entspricht der Hälfte des MUTCD-Standards für Fahrbahnmarkierungsbreite von 10 Zentimetern.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">Längsdynamik-MPC: Gefahrenfaktor</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">Quack! TORQUE % waddle-whoosh!</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">QUACK DANGER FACTOR WADDLE!</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">Quack % of quack!</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Quack-Quack Driving Personalities: Waddle!</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Quack Time in Weather: Waddle Waddle!</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2608,6 +2620,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Quack! An error splashed in: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Quack-acters: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3219,10 +3235,6 @@ Waddle back later—resets in %1 hours and %2 minutes.</translation>
<source>Enter your %1</source>
<translation type="gpt-5-generated">Quack! Waddle in your %1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">Quack! That keys invalid or too short, waddley-woot!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">Quack! Remove your %1, waddly-waddle?</translation>
@@ -5026,6 +5038,10 @@ Developer - Ultra-custom settings for seasoned duckthusiasts</translation>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Quack! Set the road-edge thickness, waddlers.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default quacks to half the MUTCD lane-line width standard of 10 centimeters.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">Longitudinal MPC: Quack! Danger Factor 🦆</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">PAR %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">FACTOR DE PELIGRO</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% de</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Personalidades de conducción</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Tiempo en el clima</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Ocurrió un error: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Caracteres: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3216,10 +3232,6 @@ Se restablecerá en %1 horas y %2 minutos.</translation>
<source>Enter your %1</source>
<translation type="gpt-5-generated">Introduce tu %1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">¡La clave introducida es inválida o demasiado corta!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">¿Quitar su %1?</translation>
@@ -5023,6 +5035,10 @@ Desarrollador: configuración altamente personalizable para entusiastas veterano
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Establece el grosor del borde de la carretera.&lt;/b&gt;&lt;br&gt;&lt;br&gt;El valor predeterminado coincide con la mitad del estándar MUTCD de ancho de línea de carril de 10 centímetros.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">MPC longitudinal: factor de peligro</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">COUPLE %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">FACTEUR DE DANGER</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% de</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Personnalités de conduite</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Temps passé par météo</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Une erreur sest produite : %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Caractères : 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3216,10 +3232,6 @@ Elle sera réinitialisée dans %1 heures et %2 minutes.</translation>
<source>Enter your %1</source>
<translation type="gpt-5-generated">Saisissez votre %1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">La clé saisie est invalide ou trop courte !</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">Retirer votre %1 ?</translation>
@@ -5023,6 +5035,10 @@ Développeur Paramètres hautement personnalisables pour passionnés chevron
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Réglez lépaisseur du bord de route.&lt;/b&gt;&lt;br&gt;&lt;br&gt;La valeur par défaut correspond à la moitié de la largeur standard des lignes de voie du MUTCD, soit 10 centimètres.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">MPC longitudinal : facteur de danger</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">Ribbit TORQUE % croak</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">RIBBIT DANGER FACTOR CROAK</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">Ribbit % of croak</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Ribbit Rides: Croak-sonalities!</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Ribbit! Time Spent in Weather, croak!</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Ribbit! An error croaked up: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Ribbit: 0/%1 croak</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3217,10 +3233,6 @@ Itll reset in %1 hours and %2 minutes.</translation>
<source>Enter your %1</source>
<translation type="gpt-5-generated">Ribbit! Enter your %1, croak.</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">Ribbit! That keys no good or too tiny, croak!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">Ribbit! Remove your %1? Croak!</translation>
@@ -5024,6 +5036,10 @@ Developer - Highly customizable settings for seasoned swamp pros</translation>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Croak! Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default ribbits to half the MUTCD lane-line width standard of 10 centimeters.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">Ribbit-longitudinal MPC: Danger Factor, croak!</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated"> %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated"></translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% </translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated"></translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated"></translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">文字数: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3215,10 +3231,6 @@ It will reset in %1 hours and %2 minutes.</source>
<source>Enter your %1</source>
<translation type="gpt-5-generated">%1 </translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated"></translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">%1 ?</translation>
@@ -5022,6 +5034,10 @@ Developer - こだわりのある上級者向けの高度にカスタマイズ
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;MUTCD10</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">MPC</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated"> %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated"> </translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% </translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated"> :"</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated"> </translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated"> : %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">문자: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3216,10 +3232,6 @@ It will reset in %1 hours and %2 minutes.</source>
<source>Enter your %1</source>
<translation type="gpt-5-generated">%1() </translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated"> !</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">%1() ?</translation>
@@ -5023,6 +5035,10 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt; .&lt;/b&gt;&lt;br&gt;&lt;br&gt; MUTCD 10 .</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated"> MPC: 위험 </translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">TORQUE %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">DANGER FACTOR, ye scallywag</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% o</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Sailin Personalities:</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Time Spent in Thar Weather:</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Arr, an error befall'd: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Characters: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3217,10 +3233,6 @@ Itll reset in %1 hours n %2 minutes.</translation>
<source>Enter your %1</source>
<translation type="gpt-5-generated">Avast! Enter yer %1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">Arr, the key ye entered be invalid or too short!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">Be ye removin yer %1?</translation>
@@ -5024,6 +5036,10 @@ Developer - Highly customizable riggins fer seasoned enthusiasts</translation
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Set th road-edge thickness, ye landlubber.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default be half o the MUTCD lane-line width standard o 10 centimeters.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">Longitudinal MPC: Peril Factor</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">TORQUE %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">FATOR DE PERIGO</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% de</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Personalidades de Condução</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Tempo gasto em clima:</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Ocorreu um erro: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Caracteres: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3217,10 +3233,6 @@ Ele será reiniciado em %1 horas e %2 minutos.</translation>
<source>Enter your %1</source>
<translation type="gpt-5-generated">Insira seu %1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">A chave inserida é inválida ou muito curta!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">Remover seu %1?</translation>
@@ -5024,6 +5036,10 @@ Desenvolvedor - Configurações altamente personalizáveis para entusiastas expe
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Defina a espessura da borda da estrada.&lt;/b&gt;&lt;br&gt;&lt;br&gt;O padrão corresponde à metade do padrão de largura de faixa do MUTCD de 10 centímetros.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">MPC Longitudinal: Fator de Perigo</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">TORQUE %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">PERILOUS FACTOR</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -971,6 +975,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% of</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Driving Dispositions:</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Time Bestowd in Tempest:</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2615,6 +2627,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">An error hath occurred: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Characters: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3226,10 +3242,6 @@ It shall reset in %1 hours and %2 minutes.</translation>
<source>Enter your %1</source>
<translation type="gpt-5-generated">Enter thy %1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">The key thou hast entered is invalid or too brief!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">Wilt thou remove thy %1?</translation>
@@ -5039,6 +5051,10 @@ Developer - Most customizable settings for well-tried enthusiasts</translation>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;The default doth match half the MUTCD lane-line width standard of 10 centimeters.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">Longitudinal MPC: Peril Factor</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated"> %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated"></translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% </translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated"></translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated"></translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">อักขระ: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3217,10 +3233,6 @@ It will reset in %1 hours and %2 minutes.</source>
<source>Enter your %1</source>
<translation type="gpt-5-generated"> %1 </translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated"> %1 ?</translation>
@@ -5024,6 +5036,10 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt; MUTCD 10 </translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">MPC ตามยาว: ปัจจัยอันตราย</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated">TORK %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">TEHLİKE FAKTÖRÜ</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% of</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Sürüş Kişilikleri</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Havada Geçirilen Süre:</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Bir hata oluştu: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Karakterler: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3216,10 +3232,6 @@ It will reset in %1 hours and %2 minutes.</source>
<source>Enter your %1</source>
<translation type="gpt-5-generated">%1 girin</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated">Girilen anahtar geçersiz veya çok kısa!</translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">%1 öğenizi kaldırın?</translation>
@@ -5023,6 +5035,10 @@ Geliştirici - Tecrübeli meraklılar için yüksek özelleştirilebilir ayarlar
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;Yol kenarı kalınlığını ayarlayın.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Varsayılan, MUTCD şerit çizgisi genişliği standardı olan 10 santimetrenin yarısına karşılık gelir.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">Boylamsal MPC: Tehlike Faktörü</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation>МОМЕНТ %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated">ФАКТОР НЕБЕЗПЕКИ</translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% від</translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated">Стилі водіння</translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated">Час, проведений у погодних умовах:</translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">Сталася помилка: %1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">Символи: 0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3125,10 +3141,6 @@
<source>Enter your %1</source>
<translation>Введіть ваш %1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation>Введений ключ недійсний або занадто короткий!</translation>
</message>
<message>
<source>REMOVE</source>
<translation>ПРИБРАТИ</translation>
@@ -5024,6 +5036,10 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation>&lt;b&gt;Встановіть товщину краю дороги.&lt;/b&gt;&lt;br&gt;&lt;br&gt;За замовчуванням встановлюється половина стандартної ширини смуги руху MUTCD, яка становить 10 сантиметрів.</translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">Поздовжній MPC: Фактор небезпеки</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated"> %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated"></translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% </translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated"></translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated"></translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">%1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3217,10 +3233,6 @@ It will reset in %1 hours and %2 minutes.</source>
<source>Enter your %1</source>
<translation type="gpt-5-generated">%1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated"></translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated">%1</translation>
@@ -5024,6 +5036,10 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt; MUTCD 线 10 </translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated">MPC</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+20 -4
View File
@@ -253,6 +253,10 @@
<source>TORQUE %</source>
<translation type="gpt-5-generated"> %</translation>
</message>
<message>
<source>DANGER FACTOR</source>
<translation type="gpt-5-generated"></translation>
</message>
</context>
<context>
<name>DevicePanel</name>
@@ -966,6 +970,14 @@
<source>% of </source>
<translation type="gpt-5-generated">% </translation>
</message>
<message>
<source>Driving Personalities:</source>
<translation type="gpt-5-generated"></translation>
</message>
<message>
<source>Time Spent in Weather:</source>
<translation type="gpt-5-generated"></translation>
</message>
</context>
<context>
<name>FrogPilotDevicePanel</name>
@@ -2606,6 +2618,10 @@
<source>An error occurred: %1</source>
<translation type="gpt-5-generated">%1</translation>
</message>
<message>
<source>Characters: 0/%1</source>
<translation type="gpt-5-generated">0/%1</translation>
</message>
</context>
<context>
<name>FrogPilotManageControl</name>
@@ -3217,10 +3233,6 @@ It will reset in %1 hours and %2 minutes.</source>
<source>Enter your %1</source>
<translation type="gpt-5-generated"> %1</translation>
</message>
<message>
<source>Inputted key is invalid or too short!</source>
<translation type="gpt-5-generated"></translation>
</message>
<message>
<source>Remove your %1?</source>
<translation type="gpt-5-generated"> %1 </translation>
@@ -5024,6 +5036,10 @@ Developer - 為資深愛好者提供高度自訂的設定</translation>
<source>&lt;b&gt;Set the road-edge thickness.&lt;/b&gt;&lt;br&gt;&lt;br&gt;Default matches half of the MUTCD lane-line width standard of 10 centimeters.</source>
<translation type="gpt-5-generated">&lt;b&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt; MUTCD 10 </translation>
</message>
<message>
<source>Longitudinal MPC: Danger Factor</source>
<translation type="gpt-5-generated"> MPC</translation>
</message>
</context>
<context>
<name>FrogPilotWheelPanel</name>
+3
View File
@@ -404,6 +404,9 @@ void Device::setAwake(bool on) {
void Device::resetInteractiveTimeout(int timeout, int timeout_onroad) {
if (timeout == -1) {
timeout = (ignition_on ? 10 : 30);
} else {
// FrogPilot variables
timeout = (ignition_on ? timeout_onroad : timeout);
}
interactive_timeout = timeout * UI_FREQ;
}