diff --git a/.github/workflows/sunnypilot-master-dev-prep.yaml b/.github/workflows/sunnypilot-master-dev-prep.yaml index 122755f2c4..4aafd4a4a4 100644 --- a/.github/workflows/sunnypilot-master-dev-prep.yaml +++ b/.github/workflows/sunnypilot-master-dev-prep.yaml @@ -118,8 +118,8 @@ jobs: run: | # Use GitHub API to get PRs with specific label, ordered by creation date PR_LIST=$(gh api graphql -f query=' - query($label:String!) { - search(query: $label, type:ISSUE, first:100) { + query($search_query:String!) { + search(query: $search_query, type:ISSUE, first:100) { nodes { ... on PullRequest { number @@ -149,7 +149,7 @@ jobs: } } } - }' -F label="is:pr is:open label:${PR_LABEL} draft:false sort:created-asc") + }' -F search_query="repo:${{ github.repository }} is:pr is:open label:${PR_LABEL},${PR_LABEL}-c3 draft:false sort:created-asc") PR_LIST=${PR_LIST//\'/} echo "PR_LIST=${PR_LIST}" >> $GITHUB_OUTPUT diff --git a/cereal/custom.capnp b/cereal/custom.capnp index 44b8bd69fa..5c0a004fa6 100644 --- a/cereal/custom.capnp +++ b/cereal/custom.capnp @@ -69,6 +69,48 @@ struct LeadData { struct SelfdriveStateSP @0x81c2f05a394cf4af { mads @0 :ModularAssistiveDrivingSystem; intelligentCruiseButtonManagement @1 :IntelligentCruiseButtonManagement; + + enum AudibleAlert { + none @0; + + engage @1; + disengage @2; + refuse @3; + + warningSoft @4; + warningImmediate @5; + + prompt @6; + promptRepeat @7; + promptDistracted @8; + + # unused, these are reserved for upstream events so we don't collide + reserved9 @9; + reserved10 @10; + reserved11 @11; + reserved12 @12; + reserved13 @13; + reserved14 @14; + reserved15 @15; + reserved16 @16; + reserved17 @17; + reserved18 @18; + reserved19 @19; + reserved20 @20; + reserved21 @21; + reserved22 @22; + reserved23 @23; + reserved24 @24; + reserved25 @25; + reserved26 @26; + reserved27 @27; + reserved28 @28; + reserved29 @29; + reserved30 @30; + + promptSingleLow @31; + promptSingleHigh @32; + } } struct ModelManagerSP @0xaedffd8f31e7b55d { @@ -404,13 +446,13 @@ struct LiveMapDataSP @0xf416ec09499d9d19 { struct ModelDataV2SP @0xa1680744031fdb2d { laneTurnDirection @0 :TurnDirection; -} enum TurnDirection { none @0; turnLeft @1; turnRight @2; } +} struct CustomReserved10 @0xcb9fd56c7057593a { } diff --git a/common/params_keys.h b/common/params_keys.h index 0844fff2bf..dd58462a95 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -150,6 +150,7 @@ inline static std::unordered_map keys = { {"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}}, {"GreenLightAlert", {PERSISTENT | BACKUP, BOOL, "0"}}, {"GithubRunnerSufficientVoltage", {CLEAR_ON_MANAGER_START , BOOL}}, + {"HideVEgoUI", {PERSISTENT | BACKUP, BOOL, "0"}}, {"IntelligentCruiseButtonManagement", {PERSISTENT | BACKUP , BOOL}}, {"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}}, {"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}}, @@ -159,14 +160,17 @@ inline static std::unordered_map keys = { {"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}}, {"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}}, {"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}}, - {"OnroadScreenOffBrightness", {PERSISTENT | BACKUP, INT, "100"}}, + {"OnroadScreenOffBrightness", {PERSISTENT | BACKUP, INT, "0"}}, {"OnroadScreenOffControl", {PERSISTENT | BACKUP, BOOL}}, - {"OnroadScreenOffTimer", {PERSISTENT | BACKUP, INT, "0"}}, + {"OnroadScreenOffTimer", {PERSISTENT | BACKUP, INT, "15"}}, + {"OnroadUploads", {PERSISTENT | BACKUP, BOOL, "1"}}, {"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}}, {"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}}, {"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}}, {"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"ShowTurnSignals", {PERSISTENT | BACKUP, BOOL, "0"}}, {"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"TrueVEgoUI", {PERSISTENT | BACKUP, BOOL, "0"}}, // MADS params {"Mads", {PERSISTENT | BACKUP, BOOL, "1"}}, @@ -193,6 +197,7 @@ inline static std::unordered_map keys = { {"SunnylinkDongleId", {PERSISTENT, STRING}}, {"SunnylinkdPid", {PERSISTENT, INT}}, {"SunnylinkEnabled", {PERSISTENT, BOOL, "1"}}, + {"SunnylinkTempFault", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0"}}, // Backup Manager params {"BackupManager_CreateBackup", {PERSISTENT, BOOL}}, @@ -200,6 +205,8 @@ inline static std::unordered_map keys = { // sunnypilot car specific params {"HyundaiLongitudinalTuning", {PERSISTENT | BACKUP, INT, "0"}}, + {"SubaruStopAndGo", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"SubaruStopAndGoManualParkingBrake", {PERSISTENT | BACKUP, BOOL, "0"}}, {"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}}, {"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}}, @@ -242,4 +249,13 @@ inline static std::unordered_map keys = { {"MapTargetVelocities", {CLEAR_ON_ONROAD_TRANSITION, STRING}}, {"SmartCruiseControlMap", {PERSISTENT | BACKUP, BOOL, "0"}}, {"SmartCruiseControlVision", {PERSISTENT | BACKUP, BOOL, "0"}}, + + // Torque lateral control custom params + {"CustomTorqueParams", {PERSISTENT | BACKUP , BOOL}}, + {"EnforceTorqueControl", {PERSISTENT | BACKUP, BOOL}}, + {"LiveTorqueParamsToggle", {PERSISTENT | BACKUP , BOOL}}, + {"LiveTorqueParamsRelaxedToggle", {PERSISTENT | BACKUP , BOOL}}, + {"TorqueParamsOverrideEnabled", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"TorqueParamsOverrideFriction", {PERSISTENT | BACKUP, FLOAT, "0.1"}}, + {"TorqueParamsOverrideLatAccelFactor", {PERSISTENT | BACKUP, FLOAT, "2.5"}}, }; diff --git a/docs/CARS.md b/docs/CARS.md index dbc1dbcd74..25f84b389e 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,7 +4,7 @@ A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. -# 334 Supported Cars +# 337 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video|Setup Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| @@ -83,7 +83,7 @@ A supported vehicle is one that just works when you install a comma device. All |Honda|Civic Hatchback 2017-18|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Civic Hatchback 2019-21|All|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Civic Hatchback 2022-24|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Civic Hatchback Hybrid 2025|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Civic Hatchback Hybrid 2025-26|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Civic Hybrid 2025|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Clarity 2018-21|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Nidec connector + Honda Clarity Proxy Board
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| @@ -99,7 +99,9 @@ A supported vehicle is one that just works when you install a comma device. All |Honda|HR-V 2023-25|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|N-Box 2018|All|openpilot available[1](#footnotes)|0 mph|11 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Odyssey 2021-25|All|openpilot available[1](#footnotes)|0 mph|43 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Honda|Pilot 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch C connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| @@ -163,6 +165,7 @@ A supported vehicle is one that just works when you install a comma device. All |Kia|EV6 (without HDA II) 2022-24[6](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Kia|K8 Hybrid (with HDA II) 2023[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| @@ -259,7 +262,7 @@ A supported vehicle is one that just works when you install a comma device. All |Tesla[11](#footnotes)|Model 3 (with HW3) 2019-23[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Tesla[11](#footnotes)|Model 3 (with HW4) 2024-25[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla B connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Tesla[11](#footnotes)|Model Y (with HW3) 2020-23[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Tesla[11](#footnotes)|Model Y (with HW4) 2024[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla B connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Tesla[11](#footnotes)|Model Y (with HW4) 2024-25[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla B connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| |Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| diff --git a/opendbc_repo b/opendbc_repo index 45a41145d9..e9ae857746 160000 --- a/opendbc_repo +++ b/opendbc_repo @@ -1 +1 @@ -Subproject commit 45a41145d9c79cd20610053b0a0ec6d1329d47d0 +Subproject commit e9ae8577467ba58761b0edacd2e523cde60daed3 diff --git a/selfdrive/assets/sounds/prompt_single_high.wav b/selfdrive/assets/sounds/prompt_single_high.wav new file mode 100644 index 0000000000..202483d17f --- /dev/null +++ b/selfdrive/assets/sounds/prompt_single_high.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dbfa5858c0a672411ffdc691efdecb06d01ae458cc1df409bcf3fdeaa4756f72 +size 34638 diff --git a/selfdrive/assets/sounds/prompt_single_low.wav b/selfdrive/assets/sounds/prompt_single_low.wav new file mode 100644 index 0000000000..925401ea27 --- /dev/null +++ b/selfdrive/assets/sounds/prompt_single_low.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db9671bb03e01f119bba1eb6cc0507e0f039ac4e5b7f9f839a87071c52e86e56 +size 44416 diff --git a/selfdrive/car/helpers.py b/selfdrive/car/helpers.py index a7abc1976c..384152c71b 100644 --- a/selfdrive/car/helpers.py +++ b/selfdrive/car/helpers.py @@ -57,7 +57,7 @@ def convert_carControlSP(struct: capnp.lib.capnp._DynamicStructReader) -> struct struct_dataclass = structs.CarControlSP(**remove_deprecated({k: v for k, v in struct_dict.items() if not isinstance(k, dict)})) struct_dataclass.mads = structs.ModularAssistiveDrivingSystem(**remove_deprecated(struct_dict.get('mads', {}))) - struct_dataclass.params = [structs.CarControlSP.Param(**remove_deprecated(p)) for p in struct_dict.get('params', [])] + # struct_dataclass.params = [structs.CarControlSP.Param(**remove_deprecated(p)) for p in struct_dict.get('params', [])] struct_dataclass.leadOne = structs.LeadData(**remove_deprecated(struct_dict.get('leadOne', {}))) struct_dataclass.leadTwo = structs.LeadData(**remove_deprecated(struct_dict.get('leadTwo', {}))) struct_dataclass.intelligentCruiseButtonManagement = structs.IntelligentCruiseButtonManagement( diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 3601ae310e..1694afee23 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -99,7 +99,6 @@ class Controls(ControlsExt, ModelStateBase): self.LaC.extension.update_model_v2(self.sm['modelV2']) - self.lat_delay = get_lat_delay(self.params, self.sm["liveDelay"].lateralDelay) self.LaC.extension.update_lateral_lag(self.lat_delay) long_plan = self.sm['longitudinalPlan'] @@ -234,6 +233,9 @@ class Controls(ControlsExt, ModelStateBase): while not evt.is_set(): self.get_params_sp() + if self.CP.lateralTuning.which() == 'torque': + self.lat_delay = get_lat_delay(self.params, self.sm["liveDelay"].lateralDelay) + time.sleep(0.1) def run(self): diff --git a/selfdrive/controls/lib/desire_helper.py b/selfdrive/controls/lib/desire_helper.py index e72d464d06..16908fa3e3 100644 --- a/selfdrive/controls/lib/desire_helper.py +++ b/selfdrive/controls/lib/desire_helper.py @@ -6,6 +6,7 @@ from openpilot.sunnypilot.selfdrive.controls.lib.lane_turn_desire import LaneTur LaneChangeState = log.LaneChangeState LaneChangeDirection = log.LaneChangeDirection +TurnDirection = custom.ModelDataV2SP.TurnDirection LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS LANE_CHANGE_TIME_MAX = 10. @@ -32,9 +33,9 @@ DESIRES = { } TURN_DESIRES = { - custom.TurnDirection.none: log.Desire.none, - custom.TurnDirection.turnLeft: log.Desire.turnLeft, - custom.TurnDirection.turnRight: log.Desire.turnRight, + TurnDirection.none: log.Desire.none, + TurnDirection.turnLeft: log.Desire.turnLeft, + TurnDirection.turnRight: log.Desire.turnRight, } @@ -49,7 +50,7 @@ class DesireHelper: self.desire = log.Desire.none self.alc = AutoLaneChangeController(self) self.lane_turn_controller = LaneTurnController(self) - self.lane_turn_direction = custom.TurnDirection.none + self.lane_turn_direction = TurnDirection.none @staticmethod def get_lane_change_direction(CS): @@ -126,7 +127,7 @@ class DesireHelper: self.prev_one_blinker = one_blinker - if self.lane_turn_direction != custom.TurnDirection.none: + if self.lane_turn_direction != TurnDirection.none: self.desire = TURN_DESIRES[self.lane_turn_direction] else: self.desire = DESIRES[self.lane_change_direction][self.lane_change_state] diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index ca9c3fde66..917fb233f4 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -48,6 +48,10 @@ class LatControlTorque(LatControl): self.lateral_accel_from_torque(-self.steer_max, self.torque_params)) def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited): + # Override torque params from extension + if self.extension.update_override_torque_params(self.torque_params): + self.update_limits() + pid_log = log.ControlsState.LateralTorqueState.new_message() if not active: output_torque = 0.0 diff --git a/selfdrive/locationd/torqued.py b/selfdrive/locationd/torqued.py index e0409957f5..57d53fdee3 100755 --- a/selfdrive/locationd/torqued.py +++ b/selfdrive/locationd/torqued.py @@ -11,6 +11,7 @@ from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator, PoseCalibrator, Pose from openpilot.sunnypilot.livedelay.helpers import get_lat_delay +from openpilot.sunnypilot.selfdrive.locationd.torqued_ext import TorqueEstimatorExt HISTORY = 5 # secs POINTS_PER_BUCKET = 1500 @@ -50,9 +51,10 @@ class TorqueBuckets(PointBuckets): break -class TorqueEstimator(ParameterEstimator): +class TorqueEstimator(ParameterEstimator, TorqueEstimatorExt): def __init__(self, CP, decimated=False, track_all_points=False): - super().__init__() + ParameterEstimator.__init__(self) + TorqueEstimatorExt.__init__(self, CP) self.CP = CP self.hist_len = int(HISTORY / DT_MDL) self.lag = 0.0 @@ -82,6 +84,8 @@ class TorqueEstimator(ParameterEstimator): self.calibrator = PoseCalibrator() + TorqueEstimatorExt.initialize_custom_params(self, decimated) + self.reset() initial_params = { @@ -260,6 +264,8 @@ def main(demo=False): t = sm.logMonoTime[which] * 1e-9 estimator.handle_log(t, which, sm[which]) + TorqueEstimatorExt.update_use_params(estimator) + # 4Hz driven by livePose if sm.frame % 5 == 0: pm.send('liveTorqueParameters', estimator.get_msg(valid=sm.all_checks())) diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py index 4bc75021f7..3bc616fb04 100755 --- a/selfdrive/selfdrived/selfdrived.py +++ b/selfdrive/selfdrived/selfdrived.py @@ -24,6 +24,7 @@ from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroa from openpilot.system.version import get_build_metadata from openpilot.sunnypilot.mads.mads import ModularAssistiveDrivingSystem +from openpilot.sunnypilot import get_sanitize_int_param from openpilot.sunnypilot.selfdrive.car.car_specific import CarSpecificEventsSP from openpilot.sunnypilot.selfdrive.car.cruise_helpers import CruiseHelper from openpilot.sunnypilot.selfdrive.car.intelligent_cruise_button_management.controller import IntelligentCruiseButtonManagement @@ -43,6 +44,7 @@ LaneChangeDirection = log.LaneChangeDirection EventName = log.OnroadEvent.EventName ButtonType = car.CarState.ButtonEvent.Type SafetyModel = car.CarParams.SafetyModel +TurnDirection = custom.ModelDataV2SP.TurnDirection IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput) @@ -130,7 +132,12 @@ class SelfdriveD(CruiseHelper): self.logged_comm_issue = None self.not_running_prev = None self.experimental_mode = False - self.personality = self.params.get("LongitudinalPersonality", return_default=True) + self.personality = get_sanitize_int_param( + "LongitudinalPersonality", + min(log.LongitudinalPersonality.schema.enumerants.values()), + max(log.LongitudinalPersonality.schema.enumerants.values()), + self.params + ) self.recalibrating_seen = False self.state_machine = StateMachine() self.rk = Ratekeeper(100, print_delay_threshold=None) @@ -299,9 +306,9 @@ class SelfdriveD(CruiseHelper): # Handle lane turn lane_turn_direction = self.sm['modelDataV2SP'].laneTurnDirection - if lane_turn_direction == custom.TurnDirection.turnLeft: + if lane_turn_direction == TurnDirection.turnLeft: self.events_sp.add(custom.OnroadEventSP.EventName.laneTurnLeft) - elif lane_turn_direction == custom.TurnDirection.turnRight: + elif lane_turn_direction == TurnDirection.turnRight: self.events_sp.add(custom.OnroadEventSP.EventName.laneTurnRight) for i, pandaState in enumerate(self.sm['pandaStates']): diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 205a14624a..6f594d939a 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -33,13 +33,6 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { "../assets/icons/experimental_white.svg", false, }, - { - "DynamicExperimentalControl", - tr("Enable Dynamic Experimental Control"), - tr("Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal."), - "../assets/offroad/icon_blank.png", - false, - }, { "DisengageOnAccelerator", tr("Disengage on Accelerator Pedal"), diff --git a/selfdrive/ui/qt/onroad/alerts.cc b/selfdrive/ui/qt/onroad/alerts.cc index 2e8f3612eb..d6829c6b08 100644 --- a/selfdrive/ui/qt/onroad/alerts.cc +++ b/selfdrive/ui/qt/onroad/alerts.cc @@ -4,9 +4,6 @@ #include #include "selfdrive/ui/qt/util.h" -#ifdef SUNNYPILOT -#include "selfdrive/ui/sunnypilot/ui.h" -#endif void OnroadAlerts::updateState(const UIState &s) { Alert a = getAlert(*(s.sm), s.scene.started_frame); @@ -76,12 +73,6 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) { } QRect r = QRect(0 + margin, height() - h + margin, width() - margin*2, h - margin*2); -#ifdef SUNNYPILOT - const int dev_ui_info = uiStateSP()->scene.dev_ui_info; - const int adjustment = dev_ui_info > 1 && alert.size != cereal::SelfdriveState::AlertSize::FULL ? 30 : 0; - r = QRect(0 + margin, height() - h + margin - adjustment, width() - margin*2, h - margin*2); -#endif - QPainter p(this); // draw background + gradient diff --git a/selfdrive/ui/qt/onroad/hud.cc b/selfdrive/ui/qt/onroad/hud.cc index d95fe5fd80..540643bed5 100644 --- a/selfdrive/ui/qt/onroad/hud.cc +++ b/selfdrive/ui/qt/onroad/hud.cc @@ -51,8 +51,8 @@ void HudRenderer::draw(QPainter &p, const QRect &surface_rect) { if (is_cruise_available) { drawSetSpeed(p, surface_rect); } -#endif drawCurrentSpeed(p, surface_rect); +#endif p.restore(); } diff --git a/selfdrive/ui/qt/onroad/model.cc b/selfdrive/ui/qt/onroad/model.cc index a1e3756cb6..176af56613 100644 --- a/selfdrive/ui/qt/onroad/model.cc +++ b/selfdrive/ui/qt/onroad/model.cc @@ -22,7 +22,7 @@ void ModelRenderer::draw(QPainter &painter, const QRect &surface_rect) { update_model(model, lead_one); drawLaneLines(painter); - drawPath(painter, model, surface_rect); + drawPath(painter, model, surface_rect.height()); if (longitudinal_control && sm.alive("radarState")) { update_leads(radar_state, model.getPosition()); @@ -34,7 +34,6 @@ void ModelRenderer::draw(QPainter &painter, const QRect &surface_rect) { drawLead(painter, lead_two, lead_vertices[1], surface_rect); } } - drawLeadStatus(painter, surface_rect.height(), surface_rect.width()); painter.restore(); } @@ -174,173 +173,6 @@ QColor ModelRenderer::blendColors(const QColor &start, const QColor &end, float (1 - t) * start.alphaF() + t * end.alphaF()); } - -void ModelRenderer::drawLeadStatus(QPainter &painter, int height, int width) { - auto *s = uiState(); - auto &sm = *(s->sm); - - if (!sm.alive("radarState")) return; - - const auto &radar_state = sm["radarState"].getRadarState(); - const auto &lead_one = radar_state.getLeadOne(); - const auto &lead_two = radar_state.getLeadTwo(); - - // Check if we have any active leads - bool has_lead_one = lead_one.getStatus(); - bool has_lead_two = lead_two.getStatus(); - - if (!has_lead_one && !has_lead_two) { - // Fade out status display - lead_status_alpha = std::max(0.0f, lead_status_alpha - 0.05f); - if (lead_status_alpha <= 0.0f) return; - } else { - // Fade in status display - lead_status_alpha = std::min(1.0f, lead_status_alpha + 0.1f); - } - - // Draw status for each lead vehicle under its chevron - if (true) { - drawLeadStatusAtPosition(painter, lead_one, lead_vertices[0], height, width, "L1"); - } - - if (has_lead_two && std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0) { - drawLeadStatusAtPosition(painter, lead_two, lead_vertices[1], height, width, "L2"); - } -} - -void ModelRenderer::drawLeadStatusAtPosition(QPainter &painter, - const cereal::RadarState::LeadData::Reader &lead_data, - const QPointF &chevron_pos, - int height, int width, - const QString &label) { - - float d_rel = lead_data.getDRel(); - float v_rel = lead_data.getVRel(); - auto *s = uiState(); - auto &sm = *(s->sm); - float v_ego = sm["carState"].getCarState().getVEgo(); - - int chevron_data = std::atoi(Params().get("ChevronInfo").c_str()); - - // Calculate chevron size (same logic as drawLead) - float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * 2.35; - - QFont content_font = painter.font(); - content_font.setPixelSize(35); - content_font.setBold(true); - painter.setFont(content_font); - - QFontMetrics fm(content_font); - bool is_metric = s->scene.is_metric; - - QStringList text_lines; - - const int chevron_types = 3; - const int chevron_all = chevron_types + 1; // All metrics (value 4) - QStringList chevron_text[chevron_types]; - int position; - float val; - - // Distance display (chevron_data == 1 or all) - if (chevron_data == 1 || chevron_data == chevron_all) { - position = 0; - val = std::max(0.0f, d_rel); - QString distance_unit = is_metric ? "m" : "ft"; - if (!is_metric) { - val *= 3.28084f; // Convert meters to feet - } - chevron_text[position].append(QString::number(val, 'f', 0) + " " + distance_unit); - } - - // Absolute velocity display (chevron_data == 2 or all) - if (chevron_data == 2 || chevron_data == chevron_all) { - position = (chevron_data == 2) ? 0 : 1; - val = std::max(0.0f, (v_rel + v_ego) * (is_metric ? static_cast(MS_TO_KPH) : static_cast(MS_TO_MPH))); - chevron_text[position].append(QString::number(val, 'f', 0) + " " + (is_metric ? "km/h" : "mph")); - } - - // Time-to-contact display (chevron_data == 3 or all) - if (chevron_data == 3 || chevron_data == chevron_all) { - position = (chevron_data == 3) ? 0 : 2; - val = (d_rel > 0 && v_ego > 0) ? std::max(0.0f, d_rel / v_ego) : 0.0f; - QString ttc_str = (val > 0 && val < 200) ? QString::number(val, 'f', 1) + "s" : "---"; - chevron_text[position].append(ttc_str); - } - - // Collect all non-empty text lines - for (int i = 0; i < chevron_types; ++i) { - if (!chevron_text[i].isEmpty()) { - text_lines.append(chevron_text[i]); - } - } - - // If no text to display, return early - if (text_lines.isEmpty()) { - return; - } - - // Text box dimensions - float str_w = 150; // Width of text area - float str_h = 45; // Height per line - - // Position text below chevron, centered horizontally - float text_x = chevron_pos.x() - str_w / 2; - float text_y = chevron_pos.y() + sz + 15; - - // Clamp to screen bounds - text_x = std::clamp(text_x, 10.0f, (float)width - str_w - 10); - - // Shadow offset - QPoint shadow_offset(2, 2); - - // Draw each line of text with shadow - for (int i = 0; i < text_lines.size(); ++i) { - if (!text_lines[i].isEmpty()) { - QRect textRect(text_x, text_y + (i * str_h), str_w, str_h); - - // Draw shadow - painter.setPen(QColor(0x0, 0x0, 0x0, (int)(200 * lead_status_alpha))); - painter.drawText(textRect.translated(shadow_offset.x(), shadow_offset.y()), - Qt::AlignBottom | Qt::AlignHCenter, text_lines[i]); - - // Determine text color based on content and danger level - QColor text_color; - - // Check if this is a distance line (contains 'm' or 'ft') - if (text_lines[i].contains("m") || text_lines[i].contains("ft")) { - if (d_rel < 20.0f) { - text_color = QColor(255, 80, 80, (int)(255 * lead_status_alpha)); // Red - danger - } else if (d_rel < 40.0f) { - text_color = QColor(255, 200, 80, (int)(255 * lead_status_alpha)); // Yellow - caution - } else { - text_color = QColor(80, 255, 120, (int)(255 * lead_status_alpha)); // Green - safe - } - } - // Enhanced color coding for time-to-contact - else if (text_lines[i].contains("s") && !text_lines[i].contains("---")) { - float ttc_val = text_lines[i].left(text_lines[i].length() - 1).toFloat(); - if (ttc_val < 3.0f) { - text_color = QColor(255, 80, 80, (int)(255 * lead_status_alpha)); // Red - urgent - } else if (ttc_val < 6.0f) { - text_color = QColor(255, 200, 80, (int)(255 * lead_status_alpha)); // Yellow - caution - } else { - text_color = QColor(0xff, 0xff, 0xff, (int)(255 * lead_status_alpha)); // White - safe - } - } - else { - text_color = QColor(0xff, 0xff, 0xff, (int)(255 * lead_status_alpha)); // White for other lines - } - - // Draw main text - painter.setPen(text_color); - painter.drawText(textRect, Qt::AlignBottom | Qt::AlignHCenter, text_lines[i]); - } - } - - // Reset pen - painter.setPen(Qt::NoPen); -} - void ModelRenderer::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, const QRect &surface_rect) { const float speedBuff = 10.; diff --git a/selfdrive/ui/qt/onroad/model.h b/selfdrive/ui/qt/onroad/model.h index e40f832c37..0a58d345c4 100644 --- a/selfdrive/ui/qt/onroad/model.h +++ b/selfdrive/ui/qt/onroad/model.h @@ -34,20 +34,11 @@ protected: bool mapToScreen(float in_x, float in_y, float in_z, QPointF *out); void mapLineToPolygon(const cereal::XYZTData::Reader &line, float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert = true); - void drawLeadStatus(QPainter &painter, int height, int width); - void drawLeadStatusAtPosition(QPainter &painter, - const cereal::RadarState::LeadData::Reader &lead_data, - const QPointF &chevron_pos, - int height, int width, - const QString &label); void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd, const QRect &surface_rect); void update_leads(const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line); virtual void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead); void drawLaneLines(QPainter &painter); void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, int height); - virtual void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, const QRect &surface_rect) {; - drawPath(painter, model, surface_rect.height()); - } void updatePathGradient(QLinearGradient &bg); QColor blendColors(const QColor &start, const QColor &end, float t); @@ -64,9 +55,4 @@ protected: QPointF lead_vertices[2] = {}; Eigen::Matrix3f car_space_transform = Eigen::Matrix3f::Zero(); QRectF clip_region; - - float lead_status_alpha = 0.0f; - QPointF lead_status_pos; - QString lead_status_text; - QColor lead_status_color; }; diff --git a/selfdrive/ui/qt/onroad/onroad_home.h b/selfdrive/ui/qt/onroad/onroad_home.h index 9b51bb62e4..ad0603c095 100644 --- a/selfdrive/ui/qt/onroad/onroad_home.h +++ b/selfdrive/ui/qt/onroad/onroad_home.h @@ -4,8 +4,10 @@ #ifdef SUNNYPILOT #include "selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h" +#include "selfdrive/ui/sunnypilot/qt/onroad/alerts.h" #define UIState UIStateSP #define AnnotatedCameraWidget AnnotatedCameraWidgetSP +#define OnroadAlerts OnroadAlertsSP #else #include "selfdrive/ui/qt/onroad/annotated_camera.h" #endif diff --git a/selfdrive/ui/qt/window.cc b/selfdrive/ui/qt/window.cc index 36f12c266b..d0806e4379 100644 --- a/selfdrive/ui/qt/window.cc +++ b/selfdrive/ui/qt/window.cc @@ -92,6 +92,16 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *event) { // ignore events when device is awakened by resetInteractiveTimeout ignore = !device()->isAwake(); device()->resetInteractiveTimeout(); + +#ifdef SUNNYPILOT + auto *s_sp = uiStateSP(); + bool onroadScreenControl = s_sp->scene.onroadScreenOffControl; + bool started = s_sp->scene.started; + bool timerExpired = (s_sp->scene.onroadScreenOffTimer == 0); + ignore |= (onroadScreenControl and started and timerExpired); + s_sp->reset_onroad_sleep_timer(); +#endif + break; } default: diff --git a/selfdrive/ui/qt/window.h b/selfdrive/ui/qt/window.h index 8a118b0bb6..63293d4177 100644 --- a/selfdrive/ui/qt/window.h +++ b/selfdrive/ui/qt/window.h @@ -7,6 +7,10 @@ #include "selfdrive/ui/qt/offroad/onboarding.h" #include "selfdrive/ui/qt/offroad/settings.h" +#ifdef SUNNYPILOT +#include "selfdrive/ui/sunnypilot/ui.h" +#endif + class MainWindow : public QWidget { Q_OBJECT diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index a94456efe0..01c7c68949 100644 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -4,7 +4,7 @@ import time import wave -from cereal import car, messaging +from cereal import car, messaging, custom from openpilot.common.basedir import BASEDIR from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.realtime import Ratekeeper @@ -26,8 +26,15 @@ AMBIENT_DB = 30 # DB where MIN_VOLUME is applied DB_SCALE = 30 # AMBIENT_DB + DB_SCALE is where MAX_VOLUME is applied AudibleAlert = car.CarControl.HUDControl.AudibleAlert +AudibleAlertSP = custom.SelfdriveStateSP.AudibleAlert +sound_list_sp: dict[int, tuple[str, int | None, float]] = { + # AudibleAlertSP, file name, play count (none for infinite) + AudibleAlertSP.promptSingleLow: ("prompt_single_low.wav", 1, MAX_VOLUME), + AudibleAlertSP.promptSingleHigh: ("prompt_single_high.wav", 1, MAX_VOLUME), +} + sound_list: dict[int, tuple[str, int | None, float]] = { # AudibleAlert, file name, play count (none for infinite) AudibleAlert.engage: ("engage.wav", 1, MAX_VOLUME), @@ -40,6 +47,8 @@ sound_list: dict[int, tuple[str, int | None, float]] = { AudibleAlert.warningSoft: ("warning_soft.wav", None, MAX_VOLUME), AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME), + + **sound_list_sp, } def check_selfdrive_timeout_alert(sm): diff --git a/selfdrive/ui/sunnypilot/SConscript b/selfdrive/ui/sunnypilot/SConscript index 3f0e013d34..be92c14261 100644 --- a/selfdrive/ui/sunnypilot/SConscript +++ b/selfdrive/ui/sunnypilot/SConscript @@ -38,6 +38,7 @@ qt_src = [ "sunnypilot/qt/offroad/settings/trips_panel.cc", "sunnypilot/qt/offroad/settings/vehicle_panel.cc", "sunnypilot/qt/offroad/settings/visuals_panel.cc", + "sunnypilot/qt/onroad/alerts.cc", "sunnypilot/qt/onroad/annotated_camera.cc", "sunnypilot/qt/onroad/buttons.cc", "sunnypilot/qt/onroad/developer_ui/developer_ui.cc", @@ -51,6 +52,8 @@ lateral_panel_qt_src = [ "sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc", "sunnypilot/qt/offroad/settings/lateral/mads_settings.cc", "sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc", + "sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc", + "sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc", ] longitudinal_panel_qt_src = [ diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc index ffd3ce1d8b..e9bd13485a 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc @@ -25,8 +25,8 @@ const QMap Brightness::brightness_options = { Brightness::Brightness() : OptionControlSP( "Brightness", - tr("Brightness"), - tr("Overrides the brightness of the device."), + tr("Global Brightness"), + tr("Overrides the brightness of the device. This applies to both onroad and offroad screens. "), "../assets/offroad/icon_blank.png", {0, 11}, 1, true, &brightness_options) { diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.cc index 9c36097f1b..021f5b3776 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.cc @@ -56,14 +56,13 @@ DeveloperPanelSP::DeveloperPanelSP(SettingsWindow *parent) : DeveloperPanel(pare addItem(errorLogBtn); QObject::connect(uiState(), &UIState::offroadTransition, this, &DeveloperPanelSP::updateToggles); - - is_release = params.getBool("IsReleaseBranch"); - is_tested = params.getBool("IsTestedBranch"); - is_development = params.getBool("IsDevelopmentBranch"); } void DeveloperPanelSP::updateToggles(bool offroad) { bool disable_updates = params.getBool("DisableUpdates"); + bool is_release = params.getBool("IsReleaseBranch"); + bool is_tested = params.getBool("IsTestedBranch"); + bool is_development = params.getBool("IsDevelopmentBranch"); prebuiltToggle->setVisible(!is_release && !is_tested && !is_development); prebuiltToggle->setEnabled(disable_updates); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h index 7f67512b5d..ed64964a56 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/developer_panel.h @@ -22,9 +22,6 @@ private: ParamControlSP *prebuiltToggle; Params params; ParamControlSP *showAdvancedControls; - bool is_development; - bool is_release; - bool is_tested; private slots: void updateToggles(bool offroad); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc index 7e3d18bd81..8295789f0a 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc @@ -23,6 +23,7 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) { {"regulatoryBtn", tr("Regulatory"), ""}, {"translateBtn", tr("Language"), ""}, {"resetParams", tr("Reset Settings"), ""}, + {"onroadUploadsBtn", tr("Onroad Uploads"), "OnroadUploads"} }; int row = 0, col = 0; @@ -75,35 +76,21 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) { connect(buttons["resetParams"], &PushButtonSP::clicked, this, &DevicePanelSP::resetSettings); + connect(buttons["onroadUploadsBtn"], &PushButtonSP::clicked, buttons["onroadUploadsBtn"], &PushButtonSP::updateButton); + // Max Time Offroad maxTimeOffroad = new MaxTimeOffroad(); connect(maxTimeOffroad, &OptionControlSP::updateLabels, maxTimeOffroad, &MaxTimeOffroad::refresh); addItem(maxTimeOffroad); - toggleDeviceBootMode = new ButtonParamControlSP("DeviceBootMode", tr("Wake-Up Behavior"), "", "", {"Default", "Offroad"}, 375, true); + toggleDeviceBootMode = new ButtonParamControlSP("DeviceBootMode", tr("Wake-Up Behavior"), "", "", {"Default", "Offroad"}, 375, true); addItem(toggleDeviceBootMode); connect(toggleDeviceBootMode, &ButtonParamControlSP::buttonClicked, this, [=](int index) { params.put("DeviceBootMode", QString::number(index).toStdString()); - updateState(); + updateState(offroad); }); - interactivityTimeout = new OptionControlSP("InteractivityTimeout", tr("Interactivity Timeout"), - tr("Apply a custom timeout for settings UI." - "\nThis is the time after which settings UI closes automatically if user is not interacting with the screen."), - "", {0, 120}, 10, true, nullptr, false); - - connect(interactivityTimeout, &OptionControlSP::updateLabels, [=]() { - updateState(); - }); - - addItem(interactivityTimeout); - - // Brightness - brightness = new Brightness(); - connect(brightness, &OptionControlSP::updateLabels, brightness, &Brightness::refresh); - addItem(brightness); - addItem(device_grid_layout); // offroad mode and power buttons @@ -129,29 +116,21 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) { offroadBtn->setFixedWidth(power_layout->sizeHint().width()); QObject::connect(offroadBtn, &PushButtonSP::clicked, this, &DevicePanelSP::setOffroadMode); - QVBoxLayout *power_group_layout = new QVBoxLayout(); + power_group_layout = new QVBoxLayout(); power_group_layout->setSpacing(25); - power_group_layout->addWidget(offroadBtn, 0, Qt::AlignHCenter); power_group_layout->addLayout(power_layout); addItem(power_group_layout); - std::vector always_enabled_btns = { + always_enabled_btns = { rebootBtn, poweroffBtn, offroadBtn, buttons["quietModeBtn"], + buttons["onroadUploadsBtn"], }; - QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { - for (auto btn : findChildren()) { - bool always_enabled = std::find(always_enabled_btns.begin(), always_enabled_btns.end(), btn) != always_enabled_btns.end(); - - if (!always_enabled) { - btn->setEnabled(offroad); - } - } - }); + QObject::connect(uiState(), &UIState::offroadTransition, this, &DevicePanelSP::updateState); } void DevicePanelSP::setOffroadMode() { @@ -175,7 +154,7 @@ void DevicePanelSP::setOffroadMode() { ConfirmationDialog::alert(tr("Disengage to Enter Always Offroad Mode"), this); } - updateState(); + updateState(offroad); } void DevicePanelSP::resetSettings() { @@ -192,16 +171,20 @@ void DevicePanelSP::resetSettings() { } void DevicePanelSP::showEvent(QShowEvent *event) { - updateState(); + updateState(offroad); } -void DevicePanelSP::updateState() { - if (!isVisible()) { - return; +void DevicePanelSP::updateState(bool _offroad) { + for (auto btn : findChildren()) { + bool always_enabled = std::find(always_enabled_btns.begin(), always_enabled_btns.end(), btn) != always_enabled_btns.end(); + + if (!always_enabled) { + btn->setEnabled(_offroad); + } } bool offroad_mode_param = params.getBool("OffroadMode"); - offroadBtn->setText(offroad_mode_param ? tr("Exit Always Offroad") : tr("Always Offroad")); + offroadBtn->setText(offroad_mode_param ? tr("Exit Always Offroad") : tr("Enable Always Offroad")); offroadBtn->setStyleSheet(offroad_mode_param ? alwaysOffroadStyle : autoOffroadStyle); DeviceSleepModeStatus currStatus = DeviceSleepModeStatus::DEFAULT; @@ -210,10 +193,11 @@ void DevicePanelSP::updateState() { } toggleDeviceBootMode->setDescription(deviceSleepModeDescription(currStatus)); - QString timeoutValue = QString::fromStdString(params.get("InteractivityTimeout")); - if (timeoutValue == "0" || timeoutValue.isEmpty()) { - interactivityTimeout->setLabel("Default"); + if (offroad and not offroad_mode_param) { + power_group_layout->insertWidget(0, offroadBtn, 0, Qt::AlignHCenter); } else { - interactivityTimeout->setLabel(timeoutValue + "s"); + AddWidgetAt(0, offroadBtn); } + + offroad = _offroad; } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h index 899a942dae..425c4528a1 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h @@ -8,7 +8,6 @@ #pragma once #include "selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.h" -#include "selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" #include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" @@ -24,7 +23,7 @@ public: explicit DevicePanelSP(SettingsWindowSP *parent = 0); void showEvent(QShowEvent *event) override; void setOffroadMode(); - void updateState(); + void updateState(bool _offroad); void resetSettings(); private: @@ -32,8 +31,10 @@ private: PushButtonSP *offroadBtn; MaxTimeOffroad *maxTimeOffroad; ButtonParamControlSP *toggleDeviceBootMode; - Brightness *brightness; - OptionControlSP *interactivityTimeout; + QVBoxLayout *power_group_layout; + bool offroad; + + std::vector always_enabled_btns = {}; const QString alwaysOffroadStyle = R"( PushButtonSP { diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.cc index 3e9dc427bf..e29d06cb82 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.cc @@ -12,30 +12,29 @@ OnroadScreenBrightnessControl::OnroadScreenBrightnessControl(const QString ¶ QWidget *parent) : ExpandableToggleRow(param, title, description, icon, parent) { auto *mainFrame = new QFrame(this); - auto *mainFrameLayout = new QGridLayout(); + auto *mainFrameLayout = new QVBoxLayout(); mainFrame->setLayout(mainFrameLayout); - mainFrameLayout->setSpacing(0); + mainFrameLayout->setSpacing(30); + mainFrameLayout->setContentsMargins(0, 0, 0, 0); onroadScreenOffTimer = new OptionControlSP( "OnroadScreenOffTimer", - "", + "Onroad Brightness Delay", "", "", {0, 11}, 1, true, &onroadScreenOffTimerOptions); onroadScreenBrightness = new OptionControlSP( "OnroadScreenOffBrightness", + "Onroad Brightness", "", "", - "", - {0, 100}, 10, true, nullptr, false); + {0, 90}, 10, true); connect(onroadScreenOffTimer, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh); connect(onroadScreenBrightness, &OptionControlSP::updateLabels, this, &OnroadScreenBrightnessControl::refresh); - onroadScreenOffTimer->setFixedWidth(280); - onroadScreenBrightness->setFixedWidth(280); - mainFrameLayout->addWidget(onroadScreenOffTimer, 0, 0, Qt::AlignLeft); - mainFrameLayout->addWidget(onroadScreenBrightness, 0, 1, Qt::AlignRight); + mainFrameLayout->addWidget(onroadScreenBrightness); + mainFrameLayout->addWidget(onroadScreenOffTimer); addItem(mainFrame); @@ -45,19 +44,11 @@ OnroadScreenBrightnessControl::OnroadScreenBrightnessControl(const QString ¶ void OnroadScreenBrightnessControl::refresh() { // Driving Screen Off Timer int valTimer = std::atoi(params.get("OnroadScreenOffTimer").c_str()); - std::string labelTimer = ""; - labelTimer += "Delay"; - labelTimer += "
"; - labelTimer += (valTimer < 60 ? std::to_string(valTimer) + "s" : std::to_string(valTimer / 60) + "m"); - labelTimer += "
"; + std::string labelTimer = (valTimer < 60 ? std::to_string(valTimer) + "s" : std::to_string(valTimer / 60) + "m"); onroadScreenOffTimer->setLabel(QString::fromStdString(labelTimer)); // Driving Screen Off Brightness std::string valBrightness = params.get("OnroadScreenOffBrightness"); - std::string labelBrightness = ""; - labelBrightness += "Brightness"; - labelBrightness += "
"; - labelBrightness += (valBrightness == "0" ? " Screen Off" : valBrightness + "%"); - labelBrightness += "
"; + std::string labelBrightness = (valBrightness == "0" ? " Screen Off" : valBrightness + "%"); onroadScreenBrightness->setLabel(QString::fromStdString(labelBrightness)); } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.cc index b441021ff3..465047f178 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.cc @@ -18,12 +18,30 @@ DisplayPanel::DisplayPanel(QWidget *parent) : QWidget(parent) { // Onroad Screen Off/Brightness onroadScreenBrightnessControl = new OnroadScreenBrightnessControl( "OnroadScreenOffControl", - tr("Driving Screen Off: Non-Critical Events"), + tr("Onroad Screen: Reduced Brightness"), tr("Turn off device screen or reduce brightness after driving starts. " - "It automatically brightens again when screen is touched or a critical event occurs."), + "It automatically brightens again when screen is touched or a visible alert is displayed."), "", this); list->addItem(onroadScreenBrightnessControl); + list->addItem(horizontal_line()); + + // Global Brightness + brightness = new Brightness(); + connect(brightness, &OptionControlSP::updateLabels, brightness, &Brightness::refresh); + list->addItem(brightness); + list->addItem(horizontal_line()); + + // Interactivity Timeout + interactivityTimeout = new OptionControlSP("InteractivityTimeout", tr("Interactivity Timeout"), + tr("Apply a custom timeout for settings UI." + "\nThis is the time after which settings UI closes automatically if user is not interacting with the screen."), + "", {0, 120}, 10, true, nullptr, false); + + connect(interactivityTimeout, &OptionControlSP::updateLabels, [=]() { + refresh(); + }); + list->addItem(interactivityTimeout); sunnypilotScroller = new ScrollViewSP(list, this); vlayout->addWidget(sunnypilotScroller); @@ -37,4 +55,11 @@ void DisplayPanel::showEvent(QShowEvent *event) { void DisplayPanel::refresh() { onroadScreenBrightnessControl->refresh(); + + QString timeoutValue = QString::fromStdString(params.get("InteractivityTimeout")); + if (timeoutValue == "0" || timeoutValue.isEmpty()) { + interactivityTimeout->setLabel("Default"); + } else { + interactivityTimeout->setLabel(timeoutValue + "s"); + } } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h index 1714c8a436..69b440c9d3 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h @@ -7,6 +7,7 @@ #pragma once +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/display/onroad_screen_brightness.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" #include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" @@ -25,4 +26,6 @@ private: ScrollViewSP *sunnypilotScroller = nullptr; Params params; OnroadScreenBrightnessControl *onroadScreenBrightnessControl = nullptr; + Brightness *brightness; + OptionControlSP *interactivityTimeout; }; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc index 0b66b83660..02ab810c57 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc @@ -10,14 +10,15 @@ NeuralNetworkLateralControl::NeuralNetworkLateralControl() : ParamControl("NeuralNetworkLateralControl", tr("Neural Network Lateral Control (NNLC)"), "", "") { setConfirmation(true, false); - updateToggle(); + updateToggle(offroad); } -void NeuralNetworkLateralControl::updateToggle() { +void NeuralNetworkLateralControl::updateToggle(bool _offroad) { QString statusInitText = "" + STATUS_CHECK_COMPATIBILITY + ""; QString notLoadedText = "" + STATUS_NOT_LOADED + ""; QString loadedText = "" + STATUS_LOADED + ""; + bool allowed = true; auto cp_bytes = params.get("CarParamsPersistent"); auto cp_sp_bytes = params.get("CarParamsSPPersistent"); if (!cp_bytes.empty() && !cp_sp_bytes.empty()) { @@ -31,7 +32,7 @@ void NeuralNetworkLateralControl::updateToggle() { if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) { params.remove("NeuralNetworkLateralControl"); setDescription(nnffDescriptionBuilder(STATUS_NOT_AVAILABLE)); - setEnabled(false); + allowed = false; } else { QString nn_model_name = QString::fromStdString(CP_SP.getNeuralNetworkLateralControl().getModel().getName()); QString nn_fuzzy = CP_SP.getNeuralNetworkLateralControl().getFuzzyFingerprint() ? @@ -56,4 +57,11 @@ void NeuralNetworkLateralControl::updateToggle() { if (getDescription() != getBaseDescription()) { showDescription(); } + + bool enforce_torque_toggle = params.getBool("EnforceTorqueControl"); + setEnabled(_offroad && allowed && !enforce_torque_toggle); + + refresh(); + + offroad = _offroad; } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h index df80fbf097..9e872b11e9 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h @@ -20,10 +20,11 @@ public: NeuralNetworkLateralControl(); public slots: - void updateToggle(); + void updateToggle(bool _offroad); private: Params params; + bool offroad; // Status messages const QString STATUS_NOT_AVAILABLE = tr("NNLC is currently not available on this platform."); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc new file mode 100644 index 0000000000..894fbc2ec4 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + * + * This file is part of sunnypilot and is licensed under the MIT License. + * See the LICENSE.md file in the root directory for more details. + */ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h" + +TorqueLateralControlCustomParams::TorqueLateralControlCustomParams(const QString ¶m, const QString &title, const QString &description, const QString &icon, QWidget *parent) + : ExpandableToggleRow(param, title, description, icon, parent) { + + QFrame *frame = new QFrame(this); + QGridLayout *frame_layout = new QGridLayout(); + frame->setLayout(frame_layout); + frame_layout->setSpacing(0); + + torqueLateralControlParamsOverride = new ParamControl( + "TorqueParamsOverrideEnabled", + tr("Manual Real-Time Tuning"), + tr("Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values."), + "../assets/offroad/icon_blank.png", + this + ); + connect(torqueLateralControlParamsOverride, &ParamControl::toggleFlipped, this, &TorqueLateralControlCustomParams::refresh); + + torqueParamsOverrideLatAccelFactor = new OptionControlSP("TorqueParamsOverrideLatAccelFactor", tr("Lateral Acceleration Factor"), "", "", {1, 500}, 1, false, nullptr, true, false); + connect(torqueParamsOverrideLatAccelFactor, &OptionControlSP::updateLabels, this, &TorqueLateralControlCustomParams::refresh); + torqueParamsOverrideLatAccelFactor->setFixedWidth(280); + + torqueParamsOverrideFriction = new OptionControlSP("TorqueParamsOverrideFriction", tr("Friction"), "", "", {1, 100}, 1, false, nullptr, true, false); + connect(torqueParamsOverrideFriction, &OptionControlSP::updateLabels, this, &TorqueLateralControlCustomParams::refresh); + torqueParamsOverrideFriction->setFixedWidth(280); + + frame_layout->addWidget(torqueLateralControlParamsOverride, 0, 0, 1, 2); + QSpacerItem *spacer = new QSpacerItem(20, 40); + frame_layout->addItem(spacer, 1, 0, 1, 2); + frame_layout->addWidget(torqueParamsOverrideLatAccelFactor, 2, 0, Qt::AlignCenter); + frame_layout->addWidget(torqueParamsOverrideFriction, 2, 1, Qt::AlignCenter); + + addItem(frame); + + refresh(); +} + +void TorqueLateralControlCustomParams::refresh() { + bool torque_override_param = params.getBool("TorqueParamsOverrideEnabled"); + float laf_param = QString::fromStdString(params.get("TorqueParamsOverrideLatAccelFactor")).toFloat(); + const QString laf_unit = "m/s²"; + + float friction_param = QString::fromStdString(params.get("TorqueParamsOverrideFriction")).toFloat(); + + torqueParamsOverrideLatAccelFactor->setTitle(tr("Lateral Acceleration Factor") + "\n(" + (torque_override_param ? tr("Real-time and Offline") : tr("Offline Only")) + ")"); + torqueParamsOverrideFriction->setTitle(tr("Friction") + "\n(" + (torque_override_param ? tr("Real-time and Offline") : tr("Offline Only")) + ")"); + + torqueParamsOverrideLatAccelFactor->setLabel(QString::number(laf_param, 'f', 2) + " " + laf_unit); + torqueParamsOverrideFriction->setLabel(QString::number(friction_param, 'f', 2)); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h new file mode 100644 index 0000000000..8442bd0d48 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + * + * This file is part of sunnypilot and is licensed under the MIT License. + * See the LICENSE.md file in the root directory for more details. + */ + +#pragma once + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h" + +class TorqueLateralControlCustomParams : public ExpandableToggleRow { + Q_OBJECT + +public: + TorqueLateralControlCustomParams(const QString ¶m, const QString &title, const QString &description, const QString &icon, QWidget *parent = nullptr); + void refresh(); + +private: + Params params; + ParamControl *torqueLateralControlParamsOverride; + OptionControlSP *torqueParamsOverrideFriction; + OptionControlSP *torqueParamsOverrideLatAccelFactor; +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc new file mode 100644 index 0000000000..914ce7a939 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + * + * This file is part of sunnypilot and is licensed under the MIT License. + * See the LICENSE.md file in the root directory for more details. + */ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h" + +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" + +TorqueLateralControlSettings::TorqueLateralControlSettings(QWidget *parent) : QWidget(parent) { + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(50, 20, 50, 20); + main_layout->setSpacing(20); + + // Back button + PanelBackButton *back = new PanelBackButton(); + connect(back, &QPushButton::clicked, [=]() { emit backPress(); }); + main_layout->addWidget(back, 0, Qt::AlignLeft); + + ListWidget *list = new ListWidget(this, false); + // param, title, desc, icon + std::vector> toggle_defs{ + { + "LiveTorqueParamsToggle", + tr("Self-Tune"), + tr("Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default."), + "../assets/offroad/icon_blank.png", + }, + { + "LiveTorqueParamsRelaxedToggle", + tr("Less Restrict Settings for Self-Tune (Beta)"), + tr("Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values."), + "../assets/offroad/icon_blank.png", + } + }; + + for (auto &[param, title, desc, icon] : toggle_defs) { + auto toggle = new ParamControlSP(param, title, desc, icon, this); + list->addItem(toggle); + toggles[param.toStdString()] = toggle; + } + + torqueLateralControlCustomParams = new TorqueLateralControlCustomParams( + "CustomTorqueParams", + tr("Enable Custom Tuning"), + tr("Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within \"opendbc/car/torque_data\". " + "The values will also be used live when \"Manual Real-Time Tuning\" toggle is enabled."), + "../assets/offroad/icon_blank.png", + this); + list->addItem(torqueLateralControlCustomParams); + + QObject::connect(uiState(), &UIState::offroadTransition, this, &TorqueLateralControlSettings::updateToggles); + QObject::connect(toggles["LiveTorqueParamsToggle"], &ParamControlSP::toggleFlipped, [=](bool state) { + if (!state) { + params.remove("LiveTorqueParamsRelaxedToggle"); + toggles["LiveTorqueParamsRelaxedToggle"]->refresh(); + } + + updateToggles(offroad); + }); + + main_layout->addWidget(new ScrollViewSP(list, this)); +} + +void TorqueLateralControlSettings::showEvent(QShowEvent *event) { + updateToggles(offroad); +} + +void TorqueLateralControlSettings::updateToggles(bool _offroad) { + bool live_toggle = toggles["LiveTorqueParamsToggle"]->isToggled(); + + toggles["LiveTorqueParamsToggle"]->setEnabled(_offroad); + toggles["LiveTorqueParamsRelaxedToggle"]->setEnabled(_offroad && live_toggle); + + torqueLateralControlCustomParams->setEnabled(_offroad); + torqueLateralControlCustomParams->refresh(); + + offroad = _offroad; +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h new file mode 100644 index 0000000000..6254073dfe --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + * + * This file is part of sunnypilot and is licensed under the MIT License. + * See the LICENSE.md file in the root directory for more details. + */ + +#pragma once + +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" + +class TorqueLateralControlSettings : public QWidget { + Q_OBJECT + +public: + explicit TorqueLateralControlSettings(QWidget *parent = nullptr); + + void showEvent(QShowEvent *event) override; + + signals: + void backPress(); + +public slots: + void updateToggles(bool _offroad); + +private: + Params params; + bool offroad; + std::map toggles; + + TorqueLateralControlCustomParams *torqueLateralControlCustomParams; +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.cc index 59636ca5a5..ac004e8856 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.cc @@ -75,6 +75,36 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) { list->addItem(horizontal_line()); + // Customized Torque Lateral Control + torqueLateralControlToggle = new ParamControl( + "EnforceTorqueControl", + tr("Enforce Torque Lateral Control"), + tr("Enable this to enforce sunnypilot to steer with Torque lateral control."), + ""); + list->addItem(torqueLateralControlToggle); + + torqueLateralControlSettingsButton = new PushButtonSP(tr("Customize Params")); + torqueLateralControlSettingsButton->setObjectName("torque_btn"); + connect(torqueLateralControlSettingsButton, &QPushButton::clicked, [=]() { + sunnypilotScroller->setLastScrollPosition(); + main_layout->setCurrentWidget(torqueLateralControlWidget); + }); + QObject::connect(torqueLateralControlToggle, &ToggleControl::toggleFlipped, [=](bool state) { + torqueLateralControlSettingsButton->setEnabled(state); + nnlcToggle->updateToggle(offroad); + updateToggles(offroad); + }); + + torqueLateralControlWidget = new TorqueLateralControlSettings(this); + connect(torqueLateralControlWidget, &TorqueLateralControlSettings::backPress, [=]() { + sunnypilotScroller->restoreScrollPosition(); + main_layout->setCurrentWidget(sunnypilotScreen); + }); + list->addItem(torqueLateralControlSettingsButton); + + list->addItem(vertical_space(0)); + list->addItem(horizontal_line()); + // Neural Network Lateral Control nnlcToggle = new NeuralNetworkLateralControl(); list->addItem(nnlcToggle); @@ -86,12 +116,10 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) { nnlcToggle->hideDescription(); } - nnlcToggle->updateToggle(); + nnlcToggle->updateToggle(offroad); + updateToggles(offroad); }); - toggleOffroadOnly = { - madsToggle, nnlcToggle, - }; QObject::connect(uiState(), &UIState::offroadTransition, this, &LateralPanel::updateToggles); sunnypilotScroller = new ScrollViewSP(list, this); @@ -100,6 +128,7 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) { main_layout->addWidget(sunnypilotScreen); main_layout->addWidget(madsWidget); main_layout->addWidget(laneChangeWidget); + main_layout->addWidget(torqueLateralControlWidget); setStyleSheet(R"( #back_btn { @@ -120,7 +149,7 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) { } void LateralPanel::showEvent(QShowEvent *event) { - nnlcToggle->updateToggle(); + nnlcToggle->updateToggle(offroad); updateToggles(offroad); } @@ -129,10 +158,7 @@ void LateralPanel::hideEvent(QHideEvent *event) { } void LateralPanel::updateToggles(bool _offroad) { - for (auto *toggle : toggleOffroadOnly) { - toggle->setEnabled(_offroad); - } - + bool torque_allowed = true; auto cp_bytes = params.get("CarParamsPersistent"); auto cp_sp_bytes = params.get("CarParamsSPPersistent"); if (!cp_bytes.empty() && !cp_sp_bytes.empty()) { @@ -148,12 +174,24 @@ void LateralPanel::updateToggles(bool _offroad) { } else { madsToggle->setDescription(descriptionBuilder(STATUS_MADS_SETTINGS_FULL_COMPATIBILITY, MADS_BASE_DESC)); } + + if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) { + params.remove("EnforceTorqueControl"); + torque_allowed = false; + } } else { madsToggle->setDescription(descriptionBuilder(STATUS_MADS_CHECK_COMPATIBILITY, MADS_BASE_DESC)); + + params.remove("EnforceTorqueControl"); + torque_allowed = false; } + madsToggle->setEnabled(_offroad); madsSettingsButton->setEnabled(madsToggle->isToggled()); + torqueLateralControlToggle->setEnabled(_offroad && torque_allowed && !nnlcToggle->isToggled()); + torqueLateralControlSettingsButton->setEnabled(torqueLateralControlToggle->isToggled()); + blinkerPauseLateralSettings->refresh(); offroad = _offroad; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h index 7b5e73fceb..88c4d401d0 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h @@ -15,6 +15,7 @@ #include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h" #include "selfdrive/ui/qt/util.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" #include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" @@ -35,7 +36,6 @@ private: QStackedLayout* main_layout = nullptr; QWidget* sunnypilotScreen = nullptr; ScrollViewSP *sunnypilotScroller = nullptr; - std::vector toggleOffroadOnly; bool offroad; ParamControl *madsToggle; @@ -45,6 +45,9 @@ private: LaneChangeSettings *laneChangeWidget = nullptr; NeuralNetworkLateralControl *nnlcToggle = nullptr; BlinkerPauseLateralSettings *blinkerPauseLateralSettings = nullptr; + ParamControl *torqueLateralControlToggle; + PushButtonSP *torqueLateralControlSettingsButton; + TorqueLateralControlSettings *torqueLateralControlWidget = nullptr; const QString MADS_BASE_DESC = tr("Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC)."); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h index 295072d1ef..6c02d627fa 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/helpers.h @@ -13,9 +13,9 @@ enum class SpeedLimitOffsetType { }; inline const QString SpeedLimitOffsetTypeTexts[]{ - QObject::tr("None"), - QObject::tr("Fixed"), - QObject::tr("Percent"), + QT_TRANSLATE_NOOP("SpeedLimitSettings", "None"), + QT_TRANSLATE_NOOP("SpeedLimitSettings", "Fixed"), + QT_TRANSLATE_NOOP("SpeedLimitSettings", "Percent"), }; enum class SpeedLimitSourcePolicy { @@ -27,11 +27,11 @@ enum class SpeedLimitSourcePolicy { }; inline const QString SpeedLimitSourcePolicyTexts[]{ - QObject::tr("Car\nOnly"), - QObject::tr("Map\nOnly"), - QObject::tr("Car\nFirst"), - QObject::tr("Map\nFirst"), - QObject::tr("Combined\nData") + QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Car\nOnly"), + QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Map\nOnly"), + QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Car\nFirst"), + QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Map\nFirst"), + QT_TRANSLATE_NOOP("SpeedLimitPolicy", "Combined\nData") }; enum class SpeedLimitMode { @@ -42,8 +42,8 @@ enum class SpeedLimitMode { }; inline const QString SpeedLimitModeTexts[]{ - QObject::tr("Off"), - QObject::tr("Information"), - QObject::tr("Warning"), - QObject::tr("Assist"), + QT_TRANSLATE_NOOP("SpeedLimitSettings", "Off"), + QT_TRANSLATE_NOOP("SpeedLimitSettings", "Information"), + QT_TRANSLATE_NOOP("SpeedLimitSettings", "Warning"), + QT_TRANSLATE_NOOP("SpeedLimitSettings", "Assist"), }; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.cc index 764a8e0208..c54ff11f69 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_policy.cc @@ -23,11 +23,11 @@ SpeedLimitPolicy::SpeedLimitPolicy(QWidget *parent) : QWidget(parent) { ListWidgetSP *list = new ListWidgetSP(this); std::vector speed_limit_policy_texts{ - SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::CAR_ONLY)], - SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::MAP_ONLY)], - SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::CAR_FIRST)], - SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::MAP_FIRST)], - SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::COMBINED)] + tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::CAR_ONLY)].toStdString().c_str()), + tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::MAP_ONLY)].toStdString().c_str()), + tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::CAR_FIRST)].toStdString().c_str()), + tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::MAP_FIRST)].toStdString().c_str()), + tr(SpeedLimitSourcePolicyTexts[static_cast(SpeedLimitSourcePolicy::COMBINED)].toStdString().c_str()) }; speed_limit_policy = new ButtonParamControlSP( "SpeedLimitPolicy", diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc index ff5d6221ce..1696c7f63a 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc @@ -7,6 +7,8 @@ #include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h" +#include "selfdrive/ui/sunnypilot/qt/util.h" + SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent) { subPanelFrame = new QFrame(); QVBoxLayout *subPanelLayout = new QVBoxLayout(subPanelFrame); @@ -25,10 +27,10 @@ SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent) speedLimitPolicyScreen = new SpeedLimitPolicy(this); std::vector speed_limit_mode_texts{ - SpeedLimitModeTexts[static_cast(SpeedLimitMode::OFF)], - SpeedLimitModeTexts[static_cast(SpeedLimitMode::INFORMATION)], - SpeedLimitModeTexts[static_cast(SpeedLimitMode::WARNING)], - SpeedLimitModeTexts[static_cast(SpeedLimitMode::ASSIST)], + tr(SpeedLimitModeTexts[static_cast(SpeedLimitMode::OFF)].toStdString().c_str()), + tr(SpeedLimitModeTexts[static_cast(SpeedLimitMode::INFORMATION)].toStdString().c_str()), + tr(SpeedLimitModeTexts[static_cast(SpeedLimitMode::WARNING)].toStdString().c_str()), + tr(SpeedLimitModeTexts[static_cast(SpeedLimitMode::ASSIST)].toStdString().c_str()) }; speed_limit_mode_settings = new ButtonParamControlSP( "SpeedLimitMode", @@ -64,9 +66,9 @@ SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent) QVBoxLayout *offsetLayout = new QVBoxLayout(offsetFrame); std::vector speed_limit_offset_texts{ - SpeedLimitOffsetTypeTexts[static_cast(SpeedLimitOffsetType::NONE)], - SpeedLimitOffsetTypeTexts[static_cast(SpeedLimitOffsetType::FIXED)], - SpeedLimitOffsetTypeTexts[static_cast(SpeedLimitOffsetType::PERCENT)] + tr(SpeedLimitOffsetTypeTexts[static_cast(SpeedLimitOffsetType::NONE)].toStdString().c_str()), + tr(SpeedLimitOffsetTypeTexts[static_cast(SpeedLimitOffsetType::FIXED)].toStdString().c_str()), + tr(SpeedLimitOffsetTypeTexts[static_cast(SpeedLimitOffsetType::PERCENT)].toStdString().c_str()) }; speed_limit_offset_settings = new ButtonParamControlSP( "SpeedLimitOffsetType", @@ -109,7 +111,7 @@ void SpeedLimitSettings::refresh() { QString offsetLabel = QString::fromStdString(params.get("SpeedLimitValueOffset")); bool has_longitudinal_control; - bool intelligent_cruise_button_management_available; + bool has_icbm; auto cp_bytes = params.get("CarParamsPersistent"); auto cp_sp_bytes = params.get("CarParamsSPPersistent"); if (!cp_bytes.empty() && !cp_sp_bytes.empty()) { @@ -121,10 +123,16 @@ void SpeedLimitSettings::refresh() { cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot(); has_longitudinal_control = hasLongitudinalControl(CP); - intelligent_cruise_button_management_available = CP_SP.getIntelligentCruiseButtonManagementAvailable(); + has_icbm = hasIntelligentCruiseButtonManagement(CP_SP); + + if (!has_longitudinal_control && !has_icbm) { + if (speed_limit_mode_param == SpeedLimitMode::ASSIST) { + params.put("SpeedLimitMode", std::to_string(static_cast(SpeedLimitMode::WARNING))); + } + } } else { has_longitudinal_control = false; - intelligent_cruise_button_management_available = false; + has_icbm = false; } speed_limit_mode_settings->setDescription(modeDescription(speed_limit_mode_param)); @@ -144,13 +152,14 @@ void SpeedLimitSettings::refresh() { speed_limit_offset->showDescription(); } - if (has_longitudinal_control || intelligent_cruise_button_management_available) { + if (has_longitudinal_control || has_icbm) { speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues(getSpeedLimitModeValues())); } else { speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues( - {SpeedLimitMode::OFF,SpeedLimitMode::INFORMATION, SpeedLimitMode::WARNING})); + {SpeedLimitMode::OFF, SpeedLimitMode::INFORMATION, SpeedLimitMode::WARNING})); } + speed_limit_mode_settings->refresh(); speed_limit_mode_settings->showDescription(); speed_limit_offset->showDescription(); } @@ -158,3 +167,7 @@ void SpeedLimitSettings::refresh() { void SpeedLimitSettings::showEvent(QShowEvent *event) { refresh(); } + +void SpeedLimitSettings::hideEvent(QHideEvent *event) { + setCurrentWidget(subPanelFrame); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h index f76f9bea2a..69e85814c2 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h @@ -21,6 +21,7 @@ public: SpeedLimitSettings(QWidget *parent = nullptr); void refresh(); void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent *event) override; signals: void backPress(); @@ -34,6 +35,7 @@ private: SpeedLimitPolicy *speedLimitPolicyScreen; ButtonParamControlSP *speed_limit_offset_settings; OptionControlSP *speed_limit_offset; + bool icbm_available = false; static QString offsetDescription(SpeedLimitOffsetType type = SpeedLimitOffsetType::NONE) { QString none_str = tr("⦿ None: No Offset"); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.cc index 3e3977ff64..2cc59ea333 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.cc @@ -7,6 +7,8 @@ #include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h" +#include "selfdrive/ui/sunnypilot/qt/util.h" + LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) { setStyleSheet(R"( #back_btn { @@ -40,9 +42,20 @@ LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) { "", this ); - intelligentCruiseButtonManagement->setConfirmation(true, false); + QObject::connect(intelligentCruiseButtonManagement, &ParamControlSP::toggleFlipped, this, [=](bool) { + refresh(offroad); + }); list->addItem(intelligentCruiseButtonManagement); + dynamicExperimentalControl = new ParamControlSP( + "DynamicExperimentalControl", + tr("Dynamic Experimental Control (DEC)"), + tr("Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal."), + "", + this + ); + list->addItem(dynamicExperimentalControl); + SmartCruiseControlVision = new ParamControl( "SmartCruiseControlVision", tr("Smart Cruise Control - Vision"), @@ -86,6 +99,10 @@ void LongitudinalPanel::showEvent(QShowEvent *event) { refresh(offroad); } +void LongitudinalPanel::hideEvent(QHideEvent *event) { + main_layout->setCurrentWidget(cruisePanelScreen); +} + void LongitudinalPanel::refresh(bool _offroad) { auto cp_bytes = params.get("CarParamsPersistent"); auto cp_sp_bytes = params.get("CarParamsSPPersistent"); @@ -99,11 +116,41 @@ void LongitudinalPanel::refresh(bool _offroad) { has_longitudinal_control = hasLongitudinalControl(CP); is_pcm_cruise = CP.getPcmCruise(); - intelligent_cruise_button_management_available = CP_SP.getIntelligentCruiseButtonManagementAvailable(); + has_icbm = hasIntelligentCruiseButtonManagement(CP_SP); + + if (CP_SP.getIntelligentCruiseButtonManagementAvailable() && !has_longitudinal_control) { + intelligentCruiseButtonManagement->setEnabled(offroad); + } else { + params.remove("IntelligentCruiseButtonManagement"); + intelligentCruiseButtonManagement->setEnabled(false); + } + + if (has_longitudinal_control || has_icbm) { + // enable Custom ACC Increments when long is available and is not PCM cruise + customAccIncrement->setEnabled(((has_longitudinal_control && !is_pcm_cruise) || has_icbm) && offroad); + dynamicExperimentalControl->setEnabled(has_longitudinal_control); + SmartCruiseControlVision->setEnabled(true); + SmartCruiseControlMap->setEnabled(true); + } else { + params.remove("CustomAccIncrementsEnabled"); + params.remove("DynamicExperimentalControl"); + params.remove("SmartCruiseControlVision"); + params.remove("SmartCruiseControlMap"); + customAccIncrement->setEnabled(false); + dynamicExperimentalControl->setEnabled(false); + SmartCruiseControlVision->setEnabled(false); + SmartCruiseControlMap->setEnabled(false); + } + + intelligentCruiseButtonManagement->refresh(); + customAccIncrement->refresh(); + dynamicExperimentalControl->refresh(); + SmartCruiseControlVision->refresh(); + SmartCruiseControlMap->refresh(); } else { has_longitudinal_control = false; is_pcm_cruise = false; - intelligent_cruise_button_management_available = false; + has_icbm = false; } QString accEnabledDescription = tr("Enable custom Short & Long press increments for cruise speed increase/decrease."); @@ -115,33 +162,19 @@ void LongitudinalPanel::refresh(bool _offroad) { customAccIncrement->setDescription(onroadOnlyDescription); customAccIncrement->showDescription(); } else { - if (has_longitudinal_control || intelligent_cruise_button_management_available) { - if (is_pcm_cruise) { + if (has_longitudinal_control || has_icbm) { + if (has_longitudinal_control && is_pcm_cruise) { customAccIncrement->setDescription(accPcmCruiseDisabledDescription); customAccIncrement->showDescription(); } else { customAccIncrement->setDescription(accEnabledDescription); } } else { - params.remove("CustomAccIncrementsEnabled"); customAccIncrement->toggleFlipped(false); customAccIncrement->setDescription(accNoLongDescription); customAccIncrement->showDescription(); - params.remove("IntelligentCruiseButtonManagement"); - intelligentCruiseButtonManagement->toggleFlipped(false); } } - bool icbm_allowed = intelligent_cruise_button_management_available && !has_longitudinal_control; - intelligentCruiseButtonManagement->setEnabled(icbm_allowed && offroad); - - // enable toggle when long is available and is not PCM cruise - bool cai_allowed = (has_longitudinal_control && !is_pcm_cruise) || icbm_allowed; - customAccIncrement->setEnabled(cai_allowed && !offroad); - customAccIncrement->refresh(); - - SmartCruiseControlVision->setEnabled(has_longitudinal_control || icbm_allowed); - SmartCruiseControlMap->setEnabled(has_longitudinal_control || icbm_allowed); - offroad = _offroad; } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h index 0b7f39c645..2b9c0b8968 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h @@ -18,13 +18,14 @@ class LongitudinalPanel : public QWidget { public: explicit LongitudinalPanel(QWidget *parent = nullptr); void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent *event) override; void refresh(bool _offroad); private: Params params; bool has_longitudinal_control = false; bool is_pcm_cruise = false; - bool intelligent_cruise_button_management_available = false;; + bool has_icbm = false; bool offroad = false; QStackedLayout *main_layout = nullptr; @@ -34,6 +35,7 @@ private: ParamControl *SmartCruiseControlVision; ParamControl *SmartCruiseControlMap; ParamControl *intelligentCruiseButtonManagement = nullptr; + ParamControl *dynamicExperimentalControl = nullptr; SpeedLimitSettings *speedLimitScreen; PushButtonSP *speedLimitSettings; }; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.cc index 332fd71a18..e946d7870f 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.cc @@ -12,6 +12,7 @@ #include #include "common/swaglog.h" +#include "selfdrive/ui/sunnypilot/qt/util.h" #include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" OsmPanel::OsmPanel(QWidget *parent) : QFrame(parent) { @@ -91,24 +92,30 @@ ButtonControlSP *OsmPanel::setupOsmDownloadButton(QWidget *parent) { locationTitles.push_back(std::get<0>(loc)); } - const QString selection = MultiOptionDialog::getSelection(tr("Country"), locationTitles, currentTitle, this); - if (!selection.isEmpty()) { - params.put("OsmLocal", "1"); - params.put("OsmLocationTitle", selection.toStdString()); - for (auto &loc: locations) { - if (std::get<0>(loc) == selection) { - params.put("OsmLocationName", std::get<1>(loc).toStdString()); - break; + InputDialog d(tr("Search Country"), this, tr("Enter search keywords, or leave blank to list all countries."), false); + d.setMinLength(0); + const int ret = d.exec(); + if (ret) { + const QString selection = search(d.text(), locationTitles, tr("Select Country")); + if (!selection.isEmpty()) { + params.put("OsmLocal", "1"); + params.put("OsmLocationTitle", selection.toStdString()); + for (auto &loc: locations) { + if (std::get<0>(loc) == selection) { + params.put("OsmLocationName", std::get<1>(loc).toStdString()); + break; + } } - } - if (params.get("OsmLocationName") == "US") { - usStatesBtn->click(); - return; - } else if (selection != "== None ==") { - if (showConfirmationDialog(parent)) { - osm_download_in_progress = true; - params.putBool("OsmDbUpdatesCheck", true); - updateLabels(); + if (params.get("OsmLocationName") == "US") { + usStatesBtn->click(); + return; + } + if (selection != "== None ==") { + if (showConfirmationDialog(parent)) { + osm_download_in_progress = true; + params.putBool("OsmDbUpdatesCheck", true); + updateLabels(); + } } } } @@ -135,20 +142,25 @@ ButtonControlSP *OsmPanel::setupUsStatesButton(QWidget *parent) { locationTitles.push_back(std::get<0>(loc)); } - const QString selection = MultiOptionDialog::getSelection(tr("State"), locationTitles, currentTitle, this); - if (!selection.isEmpty()) { - params.put("OsmStateTitle", selection.toStdString()); - for (auto &loc: locations) { - if (std::get<0>(loc) == selection) { - params.put("OsmStateName", std::get<1>(loc).toStdString()); - break; + InputDialog d(tr("Search State"), this, tr("Enter search keywords, or leave blank to list all states."), false); + d.setMinLength(0); + const int ret = d.exec(); + if (ret) { + const QString selection = search(d.text(), locationTitles, tr("Select State")); + if (!selection.isEmpty()) { + params.put("OsmStateTitle", selection.toStdString()); + for (auto &loc: locations) { + if (std::get<0>(loc) == selection) { + params.put("OsmStateName", std::get<1>(loc).toStdString()); + break; + } + } + usStatesBtn->setValue(selection); + if (showConfirmationDialog(parent)) { + osm_download_in_progress = true; + params.putBool("OsmDbUpdatesCheck", true); + updateLabels(); } - } - usStatesBtn->setValue(selection); - if (showConfirmationDialog(parent)) { - osm_download_in_progress = true; - params.putBool("OsmDbUpdatesCheck", true); - updateLabels(); } } updateLabels(); @@ -281,3 +293,15 @@ void OsmPanel::updateMapSize() { mapSizeFuture = QtConcurrent::run(getDirSize, MAP_PATH); } } + +QString OsmPanel::search(const QString &query, const QStringList &list, const QString &prompt_text) { + QStringList lst_results = searchFromList(query, list); + QString selection; + + if (lst_results.isEmpty()) { + ConfirmationDialog::alert(tr("No results found for keywords: %1").arg(query), this); + return selection; + } + selection = MultiOptionDialog::getSelection(prompt_text, lst_results, "", this); + return selection; +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.h index 171129a11c..e4067d415f 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/osm_panel.h @@ -76,6 +76,7 @@ private: void updateDownloadProgress(); static int extractIntFromJson(const QJsonObject &json, const QString &key); QString processUpdateStatus(bool pending_update_check, int total_files, int downloaded_files, const QJsonObject &json, bool failed_state); + QString search(const QString &query, const QStringList &list, const QString &prompt_text); ConfirmationDialog *confirmationDialog; LabelControlSP *mapdVersion; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.cc index 96d945ab53..4bbf894572 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.cc @@ -21,7 +21,7 @@ SunnylinkPanel::SunnylinkPanel(QWidget *parent) : QFrame(parent) { paramsRefresh(param_name, param_value); }); - is_sunnylink_enabled = Params().getBool("SunnylinkEnabled"); + is_sunnylink_enabled = params.getBool("SunnylinkEnabled"); connect(uiStateSP(), &UIStateSP::sunnylinkRolesChanged, this, &SunnylinkPanel::updatePanel); connect(uiStateSP(), &UIStateSP::sunnylinkDeviceUsersChanged, this, &SunnylinkPanel::updatePanel); connect(uiStateSP(), &UIStateSP::offroadTransition, [=](bool offroad) { @@ -272,7 +272,7 @@ void SunnylinkPanel::updatePanel() { const auto sunnylinkDongleId = getSunnylinkDongleId().value_or(tr("N/A")); sunnylinkEnabledBtn->setEnabled(!is_onroad); - is_sunnylink_enabled = Params().getBool("SunnylinkEnabled"); + is_sunnylink_enabled = params.getBool("SunnylinkEnabled"); bool is_sub = uiStateSP()->isSunnylinkSponsor() && is_sunnylink_enabled; auto max_current_sponsor_rule = uiStateSP()->sunnylinkSponsorRole(); auto role_name = max_current_sponsor_rule.getSponsorTierString(); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.cc index 47c4057f44..302740a94a 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.cc @@ -8,7 +8,52 @@ #include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h" SubaruSettings::SubaruSettings(QWidget *parent) : BrandSettingsInterface(parent) { + stopAndGoToggle = new ParamControl("SubaruStopAndGo", tr("Stop and Go (Beta)"), "", ""); + stopAndGoToggle->setConfirmation(true, false); + list->addItem(stopAndGoToggle); + + stopAndGoManualParkingBrakeToggle = new ParamControl( + "SubaruStopAndGoManualParkingBrake", + tr("Stop and Go for Manual Parking Brake (Beta)"), + "", + "" + ); + stopAndGoManualParkingBrakeToggle->setConfirmation(true, false); + list->addItem(stopAndGoManualParkingBrakeToggle); } void SubaruSettings::updateSettings() { + auto cp_bytes = params.get("CarParamsPersistent"); + if (!cp_bytes.empty()) { + AlignedBuffer aligned_buf; + capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); + cereal::CarParams::Reader CP = cmsg.getRoot(); + + is_subaru = CP.getBrand() == "subaru"; + + if (is_subaru) { + if (!(CP.getFlags() & (SUBARU_FLAG_GLOBAL_GEN2 | SUBARU_FLAG_HYBRID))) { + has_stop_and_go = true; + } + } + } else { + is_subaru = false; + has_stop_and_go = false; + } + + bool stop_and_go_disabled = !offroad || !has_stop_and_go; + QString stop_and_go_desc = stopAndGoDescriptionBuilder(stopAndGoDesc); + QString stop_and_go_manual_parking_brake_desc = stopAndGoDescriptionBuilder(stopAndGoManualParkingBrakeDesc); + if (stop_and_go_disabled) { + stop_and_go_desc = stopAndGoDescriptionBuilder(stopAndGoDesc, stopAndGoDisabledMsg()); + stop_and_go_manual_parking_brake_desc = stopAndGoDescriptionBuilder(stopAndGoManualParkingBrakeDesc, stopAndGoDisabledMsg()); + } + + stopAndGoToggle->setEnabled(has_stop_and_go); + stopAndGoToggle->setDescription(stop_and_go_desc); + stopAndGoToggle->showDescription(); + + stopAndGoManualParkingBrakeToggle->setEnabled(has_stop_and_go); + stopAndGoManualParkingBrakeToggle->setDescription(stop_and_go_manual_parking_brake_desc); + stopAndGoManualParkingBrakeToggle->showDescription(); } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h index a715951ad9..2bb160beba 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/subaru_settings.h @@ -14,6 +14,9 @@ #include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" #include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" +const int SUBARU_FLAG_GLOBAL_GEN2 = 4; +const int SUBARU_FLAG_HYBRID = 32; + class SubaruSettings : public BrandSettingsInterface { Q_OBJECT @@ -23,4 +26,32 @@ public: private: bool offroad = false; + bool is_subaru; + bool has_stop_and_go; + + ParamControl* stopAndGoToggle; + ParamControl* stopAndGoManualParkingBrakeToggle; + + QString stopAndGoDesc = tr("Experimental feature to enable auto-resume during stop-and-go for certain supported Subaru platforms."); + QString stopAndGoManualParkingBrakeDesc = tr("Experimental feature to enable stop and go for Subaru Global models with manual handbrake. Models with electric parking brake should keep this disabled. Thanks to martinl for this implementation!"); + + QString stopAndGoDisabledMsg() const { + if (is_subaru && !has_stop_and_go) { + return tr("This feature is currently not available on this platform."); + } + + if (!is_subaru) { + return tr("Start the car to check car compatibility."); + } + + if (!offroad) { + return tr("Enable \"Always Offroad\" in Device panel, or turn vehicle off to toggle."); + } + + return QString(); + } + + static QString stopAndGoDescriptionBuilder(const QString &base_description, const QString &custom_description = "") { + return "" + custom_description + "

" + base_description; + } }; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc index 7c1107d653..0e42f777cd 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc @@ -69,6 +69,27 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) { "", false, }, + { + "TrueVEgoUI", + tr("Speedometer: Always Display True Speed"), + tr("Always display the true vehicle current speed from wheel speed sensors."), + "", + false, + }, + { + "HideVEgoUI", + tr("Speedometer: Hide from Onroad Screen"), + tr("When enabled, the speedometer on the onroad screen is not displayed."), + "", + false, + }, + { + "ShowTurnSignals", + tr("Display Turn Signals"), + tr("When enabled, visual turn indicators are drawn on the HUD."), + "", + false, + }, }; // Add regular toggles first @@ -119,6 +140,40 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) { vlayout->addWidget(sunnypilotScroller); main_layout->addWidget(sunnypilotScreen); + + QObject::connect(uiState(), &UIState::offroadTransition, this, &VisualsPanel::refreshLongitudinalStatus); + + refreshLongitudinalStatus(); +} + +void VisualsPanel::refreshLongitudinalStatus() { + auto cp_bytes = params.get("CarParamsPersistent"); + if (!cp_bytes.empty()) { + AlignedBuffer aligned_buf; + capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); + cereal::CarParams::Reader CP = cmsg.getRoot(); + + has_longitudinal_control = hasLongitudinalControl(CP); + } else { + has_longitudinal_control = false; + } + + if (chevron_info_settings) { + QString chevronEnabledDescription = tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control)."); + QString chevronNoLongDescription = tr("This feature requires openpilot longitudinal control to be available."); + + if (has_longitudinal_control) { + chevron_info_settings->setDescription(chevronEnabledDescription); + } else { + // Reset to "Off" when longitudinal not available + params.put("ChevronInfo", "0"); + chevron_info_settings->setDescription(chevronNoLongDescription); + } + + // Enable only when longitudinal is available + chevron_info_settings->setEnabled(has_longitudinal_control); + chevron_info_settings->refresh(); + } } void VisualsPanel::paramsRefresh() { diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h index 30ff31c301..76a846dd45 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h @@ -19,6 +19,7 @@ public: explicit VisualsPanel(QWidget *parent = nullptr); void paramsRefresh(); + void refreshLongitudinalStatus(); protected: QStackedLayout* main_layout = nullptr; @@ -29,4 +30,6 @@ protected: ParamWatcher * param_watcher; ButtonParamControlSP *chevron_info_settings; ButtonParamControlSP *dev_ui_settings; + + bool has_longitudinal_control = false; }; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/alerts.cc b/selfdrive/ui/sunnypilot/qt/onroad/alerts.cc new file mode 100644 index 0000000000..695f6d2ce8 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/alerts.cc @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + * + * This file is part of sunnypilot and is licensed under the MIT License. + * See the LICENSE.md file in the root directory for more details. + */ + +#include "selfdrive/ui/sunnypilot/qt/onroad/alerts.h" + +#include +#include +#include +#include + +OnroadAlerts::Alert OnroadAlertsSP::getAlert(const SubMaster &sm, uint64_t started_frame) { + OnroadAlerts::Alert alert = OnroadAlerts::getAlert(sm, started_frame); + alert.text1.replace("openpilot", "sunnypilot"); + alert.text2.replace("openpilot", "sunnypilot"); + return alert; +} + +void OnroadAlertsSP::paintEvent(QPaintEvent *event) { + if (alert.size == cereal::SelfdriveState::AlertSize::NONE) { + return; + } else if (alert.size == cereal::SelfdriveState::AlertSize::FULL) { + OnroadAlerts::paintEvent(event); + return; + } + static std::map alert_heights = { + {cereal::SelfdriveState::AlertSize::SMALL, 271}, + {cereal::SelfdriveState::AlertSize::MID, 420} + }; + int h = alert_heights[alert.size]; + + QPainter p(this); + QFont topFont; + QFont bottomFont; + QRect topTextBoundingRect; + QRect bottomTextBoundingRect; + QRect rect; + + int margin = 40; + int radius = 30; + + const int dev_ui_info = uiStateSP()->scene.dev_ui_info; + const int v_adjustment = dev_ui_info > 1 && alert.size != cereal::SelfdriveState::AlertSize::FULL ? 40 : 0; + const int h_adjustment = dev_ui_info > 0 && alert.size != cereal::SelfdriveState::AlertSize::FULL ? 230 : 0; + + if (alert.size == cereal::SelfdriveState::AlertSize::SMALL) { + topFont = InterFont(74, QFont::DemiBold); + QFontMetrics fmTop(topFont); + topTextBoundingRect = fmTop.boundingRect( + QRect(0 + margin, height() - h + margin - v_adjustment, width() - margin * 2 - h_adjustment, 0), Qt::TextWordWrap, + alert.text1); + h = topTextBoundingRect.height(); + rect = QRect(0 + margin, height() - h - margin * 2 - v_adjustment, width() - margin * 2 - h_adjustment, h + margin); + } else if (alert.size == cereal::SelfdriveState::AlertSize::MID) { + topFont = InterFont(88, QFont::Bold); + bottomFont = InterFont(66); + QFontMetrics fmTop(topFont); + QFontMetrics fmBotton(bottomFont); + topTextBoundingRect = fmTop.boundingRect( + QRect(0 + margin, height() - h + margin - v_adjustment, width() - margin * 2 - h_adjustment, 0), Qt::TextWordWrap, + alert.text1); + bottomTextBoundingRect = fmBotton.boundingRect( + QRect(0 + margin, height() - h + margin - v_adjustment + topTextBoundingRect.height(), + width() - margin * 2 - h_adjustment, 0), Qt::TextWordWrap, alert.text2); + h = topTextBoundingRect.height() + bottomTextBoundingRect.height() + margin * 2; + rect = QRect(0 + margin, height() - h - margin * 2 - v_adjustment, width() - margin * 2 - h_adjustment, h + margin); + } + + + // draw background + gradient + // draw background + gradient + p.setPen(Qt::NoPen); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + p.setBrush(QBrush(alert_colors[alert.status])); + p.drawRoundedRect(rect, radius, radius); + + QLinearGradient g(0, rect.y(), 0, rect.bottom()); + g.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.05)); + g.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0.35)); + + p.setCompositionMode(QPainter::CompositionMode_DestinationOver); + p.setBrush(QBrush(g)); + p.drawRoundedRect(rect, radius, radius); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + + // text + p.setPen(QColor(0xff, 0xff, 0xff)); + p.setRenderHint(QPainter::TextAntialiasing); + p.setFont(topFont); + if (alert.size == cereal::SelfdriveState::AlertSize::SMALL) { + p.drawText(rect, Qt::AlignCenter | Qt::TextWordWrap, alert.text1); + } else if (alert.size == cereal::SelfdriveState::AlertSize::MID) { + QRect topText = QRect(rect.x(), rect.top() + margin, rect.width(), topTextBoundingRect.height()); + p.drawText(topText, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWordWrap | Qt::AlignCenter, alert.text1); + p.setFont(bottomFont); + p.drawText(QRect(rect.x(), topText.bottom() + margin, rect.width(), bottomTextBoundingRect.height()), + Qt::AlignHCenter | Qt::TextWordWrap | Qt::AlignCenter, alert.text2); + } +} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/alerts.h b/selfdrive/ui/sunnypilot/qt/onroad/alerts.h new file mode 100644 index 0000000000..8b65309f46 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/onroad/alerts.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + * + * This file is part of sunnypilot and is licensed under the MIT License. + * See the LICENSE.md file in the root directory for more details. + */ + +#pragma once + +#include "selfdrive/ui/qt/onroad/alerts.h" +#include "selfdrive/ui/sunnypilot/ui.h" + +class OnroadAlertsSP : public OnroadAlerts { + Q_OBJECT + +public: + OnroadAlertsSP(QWidget *parent = 0) : OnroadAlerts(parent) {} + +protected: + void paintEvent(QPaintEvent *) override; + Alert getAlert(const SubMaster &sm, uint64_t started_frame); +}; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc index 1d5567161a..f9b62b0ae7 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.cc @@ -18,4 +18,10 @@ void AnnotatedCameraWidgetSP::updateState(const UIState &s) { void AnnotatedCameraWidgetSP::showEvent(QShowEvent *event) { AnnotatedCameraWidget::showEvent(event); ui_update_params_sp(uiState()); + uiStateSP()->reset_onroad_sleep_timer(OnroadTimerStatusToggle::RESUME); +} + +void AnnotatedCameraWidgetSP::hideEvent(QHideEvent *event) { + AnnotatedCameraWidget::hideEvent(event); + uiStateSP()->reset_onroad_sleep_timer(OnroadTimerStatusToggle::PAUSE); } diff --git a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h index 8c0a385657..2e7609dae0 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h +++ b/selfdrive/ui/sunnypilot/qt/onroad/annotated_camera.h @@ -18,4 +18,5 @@ public: protected: void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent* event) override; }; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/hud.cc b/selfdrive/ui/sunnypilot/qt/onroad/hud.cc index 21d66ffa99..2fc9eb98fc 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/hud.cc +++ b/selfdrive/ui/sunnypilot/qt/onroad/hud.cc @@ -12,43 +12,65 @@ HudRendererSP::HudRendererSP() { - plus_arrow_up_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_plus_arrow_up", {105, 105}); - minus_arrow_down_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_minus_arrow_down", {105, 105}); + plus_arrow_up_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_plus_arrow_up", {90, 90}); + minus_arrow_down_img = loadPixmap("../../sunnypilot/selfdrive/assets/img_minus_arrow_down", {90, 90}); - int small_max = e2e_alert_small * 2 - 40; - int large_max = e2e_alert_large * 2 - 40; - green_light_alert_small_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/green_light.png", {small_max, small_max}); - green_light_alert_large_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/green_light.png", {large_max, large_max}); - lead_depart_alert_small_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/lead_depart.png", {small_max, small_max}); - lead_depart_alert_large_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/lead_depart.png", {large_max, large_max}); + int size = e2e_alert_size * 2 - 40; + green_light_alert_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/green_light.png", {size, size}); + lead_depart_alert_img = loadPixmap("../../sunnypilot/selfdrive/assets/images/lead_depart.png", {size, size}); } void HudRendererSP::updateState(const UIState &s) { HudRenderer::updateState(s); + float speedConv = is_metric ? MS_TO_KPH : MS_TO_MPH; + devUiInfo = s.scene.dev_ui_info; + roadName = s.scene.road_name; + showTurnSignals = s.scene.turn_signals; + speedLimitMode = static_cast(s.scene.speed_limit_mode); + speedUnit = is_metric ? tr("km/h") : tr("mph"); + standstillTimer = s.scene.standstill_timer; + const SubMaster &sm = *(s.sm); const auto cs = sm["controlsState"].getControlsState(); const auto car_state = sm["carState"].getCarState(); const auto car_control = sm["carControl"].getCarControl(); const auto radar_state = sm["radarState"].getRadarState(); const auto is_gps_location_external = sm.rcv_frame("gpsLocationExternal") > 1; - const auto gpsLocation = is_gps_location_external ? sm["gpsLocationExternal"].getGpsLocationExternal() : sm["gpsLocation"].getGpsLocation(); + const char *gps_source = is_gps_location_external ? "gpsLocationExternal" : "gpsLocation"; + const auto gpsLocation = is_gps_location_external ? sm[gps_source].getGpsLocationExternal() : sm[gps_source].getGpsLocation(); const auto ltp = sm["liveTorqueParameters"].getLiveTorqueParameters(); const auto car_params = sm["carParams"].getCarParams(); + const auto car_params_sp = sm["carParamsSP"].getCarParamsSP(); const auto lp_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP(); const auto lmd = sm["liveMapDataSP"].getLiveMapDataSP(); - float speedConv = is_metric ? MS_TO_KPH : MS_TO_MPH; - speedLimit = lp_sp.getSpeedLimit().getResolver().getSpeedLimit() * speedConv; - speedLimitLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLast() * speedConv; - speedLimitOffset = lp_sp.getSpeedLimit().getResolver().getSpeedLimitOffset() * speedConv; - speedLimitValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitValid(); - speedLimitLastValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLastValid(); - speedLimitFinalLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitFinalLast() * speedConv; - speedLimitMode = static_cast(s.scene.speed_limit_mode); - speedLimitAssistState = lp_sp.getSpeedLimit().getAssist().getState(); - speedLimitAssistActive = lp_sp.getSpeedLimit().getAssist().getActive(); - roadName = s.scene.road_name; + if (sm.updated("carParams")) { + steerControlType = car_params.getSteerControlType(); + } + + if (sm.updated("carParamsSP")) { + pcmCruiseSpeed = car_params_sp.getPcmCruiseSpeed(); + } + + if (sm.updated("longitudinalPlanSP")) { + speedLimit = lp_sp.getSpeedLimit().getResolver().getSpeedLimit() * speedConv; + speedLimitLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLast() * speedConv; + speedLimitOffset = lp_sp.getSpeedLimit().getResolver().getSpeedLimitOffset() * speedConv; + speedLimitValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitValid(); + speedLimitLastValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLastValid(); + speedLimitFinalLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitFinalLast() * speedConv; + speedLimitSource = lp_sp.getSpeedLimit().getResolver().getSource(); + speedLimitAssistState = lp_sp.getSpeedLimit().getAssist().getState(); + speedLimitAssistActive = lp_sp.getSpeedLimit().getAssist().getActive(); + smartCruiseControlVisionEnabled = lp_sp.getSmartCruiseControl().getVision().getEnabled(); + smartCruiseControlVisionActive = lp_sp.getSmartCruiseControl().getVision().getActive(); + smartCruiseControlMapEnabled = lp_sp.getSmartCruiseControl().getMap().getEnabled(); + smartCruiseControlMapActive = lp_sp.getSmartCruiseControl().getMap().getActive(); + } + greenLightAlert = lp_sp.getE2eAlerts().getGreenLightAlert(); + leadDepartAlert = lp_sp.getE2eAlerts().getLeadDepartAlert(); + if (sm.updated("liveMapDataSP")) { roadNameStr = QString::fromStdString(lmd.getRoadName()); speedLimitAheadValid = lmd.getSpeedLimitAheadValid(); @@ -64,7 +86,7 @@ void HudRendererSP::updateState(const UIState &s) { static int reverse_delay = 0; bool reverse_allowed = false; - if (int(car_state.getGearShifter()) != 4) { + if (car_state.getGearShifter() != cereal::CarState::GearShifter::REVERSE) { reverse_delay = 0; reverse_allowed = false; } else { @@ -76,45 +98,62 @@ void HudRendererSP::updateState(const UIState &s) { reversing = reverse_allowed; + if (sm.updated("liveParameters")) { + roll = sm["liveParameters"].getLiveParameters().getRoll(); + } + + if (sm.updated("deviceState")) { + memoryUsagePercent = sm["deviceState"].getDeviceState().getMemoryUsagePercent(); + } + + if (sm.updated(gps_source)) { + gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0; // External reports accuracy, internal does not. + altitude = gpsLocation.getAltitude(); + bearingAccuracyDeg = gpsLocation.getBearingAccuracyDeg(); + bearingDeg = gpsLocation.getBearingDeg(); + } + + if (sm.updated("liveTorqueParameters")) { + torquedUseParams = ltp.getUseParams(); + latAccelFactorFiltered = ltp.getLatAccelFactorFiltered(); + frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered(); + liveValid = ltp.getLiveValid(); + } + latActive = car_control.getLatActive(); + actuators = car_control.getActuators(); + longOverride = car_control.getCruiseControl().getOverride(); + carControlEnabled = car_control.getEnabled(); + steerOverride = car_state.getSteeringPressed(); - - devUiInfo = s.scene.dev_ui_info; - - speedUnit = is_metric ? tr("km/h") : tr("mph"); lead_d_rel = radar_state.getLeadOne().getDRel(); lead_v_rel = radar_state.getLeadOne().getVRel(); lead_status = radar_state.getLeadOne().getStatus(); - steerControlType = car_params.getSteerControlType(); - actuators = car_control.getActuators(); torqueLateral = steerControlType == cereal::CarParams::SteerControlType::TORQUE; angleSteers = car_state.getSteeringAngleDeg(); desiredCurvature = cs.getDesiredCurvature(); curvature = cs.getCurvature(); - roll = sm["liveParameters"].getLiveParameters().getRoll(); - memoryUsagePercent = sm["deviceState"].getDeviceState().getMemoryUsagePercent(); - gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0; // External reports accuracy, internal does not. - altitude = gpsLocation.getAltitude(); vEgo = car_state.getVEgo(); aEgo = car_state.getAEgo(); steeringTorqueEps = car_state.getSteeringTorqueEps(); - bearingAccuracyDeg = gpsLocation.getBearingAccuracyDeg(); - bearingDeg = gpsLocation.getBearingDeg(); - torquedUseParams = ltp.getUseParams(); - latAccelFactorFiltered = ltp.getLatAccelFactorFiltered(); - frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered(); - liveValid = ltp.getLiveValid(); - standstillTimer = s.scene.standstill_timer; isStandstill = car_state.getStandstill(); - longOverride = car_control.getCruiseControl().getOverride(); - smartCruiseControlVisionEnabled = lp_sp.getSmartCruiseControl().getVision().getEnabled(); - smartCruiseControlVisionActive = lp_sp.getSmartCruiseControl().getVision().getActive(); - smartCruiseControlMapEnabled = lp_sp.getSmartCruiseControl().getMap().getEnabled(); - smartCruiseControlMapActive = lp_sp.getSmartCruiseControl().getMap().getActive(); + if (!s.scene.started) standstillElapsedTime = 0.0; - greenLightAlert = lp_sp.getE2eAlerts().getGreenLightAlert(); - leadDepartAlert = lp_sp.getE2eAlerts().getLeadDepartAlert(); + // override stock current speed values + float v_ego = (v_ego_cluster_seen && !s.scene.trueVEgoUI) ? car_state.getVEgoCluster() : car_state.getVEgo(); + speed = std::max(0.0f, v_ego * (is_metric ? MS_TO_KPH : MS_TO_MPH)); + hideVEgoUI = s.scene.hideVEgoUI; + + leftBlinkerOn = car_state.getLeftBlinker(); + rightBlinkerOn = car_state.getRightBlinker(); + leftBlindspot = car_state.getLeftBlindspot(); + rightBlindspot = car_state.getRightBlindspot(); + + speedCluster = car_state.getCruiseState().getSpeedCluster() * speedConv; + + allow_e2e_alerts = sm["selfdriveState"].getSelfdriveState().getAlertSize() == cereal::SelfdriveState::AlertSize::NONE && + sm.rcv_frame("driverStateV2") > s.scene.started_frame && !reversing; } void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) { @@ -128,6 +167,10 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) { drawSetSpeedSP(p, surface_rect); } + if (!hideVEgoUI) { + drawCurrentSpeedSP(p, surface_rect); + } + if (!reversing) { // Smart Cruise Control int x_offset = -260; @@ -170,11 +213,6 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) { drawRightDevUI(p, surface_rect.right() - 184 - UI_BORDER_SIZE * 2, UI_BORDER_SIZE * 2 + rect_right.height()); } - // Standstill Timer - if (standstillTimer) { - drawStandstillTimer(p, surface_rect.right() / 12 * 10, surface_rect.bottom() / 12 * 1.53); - } - // Speed Limit bool showSpeedLimit; bool speed_limit_assist_pre_active_pulse = pulseElement(speedLimitAssistFrame); @@ -208,7 +246,7 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) { drawRoadName(p, surface_rect); // Green Light & Lead Depart Alerts - if (greenLightAlert or leadDepartAlert) { + if (greenLightAlert || leadDepartAlert) { e2eAlertDisplayTimer = 3 * UI_FREQ; // reset onroad sleep timer for e2e alerts uiStateSP()->reset_onroad_sleep_timer(); @@ -218,15 +256,34 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) { e2eAlertFrame++; if (greenLightAlert) { alert_text = tr("GREEN\nLIGHT"); - alert_img = devUiInfo > 0 ? green_light_alert_small_img : green_light_alert_large_img; + alert_img = green_light_alert_img; } else if (leadDepartAlert) { alert_text = tr("LEAD VEHICLE\nDEPARTING"); - alert_img = devUiInfo > 0 ? lead_depart_alert_small_img : lead_depart_alert_large_img; + alert_img = lead_depart_alert_img; } drawE2eAlert(p, surface_rect); - } else { + } + // Standstill Timer + else if (standstillTimer && isStandstill) { + alert_img = QPixmap(); + + standstillElapsedTime += 1.0 / UI_FREQ; + int minute = static_cast(standstillElapsedTime / 60); + int second = static_cast(standstillElapsedTime - (minute * 60)); + alert_text = QString("%1:%2").arg(minute, 1, 10, QChar('0')).arg(second, 2, 10, QChar('0')); + drawE2eAlert(p, surface_rect, tr("STOPPED")); + e2eAlertFrame++; + } + // No Alerts displayed + else { e2eAlertFrame = 0; + if (!isStandstill) standstillElapsedTime = 0.0; + } + + // Blinker + if (showTurnSignals) { + drawBlinker(p, surface_rect); } } @@ -385,40 +442,6 @@ void HudRendererSP::drawBottomDevUI(QPainter &p, int x, int y) { rw += drawBottomDevUIElement(p, rw, y, altitudeElement.value, altitudeElement.label, altitudeElement.units, altitudeElement.color); } -void HudRendererSP::drawStandstillTimer(QPainter &p, int x, int y) { - if (isStandstill) { - standstillElapsedTime += 1.0 / UI_FREQ; - - int minute = static_cast(standstillElapsedTime / 60); - int second = static_cast(standstillElapsedTime - (minute * 60)); - - // stop sign for standstill timer - const int size = 190; // size - const float angle = M_PI / 8.0; - - QPolygon octagon; - for (int i = 0; i < 8; i++) { - float curr_angle = angle + i * M_PI / 4.0; - int point_x = x + size / 2 * cos(curr_angle); - int point_y = y + size / 2 * sin(curr_angle); - octagon << QPoint(point_x, point_y); - } - - p.setPen(QPen(Qt::white, 6)); - p.setBrush(QColor(255, 90, 81, 200)); // red pastel - p.drawPolygon(octagon); - - QString time_str = QString("%1:%2").arg(minute, 1, 10, QChar('0')).arg(second, 2, 10, QChar('0')); - p.setFont(InterFont(55, QFont::Bold)); - p.setPen(Qt::white); - QRect timerTextRect = p.fontMetrics().boundingRect(QString(time_str)); - timerTextRect.moveCenter({x, y}); - p.drawText(timerTextRect, Qt::AlignCenter, QString(time_str)); - } else { - standstillElapsedTime = 0.0; - } -} - void HudRendererSP::drawSpeedLimitSigns(QPainter &p, QRect &sign_rect) { bool speedLimitWarningEnabled = speedLimitMode >= SpeedLimitMode::WARNING; // TODO-SP: update to include SpeedLimitMode::ASSIST bool hasSpeedLimit = speedLimitValid || speedLimitLastValid; @@ -546,7 +569,8 @@ void HudRendererSP::drawSpeedLimitSigns(QPainter &p, QRect &sign_rect) { } void HudRendererSP::drawUpcomingSpeedLimit(QPainter &p) { - bool speed_limit_ahead = speedLimitAheadValid && speedLimitAhead > 0 && speedLimitAhead != speedLimit && speedLimitAheadValidFrame > 0; + bool speed_limit_ahead = speedLimitAheadValid && speedLimitAhead > 0 && speedLimitAhead != speedLimit && speedLimitAheadValidFrame > 0 && + speedLimitSource == cereal::LongitudinalPlanSP::SpeedLimit::Source::MAP; if (!speed_limit_ahead) { return; } @@ -640,7 +664,7 @@ void HudRendererSP::drawRoadName(QPainter &p, const QRect &surface_rect) { void HudRendererSP::drawSpeedLimitPreActiveArrow(QPainter &p, QRect &sign_rect) { const int sign_margin = 12; - const int arrow_spacing = sign_margin * 3; + const int arrow_spacing = sign_margin * 1.4; int arrow_x = sign_rect.right() + arrow_spacing; int _set_speed = std::nearbyint(set_speed); @@ -689,10 +713,23 @@ void HudRendererSP::drawSetSpeedSP(QPainter &p, const QRect &surface_rect) { } } - // Draw "MAX" text - p.setFont(InterFont(40, QFont::DemiBold)); + // Draw "MAX" or carState.cruiseState.speedCluster (when ICBM is active) text + if (!pcmCruiseSpeed && carControlEnabled) { + if (std::nearbyint(set_speed) != std::nearbyint(speedCluster)) { + icbm_active_counter = 3 * UI_FREQ; + } else if (icbm_active_counter > 0) { + icbm_active_counter--; + } + } else { + icbm_active_counter = 0; + } + int max_str_size = (icbm_active_counter != 0) ? 60 : 40; + int max_str_y = (icbm_active_counter != 0) ? 15 : 27; + QString max_str = (icbm_active_counter != 0) ? QString::number(std::nearbyint(speedCluster)) : tr("MAX"); + + p.setFont(InterFont(max_str_size, QFont::DemiBold)); p.setPen(max_color); - p.drawText(set_speed_rect.adjusted(0, 27, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("MAX")); + p.drawText(set_speed_rect.adjusted(0, max_str_y, 0, 0), Qt::AlignTop | Qt::AlignHCenter, max_str); // Draw set speed QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(set_speed)) : "–"; @@ -701,33 +738,150 @@ void HudRendererSP::drawSetSpeedSP(QPainter &p, const QRect &surface_rect) { p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr); } -void HudRendererSP::drawE2eAlert(QPainter &p, const QRect &surface_rect) { - int size = devUiInfo > 0 ? e2e_alert_small : e2e_alert_large; - int x = surface_rect.center().x() + surface_rect.width() / 4; - int y = surface_rect.center().y() + 40; - x += devUiInfo > 0 ? 0 : 50; - y += devUiInfo > 0 ? 0 : 80; - QRect alertRect(x - size, y - size, size * 2, size * 2); +void HudRendererSP::drawE2eAlert(QPainter &p, const QRect &surface_rect, const QString &alert_alt_text) { + if (!allow_e2e_alerts) return; + + int x = surface_rect.right() - e2e_alert_size - (devUiInfo > 0 ? 180 : 100) - (UI_BORDER_SIZE * 3); + int y = surface_rect.center().y() + 20; + QRect alertRect(x - e2e_alert_size, y - e2e_alert_size, e2e_alert_size * 2, e2e_alert_size * 2); // Alert Circle QPoint center = alertRect.center(); - QColor frameColor = pulseElement(e2eAlertFrame) ? QColor(255, 255, 255, 75) : QColor(0, 255, 0, 75); + QColor frameColor; + if (!alert_alt_text.isEmpty()) frameColor = QColor(255, 255, 255, 75); + else frameColor = pulseElement(e2eAlertFrame) ? QColor(255, 255, 255, 75) : QColor(0, 255, 0, 75); p.setPen(QPen(frameColor, 15)); p.setBrush(QColor(0, 0, 0, 190)); - p.drawEllipse(center, size, size); + p.drawEllipse(center, e2e_alert_size, e2e_alert_size); // Alert Text - QColor txtColor = pulseElement(e2eAlertFrame) ? QColor(255, 255, 255, 255) : QColor(0, 255, 0, 255); - p.setFont(InterFont(48, QFont::Bold)); + QColor txtColor; + QFont font; + int alert_bottom_adjustment; + if (!alert_alt_text.isEmpty()) { + font = InterFont(100, QFont::Bold); + alert_bottom_adjustment = 5; + txtColor = QColor(255, 255, 255, 255); + } else { + font = InterFont(48, QFont::Bold); + alert_bottom_adjustment = 7; + txtColor = pulseElement(e2eAlertFrame) ? QColor(255, 255, 255, 255) : QColor(0, 255, 0, 190); + } p.setPen(txtColor); + p.setFont(font); QFontMetrics fm(p.font()); QRect textRect = fm.boundingRect(alertRect, Qt::TextWordWrap, alert_text); textRect.moveCenter({alertRect.center().x(), alertRect.center().y()}); - textRect.moveBottom(alertRect.bottom() - alertRect.height() / 7); + textRect.moveBottom(alertRect.bottom() - alertRect.height() / alert_bottom_adjustment); p.drawText(textRect, Qt::AlignCenter, alert_text); - // Alert Image - QPointF pixmapCenterOffset = QPointF(alert_img.width() / 2.0, alert_img.height() / 2.0); - QPointF drawPoint = center - pixmapCenterOffset; - p.drawPixmap(drawPoint, alert_img); + if (!alert_alt_text.isEmpty()) { + // Alert Alternate Text + p.setFont(InterFont(80, QFont::Bold)); + p.setPen(QColor(255, 175, 3, 240)); + QFontMetrics fmt(p.font()); + QRect topTextRect = fmt.boundingRect(alertRect, Qt::TextWordWrap, alert_alt_text); + topTextRect.moveCenter({alertRect.center().x(), alertRect.center().y()}); + topTextRect.moveTop(alertRect.top() + alertRect.height() / 3.5); + p.drawText(topTextRect, Qt::AlignCenter, alert_alt_text); + } else { + // Alert Image instead of Top Text + QPointF pixmapCenterOffset = QPointF(alert_img.width() / 2.0, alert_img.height() / 2.0); + QPointF drawPoint = center - pixmapCenterOffset; + p.drawPixmap(drawPoint, alert_img); + } +} + +void HudRendererSP::drawCurrentSpeedSP(QPainter &p, const QRect &surface_rect) { + QString speedStr = QString::number(std::nearbyint(speed)); + + p.setFont(InterFont(176, QFont::Bold)); + HudRenderer::drawText(p, surface_rect.center().x(), 210, speedStr); + + p.setFont(InterFont(66)); + HudRenderer::drawText(p, surface_rect.center().x(), 290, is_metric ? tr("km/h") : tr("mph"), 200); +} + +void HudRendererSP::drawBlinker(QPainter &p, const QRect &surface_rect) { + const bool hazard = leftBlinkerOn && rightBlinkerOn; + int blinkerStatus = hazard ? 2 : (leftBlinkerOn || rightBlinkerOn) ? 1 : 0; + + if (!leftBlinkerOn && !rightBlinkerOn) { + blinkerFrameCounter = 0; + lastBlinkerStatus = 0; + return; + } + + if (blinkerStatus != lastBlinkerStatus) { + blinkerFrameCounter = 0; + lastBlinkerStatus = blinkerStatus; + } + + ++blinkerFrameCounter; + + const int BLINKER_COOLDOWN_FRAMES = UI_FREQ / 10; + if (blinkerFrameCounter < BLINKER_COOLDOWN_FRAMES) { + return; + } + + const int circleRadius = 60; + const int arrowLength = 60; + const int x_gap = 160; + const int y_offset = 272; + + const int centerX = surface_rect.center().x(); + + const QPen bgBorder(Qt::white, 5); + const QPen arrowPen(Qt::NoPen); + + p.save(); + + auto drawArrow = [&](int cx, int cy, int dir, const QBrush &arrowBrush) { + const int bodyLength = arrowLength / 2; + const int bodyWidth = arrowLength / 2; + const int headLength = arrowLength / 2; + const int headWidth = arrowLength; + + QPolygon arrow; + arrow.reserve(7); + arrow << QPoint(cx - dir * bodyLength, cy - bodyWidth / 2) + << QPoint(cx, cy - bodyWidth / 2) + << QPoint(cx, cy - headWidth / 2) + << QPoint(cx + dir * headLength, cy) + << QPoint(cx, cy + headWidth / 2) + << QPoint(cx, cy + bodyWidth / 2) + << QPoint(cx - dir * bodyLength, cy + bodyWidth / 2); + + p.setPen(arrowPen); + p.setBrush(arrowBrush); + p.drawPolygon(arrow); + }; + + auto drawCircle = [&](int cx, int cy, const QBrush &bgBrush) { + p.setPen(bgBorder); + p.setBrush(bgBrush); + p.drawEllipse(QPoint(cx, cy), circleRadius, circleRadius); + }; + + struct BlinkerSide { bool on; int dir; bool blocked; int cx; }; + const std::array sides = {{ + {leftBlinkerOn, -1, hazard ? true : (leftBlinkerOn && leftBlindspot), centerX - x_gap}, + {rightBlinkerOn, 1, hazard ? true : (rightBlinkerOn && rightBlindspot), centerX + x_gap}, + }}; + + for (const auto &s: sides) { + if (!s.on) continue; + + QColor bgColor = s.blocked ? QColor(135, 23, 23) : QColor(23, 134, 68); + QColor arrowColor = s.blocked ? QColor(66, 12, 12) : QColor(12, 67, 34); + if (pulseElement(blinkerFrameCounter)) arrowColor = Qt::white; + + const QBrush bgBrush(bgColor); + const QBrush arrowBrush(arrowColor); + + drawCircle(s.cx, y_offset, bgBrush); + drawArrow(s.cx, y_offset, s.dir, arrowBrush); + } + + p.restore(); } diff --git a/selfdrive/ui/sunnypilot/qt/onroad/hud.h b/selfdrive/ui/sunnypilot/qt/onroad/hud.h index cf840ee3d0..f021a949e4 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/hud.h +++ b/selfdrive/ui/sunnypilot/qt/onroad/hud.h @@ -36,7 +36,9 @@ private: void drawRoadName(QPainter &p, const QRect &surface_rect); void drawSpeedLimitPreActiveArrow(QPainter &p, QRect &sign_rect); void drawSetSpeedSP(QPainter &p, const QRect &surface_rect); - void drawE2eAlert(QPainter &p, const QRect &surface_rect); + void drawE2eAlert(QPainter &p, const QRect &surface_rect, const QString &alert_alt_text = ""); + void drawCurrentSpeedSP(QPainter &p, const QRect &surface_rect); + void drawBlinker(QPainter &p, const QRect &surface_rect); bool lead_status; float lead_d_rel; @@ -81,6 +83,7 @@ private: bool speedLimitValid; bool speedLimitLastValid; float speedLimitFinalLast; + cereal::LongitudinalPlanSP::SpeedLimit::Source speedLimitSource; bool speedLimitAheadValid; float speedLimitAhead; float speedLimitAheadDistance; @@ -94,16 +97,27 @@ private: int speedLimitAssistFrame; QPixmap plus_arrow_up_img; QPixmap minus_arrow_down_img; - int e2e_alert_small = 250; - int e2e_alert_large = 300; - QPixmap green_light_alert_small_img; - QPixmap green_light_alert_large_img; + int e2e_alert_size = 250; + QPixmap green_light_alert_img; bool greenLightAlert; int e2eAlertFrame; int e2eAlertDisplayTimer = 0; + bool allow_e2e_alerts; bool leadDepartAlert; - QPixmap lead_depart_alert_small_img; - QPixmap lead_depart_alert_large_img; + QPixmap lead_depart_alert_img; QString alert_text; QPixmap alert_img; + bool hideVEgoUI; + bool leftBlinkerOn; + bool rightBlinkerOn; + bool leftBlindspot; + bool rightBlindspot; + int blinkerFrameCounter; + int lastBlinkerStatus; + bool showTurnSignals; + + bool carControlEnabled; + float speedCluster = 0; + int icbm_active_counter = 0; + bool pcmCruiseSpeed = true; }; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/model.cc b/selfdrive/ui/sunnypilot/qt/onroad/model.cc index 5d92838f8a..590ade24a1 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/model.cc +++ b/selfdrive/ui/sunnypilot/qt/onroad/model.cc @@ -21,70 +21,234 @@ void ModelRendererSP::update_model(const cereal::ModelDataV2::Reader &model, con mapLineToPolygon(model.getLaneLines()[2], 0.2, -0.05, &right_blindspot_vertices, max_idx_barrier); } -void ModelRendererSP::drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, const QRect &surface_rect) { +void ModelRendererSP::draw(QPainter &painter, const QRect &surface_rect) { auto *s = uiState(); auto &sm = *(s->sm); - bool blindspot = Params().getBool("BlindSpot"); - if (blindspot) { - bool left_blindspot = sm["carState"].getCarState().getLeftBlindspot(); - bool right_blindspot = sm["carState"].getCarState().getRightBlindspot(); - - //painter.setBrush(QColor::fromRgbF(1.0, 0.0, 0.0, 0.4)); // Red with alpha for blind spot - - if (left_blindspot && !left_blindspot_vertices.isEmpty()) { - QLinearGradient gradient(0, 0, surface_rect.width(), 0); // Horizontal gradient from left to right - gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha - gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha - painter.setBrush(gradient); - painter.drawPolygon(left_blindspot_vertices); - } - - if (right_blindspot && !right_blindspot_vertices.isEmpty()) { - QLinearGradient gradient(surface_rect.width(), 0, 0, 0); // Horizontal gradient from right to left - gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha - gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha - painter.setBrush(gradient); - painter.drawPolygon(right_blindspot_vertices); - } + if (sm.rcv_frame("liveCalibration") < s->scene.started_frame || + sm.rcv_frame("modelV2") < s->scene.started_frame) { + return; } - bool rainbow = Params().getBool("RainbowMode"); - //float v_ego = sm["carState"].getCarState().getVEgo(); + clip_region = surface_rect.adjusted(-CLIP_MARGIN, -CLIP_MARGIN, CLIP_MARGIN, CLIP_MARGIN); + experimental_mode = sm["selfdriveState"].getSelfdriveState().getExperimentalMode(); + longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl(); + path_offset_z = sm["liveCalibration"].getLiveCalibration().getHeight()[0]; - if (rainbow) { - // Simple time-based animation - float time_offset = std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()).count() / 1000.0f; + painter.save(); - // simple linear gradient from bottom to top - QLinearGradient bg(0, surface_rect.height(), 0, 0); + const auto &model = sm["modelV2"].getModelV2(); + const auto &radar_state = sm["radarState"].getRadarState(); + const auto &lead_one = radar_state.getLeadOne(); + const auto &car_state = sm["carState"].getCarState(); - // evenly spaced colors across the spectrum - // The animation shifts the entire spectrum smoothly - float animation_speed = 40.0f; // speed vroom vroom - float hue_offset = fmod(time_offset * animation_speed, 360.0f); + update_model(model, lead_one); + drawLaneLines(painter); - // 6-8 color stops for smooth transitions more color makes it laggy - const int num_stops = 7; - for (int i = 0; i < num_stops; i++) { - float position = static_cast(i) / (num_stops - 1); - - float hue = fmod(hue_offset + position * 360.0f, 360.0f); - float saturation = 0.9f; - float lightness = 0.6f; - - // Alpha fades out towards the far end of the path - float alpha = 0.8f * (1.0f - position * 0.3f); - - QColor color = QColor::fromHslF(hue / 360.0f, saturation, lightness, alpha); - bg.setColorAt(position, color); - } - - painter.setBrush(bg); - painter.drawPolygon(track_vertices); + if (s->scene.rainbow_mode) { + drawRainbowPath(painter, surface_rect); } else { - // Normal path rendering ModelRenderer::drawPath(painter, model, surface_rect.height()); } + + if (longitudinal_control && sm.alive("radarState")) { + update_leads(radar_state, model.getPosition()); + const auto &lead_two = radar_state.getLeadTwo(); + if (lead_one.getStatus()) { + drawLead(painter, lead_one, lead_vertices[0], surface_rect); + } + if (lead_two.getStatus() && (std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0)) { + drawLead(painter, lead_two, lead_vertices[1], surface_rect); + } + } + + if (s->scene.blindspot_ui) { + const bool left_blindspot = car_state.getLeftBlindspot(); + const bool right_blindspot = car_state.getRightBlindspot(); + drawBlindspot(painter, surface_rect, left_blindspot, right_blindspot); + } + drawLeadStatus(painter, surface_rect.height(), surface_rect.width()); + + painter.restore(); +} + +void ModelRendererSP::drawBlindspot(QPainter &painter, const QRect &surface_rect, bool left_blindspot, bool right_blindspot) { + if (left_blindspot && !left_blindspot_vertices.isEmpty()) { + QLinearGradient gradient(0, 0, surface_rect.width(), 0); // Horizontal gradient from left to right + gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha + gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha + painter.setBrush(gradient); + painter.drawPolygon(left_blindspot_vertices); + } + + if (right_blindspot && !right_blindspot_vertices.isEmpty()) { + QLinearGradient gradient(surface_rect.width(), 0, 0, 0); // Horizontal gradient from right to left + gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha + gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha + painter.setBrush(gradient); + painter.drawPolygon(right_blindspot_vertices); + } +} + +void ModelRendererSP::drawLeadStatus(QPainter &painter, int height, int width) { + auto *s = uiState(); + auto &sm = *(s->sm); + + bool longitudinal_control = sm["carParams"].getCarParams().getOpenpilotLongitudinalControl(); + if (!longitudinal_control) { + lead_status_alpha = std::max(0.0f, lead_status_alpha - 0.05f); + return; + } + + if (!sm.alive("radarState")) { + lead_status_alpha = std::max(0.0f, lead_status_alpha - 0.05f); + return; + } + + const auto &radar_state = sm["radarState"].getRadarState(); + const auto &lead_one = radar_state.getLeadOne(); + const auto &lead_two = radar_state.getLeadTwo(); + + bool has_lead_one = lead_one.getStatus(); + bool has_lead_two = lead_two.getStatus(); + + if (!has_lead_one && !has_lead_two) { + lead_status_alpha = std::max(0.0f, lead_status_alpha - 0.05f); + if (lead_status_alpha <= 0.0f) return; + } else { + lead_status_alpha = std::min(1.0f, lead_status_alpha + 0.1f); + } + + if (has_lead_one) { + drawLeadStatusPosition(painter, lead_one, lead_vertices[0], height, width); + } + + if (has_lead_two && std::abs(lead_one.getDRel() - lead_two.getDRel()) > 3.0) { + drawLeadStatusPosition(painter, lead_two, lead_vertices[1], height, width); + } +} + +void ModelRendererSP::drawLeadStatusPosition(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, + const QPointF &chevron_pos, int height, int width) { + float d_rel = lead_data.getDRel(); + float v_rel = lead_data.getVRel(); + auto *s = uiState(); + auto &sm = *(s->sm); + float v_ego = sm["carState"].getCarState().getVEgo(); + + int chevron_data = s->scene.chevron_info; + float sz = std::clamp((25 * 30) / (d_rel / 3 + 30), 15.0f, 30.0f) * 2.35; + + QFont content_font = painter.font(); + content_font.setPixelSize(50); + content_font.setBold(true); + painter.setFont(content_font); + + bool is_metric = s->scene.is_metric; + QStringList text_lines; + const int chevron_all = 4; + QStringList chevron_text[3]; + + // Distance display + if (chevron_data == 1 || chevron_data == chevron_all) { + int pos = 0; + float val = std::max(0.0f, d_rel); + QString unit = is_metric ? "m" : "ft"; + if (!is_metric) val *= 3.28084f; + chevron_text[pos].append(QString::number(val, 'f', 0) + " " + unit); + } + + // Speed display + if (chevron_data == 2 || chevron_data == chevron_all) { + int pos = (chevron_data == 2) ? 0 : 1; + float multiplier = is_metric ? static_cast(MS_TO_KPH) : static_cast(MS_TO_MPH); + float val = std::max(0.0f, (v_rel + v_ego) * multiplier); + QString unit = is_metric ? "km/h" : "mph"; + chevron_text[pos].append(QString::number(val, 'f', 0) + " " + unit); + } + + // Time to contact + if (chevron_data == 3 || chevron_data == chevron_all) { + int pos = (chevron_data == 3) ? 0 : 2; + float val = (d_rel > 0 && v_ego > 0) ? std::max(0.0f, d_rel / v_ego) : 0.0f; + QString ttc = (val > 0 && val < 200) ? QString::number(val, 'f', 1) + "s" : "---"; + chevron_text[pos].append(ttc); + } + + for (int i = 0; i < 3; ++i) { + if (!chevron_text[i].isEmpty()) text_lines.append(chevron_text[i]); + } + + if (text_lines.isEmpty()) return; + + QFontMetrics fm(content_font); + float text_width = 120.0f; + for (const QString &line : text_lines) { + text_width = std::max(text_width, fm.horizontalAdvance(line) + 20.0f); + } + text_width = std::min(text_width, 250.0f); + + float line_height = 50.0f; + float total_height = text_lines.size() * line_height; + float margin = 20.0f; + + float text_y = chevron_pos.y() + sz + 15; + if (text_y + total_height > height - margin) { + float y_max = chevron_pos.y() > (height - margin) ? (height - margin) : chevron_pos.y(); + text_y = y_max - 15 - total_height; + text_y = std::max(margin, text_y); + } + + float text_x = chevron_pos.x() - text_width / 2; + text_x = std::clamp(text_x, margin, (float)width - text_width - margin); + + QPoint shadow_offset(2, 2); + QColor text_color = QColor(255, 255, 255, (int)(255 * lead_status_alpha)); + for (int i = 0; i < text_lines.size(); ++i) { + float y = text_y + (i * line_height); + if (y + line_height > height - margin) break; + + QRect rect(text_x, y, text_width, line_height); + + // Draw shadow + painter.setPen(QColor(0, 0, 0, (int)(200 * lead_status_alpha))); + painter.drawText(rect.translated(shadow_offset), Qt::AlignCenter, text_lines[i]); + painter.setPen(text_color); + painter.drawText(rect, Qt::AlignCenter, text_lines[i]); + } + + painter.setPen(Qt::NoPen); +} + +void ModelRendererSP::drawRainbowPath(QPainter &painter, const QRect &surface_rect) { + // Simple time-based animation + float time_offset = std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()).count() / 1000.0f; + + // simple linear gradient from bottom to top + QLinearGradient bg(0, surface_rect.height(), 0, 0); + + // evenly spaced colors across the spectrum + // The animation shifts the entire spectrum smoothly + float animation_speed = 40.0f; // speed vroom vroom + float hue_offset = fmod(time_offset * animation_speed, 360.0f); + + // 6-8 color stops for smooth transitions more color makes it laggy + const int num_stops = 7; + for (int i = 0; i < num_stops; i++) { + float position = static_cast(i) / (num_stops - 1); + + float hue = fmod(hue_offset + position * 360.0f, 360.0f); + float saturation = 0.9f; + float lightness = 0.6f; + + // Alpha fades out towards the far end of the path + float alpha = 0.8f * (1.0f - position * 0.3f); + + QColor color = QColor::fromHslF(hue / 360.0f, saturation, lightness, alpha); + bg.setColorAt(position, color); + } + + painter.setBrush(bg); + painter.drawPolygon(track_vertices); } diff --git a/selfdrive/ui/sunnypilot/qt/onroad/model.h b/selfdrive/ui/sunnypilot/qt/onroad/model.h index 24404f32f0..68068f2068 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/model.h +++ b/selfdrive/ui/sunnypilot/qt/onroad/model.h @@ -13,10 +13,19 @@ class ModelRendererSP : public ModelRenderer { public: ModelRendererSP() = default; + void draw(QPainter &painter, const QRect &surface_rect); + private: void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead) override; - void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, const QRect &rect) override; + void drawLeadStatus(QPainter &painter, int height, int width); + void drawLeadStatusPosition(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, + const QPointF &chevron_pos, int height, int width); + void drawBlindspot(QPainter &painter, const QRect &surface_rect, bool left_blindspot, bool right_blindspot); + void drawRainbowPath(QPainter &painter, const QRect &surface_rect); QPolygonF left_blindspot_vertices; QPolygonF right_blindspot_vertices; + + // Lead status animation + float lead_status_alpha = 0.0f; }; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc b/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc index 3f853e3363..b26d1b828a 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc +++ b/selfdrive/ui/sunnypilot/qt/onroad/onroad_home.cc @@ -25,10 +25,8 @@ void OnroadWindowSP::updateState(const UIStateSP &s) { void OnroadWindowSP::mousePressEvent(QMouseEvent *e) { OnroadWindow::mousePressEvent(e); - uiStateSP()->reset_onroad_sleep_timer(); } void OnroadWindowSP::offroadTransition(bool offroad) { OnroadWindow::offroadTransition(offroad); - uiStateSP()->reset_onroad_sleep_timer(); } diff --git a/selfdrive/ui/sunnypilot/qt/util.cc b/selfdrive/ui/sunnypilot/qt/util.cc index 2e066e88b5..eaa1f4bd12 100644 --- a/selfdrive/ui/sunnypilot/qt/util.cc +++ b/selfdrive/ui/sunnypilot/qt/util.cc @@ -95,13 +95,12 @@ QStringList searchFromList(const QString &query, const QStringList &list) { return list; } - QStringList search_terms = query.simplified().toLower().split(" ", QString::SkipEmptyParts); + QStringList search_terms = query.simplified().toLower().replace(QRegularExpression("[^a-zA-Z0-9\\s]"), " ").split(" ", QString::SkipEmptyParts); QStringList search_results; for (const QString &element : list) { if (std::all_of(search_terms.begin(), search_terms.end(), [&](const QString &term) { QString normalized_term = term.normalized(QString::NormalizationForm_KD).toLower(); - normalized_term.remove(QRegularExpression("[^a-zA-Z0-9\\s]")); QString normalized_element = element.normalized(QString::NormalizationForm_KD).toLower(); return normalized_element.contains(normalized_term, Qt::CaseInsensitive); })) { @@ -123,3 +122,7 @@ std::optional loadCerealEvent(Params& params, const std:: return std::nullopt; } } + +bool hasIntelligentCruiseButtonManagement(const cereal::CarParamsSP::Reader &car_params_sp) { + return car_params_sp.getIntelligentCruiseButtonManagementAvailable() && Params().getBool("IntelligentCruiseButtonManagement"); +} diff --git a/selfdrive/ui/sunnypilot/qt/util.h b/selfdrive/ui/sunnypilot/qt/util.h index 4b9d615ce5..60a73615ba 100644 --- a/selfdrive/ui/sunnypilot/qt/util.h +++ b/selfdrive/ui/sunnypilot/qt/util.h @@ -23,3 +23,4 @@ std::optional getParamIgnoringDefault(const std::string ¶m_name, co QMap loadPlatformList(); QStringList searchFromList(const QString &query, const QStringList &list); std::optional loadCerealEvent(Params& params, const std::string& _param); +bool hasIntelligentCruiseButtonManagement(const cereal::CarParamsSP::Reader &car_params_sp); diff --git a/selfdrive/ui/sunnypilot/qt/widgets/controls.h b/selfdrive/ui/sunnypilot/qt/widgets/controls.h index e9e1e4bb85..e111ce2fb5 100644 --- a/selfdrive/ui/sunnypilot/qt/widgets/controls.h +++ b/selfdrive/ui/sunnypilot/qt/widgets/controls.h @@ -545,10 +545,8 @@ public: main_layout->removeWidget(title_label); hlayout->addWidget(title_label, 1); } - if (spacingItem != nullptr && main_layout->indexOf(spacingItem) != -1) { - main_layout->removeItem(spacingItem); - spacingItem = nullptr; - } + main_layout->removeItem(spacingItem); + spacingItem = nullptr; } label.setStyleSheet(label_enabled_style); diff --git a/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.cc b/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.cc index b918938d11..b22684a295 100644 --- a/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.cc +++ b/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.cc @@ -14,10 +14,10 @@ ExpandableToggleRow::ExpandableToggleRow(const QString ¶m, const QString &ti QObject::connect(this, &ExpandableToggleRow::toggleFlipped, this, &ExpandableToggleRow::toggleClicked); collapsibleWidget = new QFrame(this); - collapsibleWidget->setContentsMargins(0, 0, 0, 0); collapsibleWidget->setVisible(false); QVBoxLayout *collapsible_layout = new QVBoxLayout(); collapsibleWidget->setLayout(collapsible_layout); + collapsible_layout->setContentsMargins(0, 0, 0, 0); list = new ListWidgetSP(this, false); diff --git a/selfdrive/ui/sunnypilot/ui.cc b/selfdrive/ui/sunnypilot/ui.cc index 7f4fc88235..df7b3ce5ca 100644 --- a/selfdrive/ui/sunnypilot/ui.cc +++ b/selfdrive/ui/sunnypilot/ui.cc @@ -29,7 +29,7 @@ UIStateSP::UIStateSP(QObject *parent) : UIState(parent) { "wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan", "modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP", "carControl", "gpsLocationExternal", "gpsLocation", "liveTorqueParameters", - "carStateSP", "liveParameters", "liveMapDataSP" + "carStateSP", "liveParameters", "liveMapDataSP", "carParamsSP" }); // update timer @@ -64,20 +64,29 @@ void ui_update_params_sp(UIStateSP *s) { s->scene.standstill_timer = params.getBool("StandstillTimer"); s->scene.speed_limit_mode = std::atoi(params.get("SpeedLimitMode").c_str()); s->scene.road_name = params.getBool("RoadNameToggle"); + s->scene.trueVEgoUI = params.getBool("TrueVEgoUI"); + s->scene.hideVEgoUI = params.getBool("HideVEgoUI"); // Onroad Screen Brightness s->scene.onroadScreenOffBrightness = std::atoi(params.get("OnroadScreenOffBrightness").c_str()); s->scene.onroadScreenOffControl = params.getBool("OnroadScreenOffControl"); s->scene.onroadScreenOffTimerParam = std::atoi(params.get("OnroadScreenOffTimer").c_str()); - s->reset_onroad_sleep_timer(); + + s->scene.turn_signals = params.getBool("ShowTurnSignals"); + s->scene.chevron_info = std::atoi(params.get("ChevronInfo").c_str()); + s->scene.blindspot_ui = params.getBool("BlindSpot"); + s->scene.rainbow_mode = params.getBool("RainbowMode"); } -void UIStateSP::reset_onroad_sleep_timer() { - if (scene.onroadScreenOffTimerParam >= 0 and scene.onroadScreenOffControl) { - scene.onroadScreenOffTimer = scene.onroadScreenOffTimerParam * UI_FREQ; - } else { +void UIStateSP::reset_onroad_sleep_timer(OnroadTimerStatusToggle toggleTimerStatus) { + // Toggling from active state to inactive + if (toggleTimerStatus == OnroadTimerStatusToggle::PAUSE and scene.onroadScreenOffTimer != -1) { scene.onroadScreenOffTimer = -1; } + // Toggling from a previously inactive state or resetting an active timer + else if ((scene.onroadScreenOffTimerParam >= 0 and scene.onroadScreenOffControl and scene.onroadScreenOffTimer != -1) or toggleTimerStatus == OnroadTimerStatusToggle::RESUME) { + scene.onroadScreenOffTimer = scene.onroadScreenOffTimerParam * UI_FREQ; + } } DeviceSP::DeviceSP(QObject *parent) : Device(parent) { diff --git a/selfdrive/ui/sunnypilot/ui.h b/selfdrive/ui/sunnypilot/ui.h index 55dd43ad52..ba5de83ef6 100644 --- a/selfdrive/ui/sunnypilot/ui.h +++ b/selfdrive/ui/sunnypilot/ui.h @@ -15,6 +15,12 @@ #include "selfdrive/ui/ui.h" #include "selfdrive/ui/qt/util.h" +enum OnroadTimerStatusToggle { + NONE, + PAUSE, + RESUME +}; + class UIStateSP : public UIState { Q_OBJECT @@ -61,7 +67,7 @@ public: return user.user_id.toLower() != "unregisteredsponsor" && user.user_id.toLower() != "temporarysponsor"; }); } - void reset_onroad_sleep_timer(); + void reset_onroad_sleep_timer(OnroadTimerStatusToggle toggleTimerStatus = OnroadTimerStatusToggle::NONE); signals: void sunnylinkRoleChanged(bool subscriber); diff --git a/selfdrive/ui/sunnypilot/ui_scene.h b/selfdrive/ui/sunnypilot/ui_scene.h index 7cfabb15c3..da98931e6b 100644 --- a/selfdrive/ui/sunnypilot/ui_scene.h +++ b/selfdrive/ui/sunnypilot/ui_scene.h @@ -15,4 +15,10 @@ typedef struct UISceneSP : UIScene { int onroadScreenOffBrightness, onroadScreenOffTimer = 0; bool onroadScreenOffControl; int onroadScreenOffTimerParam; + bool trueVEgoUI; + bool hideVEgoUI; + bool turn_signals = false; + int chevron_info; + bool blindspot_ui; + bool rainbow_mode; } UISceneSP; diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index ef7110e72e..4048daf74a 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -464,15 +472,6 @@ Steering lag calibration is complete. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot إعادة التشغيل @@ -517,10 +516,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -533,6 +528,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -594,6 +617,61 @@ This is the time after which settings UI closes automatically if user is not int تشغيل وضع الراحة + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + التحقق + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -649,6 +727,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX + + HudRendererSP + + km/h + كم/س + + + mph + ميل/س + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + MAX + + HyundaiSettings @@ -767,6 +902,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -790,6 +937,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1048,6 +1223,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1169,10 +1356,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. يتم تنزيل تحديث لنظام تشغيل جهازك في الخلفية. سيطلَب منك التحديث عندما يصبح جاهزاً للتثبيت. - - NVMe drive not mounted. - محرك NVMe غير مثبَّت. - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. @@ -1211,6 +1394,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1597,6 +1784,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1691,6 +1931,10 @@ Warning: You are on a metered connection! Developer المطور + + Display + + SetupWidget @@ -1927,6 +2171,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + السابق + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + السابق + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2309,6 +2631,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2319,6 +2695,10 @@ Warning: You are on a metered connection! Cancel إلغاء + + Favorites + + VisualsPanel @@ -2362,6 +2742,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index dde9241460..3d90dca182 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -464,15 +472,6 @@ Steering lag calibration is complete. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot Neustart @@ -517,10 +516,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -533,6 +528,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -594,6 +617,61 @@ This is the time after which settings UI closes automatically if user is not int ENTSPANNTER MODUS AN + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + ÜBERPRÜFEN + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -645,6 +723,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX + + HudRendererSP + + km/h + km/h + + + mph + mph + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + MAX + + HyundaiSettings @@ -759,6 +894,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -782,6 +929,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1040,6 +1215,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1157,10 +1344,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. Ein Update für das Betriebssystem deines Geräts wird im Hintergrund heruntergeladen. Du wirst aufgefordert, das Update zu installieren, sobald es bereit ist. - - NVMe drive not mounted. - NVMe-Laufwerk nicht gemounted. - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 Gerätetemperatur zu hoch. Das System kühlt ab, bevor es startet. Aktuelle interne Komponententemperatur: %1 @@ -1203,6 +1386,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1577,6 +1764,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1671,6 +1911,10 @@ Warning: You are on a metered connection! Developer Entwickler + + Display + + SetupWidget @@ -1909,6 +2153,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + Zurück + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + Zurück + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2291,6 +2613,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2301,6 +2677,10 @@ Warning: You are on a metered connection! Cancel Abbrechen + + Favorites + + VisualsPanel @@ -2344,6 +2724,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_es.ts b/selfdrive/ui/translations/main_es.ts index 3b53e7f944..284f63ebf3 100644 --- a/selfdrive/ui/translations/main_es.ts +++ b/selfdrive/ui/translations/main_es.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -468,15 +476,6 @@ La calibración del retraso de la dirección está completa. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot Reiniciar @@ -521,10 +520,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -537,6 +532,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -598,6 +621,61 @@ This is the time after which settings UI closes automatically if user is not int MODO CHILL + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + VERIFICAR + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -649,6 +727,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX + + HudRendererSP + + km/h + km/h + + + mph + mph + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + MAX + + HyundaiSettings @@ -763,6 +898,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -786,6 +933,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1044,6 +1219,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1165,10 +1352,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. Se está descargando una actualización del sistema operativo de su dispositivo en segundo plano. Se le pedirá que actualice cuando esté listo para instalarse. - - NVMe drive not mounted. - Unidad NVMe no montada. - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. @@ -1207,6 +1390,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1581,6 +1768,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1675,6 +1915,10 @@ Warning: You are on a metered connection! Developer Desarrollador + + Display + + SetupWidget @@ -1911,6 +2155,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2293,6 +2615,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2303,6 +2679,10 @@ Warning: You are on a metered connection! Cancel Cancelar + + Favorites + + VisualsPanel @@ -2346,6 +2726,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_fr.ts b/selfdrive/ui/translations/main_fr.ts index 45705defd9..c6c998b723 100644 --- a/selfdrive/ui/translations/main_fr.ts +++ b/selfdrive/ui/translations/main_fr.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -464,15 +472,6 @@ Steering lag calibration is complete. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot Redémarrer @@ -517,10 +516,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -533,6 +528,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -594,6 +617,61 @@ This is the time after which settings UI closes automatically if user is not int MODE DÉTENTE ACTIVÉ + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + VÉRIFIER + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -645,6 +723,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX + + HudRendererSP + + km/h + km/h + + + mph + mi/h + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + MAX + + HyundaiSettings @@ -759,6 +894,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -782,6 +929,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1040,6 +1215,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1161,10 +1348,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. Une mise à jour du système d'exploitation de votre appareil est en cours de téléchargement en arrière-plan. Vous serez invité à effectuer la mise à jour lorsqu'elle sera prête à être installée. - - NVMe drive not mounted. - Le disque NVMe n'est pas monté. - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. @@ -1203,6 +1386,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1577,6 +1764,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1671,6 +1911,10 @@ Warning: You are on a metered connection! Developer Dév. + + Display + + SetupWidget @@ -1907,6 +2151,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + Retour + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + Retour + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2289,6 +2611,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2299,6 +2675,10 @@ Warning: You are on a metered connection! Cancel Annuler + + Favorites + + VisualsPanel @@ -2342,6 +2722,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 3faa183954..b6a29a867c 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -468,15 +476,6 @@ Steering lag calibration is complete. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot 再起動 @@ -521,10 +520,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -537,6 +532,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -598,6 +621,61 @@ This is the time after which settings UI closes automatically if user is not int CHILLモード + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + 確認 + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -648,6 +726,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp 最大速度 + + HudRendererSP + + km/h + km/h + + + mph + mph + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + 最大速度 + + HyundaiSettings @@ -761,6 +896,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -784,6 +931,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1042,6 +1217,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1159,10 +1346,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. オペレーティングシステムがバックグラウンドでダウンロードされています。インストールの準備が整うと更新を促されます。 - - NVMe drive not mounted. - SSDドライブ(NVMe)がマウントされていません。 - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 デバイスの温度が高すぎるためシステム起動前の冷却中です。現在のデバイス内部温度: %1 @@ -1205,6 +1388,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1576,6 +1763,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1670,6 +1910,10 @@ Warning: You are on a metered connection! Developer 開発 + + Display + + SetupWidget @@ -1906,6 +2150,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + 戻る + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + 戻る + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2288,6 +2610,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2298,6 +2674,10 @@ Warning: You are on a metered connection! Cancel キャンセル + + Favorites + + VisualsPanel @@ -2341,6 +2721,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 756cad6045..164ce09f07 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -134,14 +134,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - 밝기 - - - Overrides the brightness of the device. - 기기 밝기를 직접 설정합니다. - Auto (Dark) 자동 (어둡게) @@ -150,6 +142,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto 자동 + + Global Brightness + 전역 밝기 + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + 기기의 밝기를 강제로 설정합니다. 이 설정은 주행 중 화면과 비주행 화면(설정 등) 모두에 적용됩니다. + ConfirmationDialog @@ -254,6 +254,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. 빠른 부팅 모드는 업데이트가 비활성화되어 있어야 합니다.<br>먼저 소프트웨어 패널에서 '업데이트 비활성화'를 활성화하세요. + + Enable Copyparty service + Copyparty 서비스 사용 + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + Copyparty는 매우 유능한 파일 서버로, 이를 통해 주행 기록을 다운로드하고, 로그 파일을 확인하며, 심지어 브라우저에서 일부 파일을 편집할 수도 있습니다. 이 기능을 사용하려면 comma 기기의 로컬 IP를 통해 접속해야 합니다. + DevicePanel @@ -472,16 +480,6 @@ Steering lag calibration is complete. Wake-Up Behavior 깨우기 동작 - - Interactivity Timeout - 상호작용 타임아웃 - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - 설정 화면에 사용자 지정 타임아웃을 적용하세요. -사용자가 화면과 상호작용하지 않으면 설정 화면이 자동으로 닫히는 시간입니다. - Reboot 재부팅 @@ -526,10 +524,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad 항상 오프로드 종료 - - Always Offroad - 항상 오프로드 - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. ⁍ 기본값: 기기가 정상적으로 부팅/절전 모드에서 해제되며, 작동 준비가 완료됩니다. @@ -542,6 +536,35 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. 부팅/절전 모드 후 기기의 상태를 제어합니다. + + Onroad Uploads + 주행 중 업로드 + + + Enable Always Offroad + 항상 오프로드 사용 + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + 주행 중 화면: 밝기 감소 + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + 운전이 시작된 후 기기 화면을 끄거나 밝기를 줄입니다. 화면을 터치하거나 시각적 알림이 표시되면 자동으로 다시 밝아집니다. + + + Interactivity Timeout + 상호작용 타임아웃 + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + 설정 UI에 사용자 지정 타임아웃을 적용하세요. +이는 사용자가 화면과 상호 작용하지 않으면 설정 UI가 자동으로 닫히는 시간입니다. + DriveStats @@ -603,6 +626,61 @@ This is the time after which settings UI closes automatically if user is not int 안정 모드 켜짐 + + ExternalStorageControl + + External Storage + 외부 저장소 + + + Extend your comma device's storage by inserting a USB drive into the aux port. + USB 드라이브를 AUX 포트에 삽입하여 comma 기기의 저장 공간을 확장합니다. + + + CHECK + 확인 + + + MOUNT + 마운트 + + + UNMOUNT + 마운트 해제 + + + FORMAT + 포맷 + + + Are you sure you want to format this drive? This will erase all data. + 이 드라이브를 포맷하시겠습니까? 이 작업은 모든 데이터를 지웁니다. + + + Format + 포맷 + + + formatting + 포맷 중 + + + insert drive + 드라이브 삽입 + + + needs format + 포맷 필요 + + + mounting + 마운트 중 + + + unmounting + 마운트 해제 중 + + FirehosePanel @@ -655,6 +733,64 @@ Firehose 모드를 사용하면 훈련 데이터 업로드를 극대화하여 op 최대 + + HudRendererSP + + km/h + km/h + + + mph + mph + + + GREEN +LIGHT + 녹색 신호 + + + LEAD VEHICLE +DEPARTING + 전방 차량이 +출발하였습니다 + + + SPEED + SPEED + + + LIMIT + LIMIT + + + Near + 근처 + + + km + km + + + m + m + + + mi + mi + + + ft + ft + + + AHEAD + 전방 + + + MAX + 최대 + + HyundaiSettings @@ -768,6 +904,18 @@ Firehose 모드를 사용하면 훈련 데이터 업로드를 극대화하여 op This platform supports limited MADS settings. 이 플랫폼은 제한된 MADS 설정을 지원합니다. + + Enforce Torque Lateral Control + 토크 조향 제어 강제 적용 + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + sunnypilot이 토크 조향 제어를 통해 조향하도록 강제하려면 이 기능을 활성화하세요. + + + Customize Params + 매개변수 사용자 지정 + LongitudinalPanel @@ -791,6 +939,34 @@ Firehose 모드를 사용하면 훈련 데이터 업로드를 극대화하여 op Start the vehicle to check vehicle compatibility. 차량 호환성을 확인하려면 차량 시동을 걸어주세요. + + Intelligent Cruise Button Management (ICBM) (Alpha) + 지능형 크루즈 버튼 관리 (ICBM) (알파) + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + 활성화하면, sunnypilot은 제한적인 가감속 제어를 위해 버튼 조작을 재현하여 내장 크루즈 컨트롤 버튼을 관리하려고 시도합니다. + + + Smart Cruise Control - Vision + 스마트 크루즈 컨트롤 - 비전 + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + 전방 커브 구간을 통과하기 위한 적절한 속도를 예측하기 위해 시각 경로 예측 기능을 사용합니다. + + + Smart Cruise Control - Map + 스마트 크루즈 컨트롤 - 지도 + + + Use map data to estimate the appropriate speed to drive through turns ahead. + 전방 커브 구간을 통과하기 위한 적절한 속도를 예측하기 위해 지도 데이터를 사용합니다. + + + Speed Limit + 속도 제한 + MadsSettings @@ -1020,35 +1196,47 @@ The default software delay value is 0.2 Refresh Model List - + 모델 목록 새로고침 REFRESH - 새로 고침 + 새로고침 Fetching Latest Models - + 최신 모델 불러오는 중 Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. - + 이 기능을 켜면 차량이 스스로 조향 응답 속도를 학습하고 맞춥니다. 끄면 고정된 조향 응답 속도를 사용합니다. 이 기능을 켜두는 것이 기본 openpilot 경험을 제공합니다. Live Steer Delay: - + 실시간 조향 지연 시간: Actuator Delay: - + 액츄에이터 지연 시간: Software Delay: - + 소프트웨어 지연 시간: Total Delay: - + 전체 지연 시간: + + + Use Lane Turn Desires + 차로 회전 의도 사용 + + + Adjust Lane Turn Speed + 차로 회전 속도 조정 + + + Set the maximum speed for lane turn desires. Default is 19 %1. + 차로 회전 의도의 최대 속도를 설정합니다. 기본값은 19 %1 입니다. @@ -1167,10 +1355,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. 기기 운영체제 업데이트가 백그라운드에서 다운로드 중입니다. 설치가 준비되면 업데이트를 진행하라는 메시지가 표시됩니다. - - NVMe drive not mounted. - NVMe 드라이브가 마운트되지 않았습니다. - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 기기 온도가 너무 높습니다. 시스템이 시작하기 전에 온도를 낮추고 있습니다. 현재 내부 부품 온도는 %1입니다. @@ -1215,6 +1399,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + <b>지원되지 않는 브랜치 감지</b> - 현재 사용 중인 <b><u>%1</u></b> 브랜치는 comma three 기기에서 더 이상 지원되지 않습니다. <b>[기기 > 소프트웨어]</b>로 이동하여 브랜치 이름에 <b><u>-tici</u></b> 가 포함된 comma three용 브랜치로 설치하세요. + OffroadHome @@ -1684,6 +1872,10 @@ Warning: You are on a metered connection! Developer 개발자 + + Display + 화면 + SetupWidget @@ -1920,6 +2112,140 @@ Warning: You are on a metered connection! 이 설정들을 변경하려면 항상 오프로드 모드를 활성화하거나 차량 시동을 꺼야 합니다. + + SpeedLimitPolicy + + Back + 뒤로 + + + Speed Limit Source + 속도 제한 출처 + + + ⦿ Car Only: Use Speed Limit data only from Car + ⦿ 차량만: 차량에서 제공되는 속도 제한 데이터만 사용 + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + ⦿ 지도만: OpenStreetMaps에서 제공되는 속도 제한 데이터만 사용 + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + ⦿ 차량 우선: 사용 가능한 경우 차량의 속도 제한 데이터를 사용하고, 그렇지 않은 경우 OpenStreetMaps의 데이터 사용 + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + ⦿ 지도 우선: 사용 가능한 경우 OpenStreetMaps의 속도 제한 데이터를 사용하고, 그렇지 않은 경우 차량의 데이터 사용 + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + ⦿ 결합: 차량 및 OpenStreetMaps의 속도 제한 결합 데이터 사용 + + + Car +Only + 차량만 + + + Map +Only + 지도만 + + + Car +First + 차량 +우선 + + + Map +First + 지도 +우선 + + + Combined +Data + 결합 +데이터 + + + + SpeedLimitSettings + + Back + 뒤로 + + + Speed Limit + 속도 제한 + + + Customize Source + 출처 사용자 지정 + + + Speed Limit Offset + 속도 제한 오프셋 + + + ⦿ None: No Offset + ⦿ 없음: 오프셋 없음 + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + ⦿ 고정: 고정 오프셋을 추가합니다. [제한 속도 + 오프셋] + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + ⦿ 비율: 백분율 오프셋을 추가합니다. [제한 속도 + (오프셋 % 제한 속도)] + + + ⦿ Off: Disables the Speed Limit functions. + ⦿ 끄기: 속도 제한 기능을 비활성화합니다. + + + ⦿ Information: Displays the current road's speed limit. + ⦿ 정보: 현재 도로의 제한 속도를 표시합니다. + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + ⦿ 경고: 현재 도로의 제한 속도를 초과할 경우 경고합니다. + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + ⦿ 보조: +/- 버튼을 조작할 때 현재 도로의 제한 속도를 기준으로 차량의 크루즈 속도를 조정합니다. + + + None + 없음 + + + Fixed + 고정 + + + Percent + 비율 + + + Off + 끄기 + + + Information + 정보 + + + Warning + 경고 + + + Assist + 보조 + + SshControl @@ -2090,27 +2416,27 @@ Warning: You are on a metered connection! Enable sunnylink uploader to allow sunnypilot to upload your driving data to sunnypilot servers. (only for highest tiers, and does NOT bring ANY benefit to you. We are just testing data volume.) - + sunnylink 업로더를 활성화하여 sunnypilot이 귀하의 주행 데이터를 sunnypilot 서버로 업로드하도록 허용합니다. (가장 높은 등급에서만 해당하며, 사용자에게는 어떠한 이점도 제공하지 않습니다. 저희는 그냥 데이터 용량을 테스트하는 중입니다.) [Don't use] Enable sunnylink uploader - + [사용하지 마세요] sunnylink 업로더 사용 🚀 sunnylink 🚀 - + 🚀 sunnylink 🚀 For secure backup, restore, and remote configuration - + 안전한 백업, 복원 및 원격 설정을 위해 Sponsorship isn't required for basic backup/restore - + 기본적인 백업/복원은 후원이 필요하지 않습니다 Click the sponsor button for more details - + 후원 버튼을 눌러 더 자세한 정보를 확인하세요 @@ -2302,6 +2628,60 @@ Warning: You are on a metered connection! 실험 모드를 활성화하려면 sunnypilot 가감속 제어(알파) 토글을 켜세요. + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + 실시간 수동 튜닝 + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + 토크 조향 제어기가 셀프 튜닝에서 학습된 값 대신 고정된 값을 사용하도록 강제합니다. 이 토글을 활성화하면 셀프 튜닝 값이 무시됩니다. + + + Lateral Acceleration Factor + 조향 가속 계수 + + + Friction + 마찰 + + + Real-time and Offline + 실시간 및 오프라인 + + + Offline Only + 오프라인만 + + + + TorqueLateralControlSettings + + Self-Tune + 셀프 튜닝 + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + 기본적으로 토크 조향 제어를 사용하지 않는 플랫폼에 대해 토크 조향 제어의 셀프 튜닝 기능을 활성화합니다. + + + Less Restrict Settings for Self-Tune (Beta) + 셀프 튜닝 제한 완화 설정 (베타) + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + 셀프 튜닝 사용 시 덜 엄격한 설정을 사용합니다. 이는 학습 값에 대해 torqued가 더 관대하도록 허용합니다. + + + Enable Custom Tuning + 사용자 지정 튜닝 사용 + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + 토크 조향 제어에 대한 사용자 지정 튜닝을 활성화합니다. 아래에서 조향 가속 계수 및 마찰을 수정하면 "opendbc/car/torque_data" 내의 YAML 파일에 명시된 오프라인 값이 무시됩니다. 이 값들은 "실시간 수동 튜닝" 토글이 활성화되면 실시간으로도 사용됩니다. + + TreeOptionDialog @@ -2312,6 +2692,10 @@ Warning: You are on a metered connection! Cancel 취소 + + Favorites + 즐겨찾기 + VisualsPanel @@ -2355,6 +2739,92 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). 앞차를 추적하는 역삼각형 아래에 유용한 측정 지표를 표시합니다. (openpilot 가감속 제어 기능이 있는 차량에만 해당됩니다) + + Enable Tesla Rainbow Mode + 테슬라 무지개 모드 사용 + + + A beautiful rainbow effect on the path the model wants to take. + 모델이 가고자 하는 경로에 아름다운 무지개 효과를 추가합니다. + + + It + 이는 운전에 + + + does not + 어떠한 + + + affect driving in any way. + 영향도 미치지 않습니다. + + + Enable Standstill Timer + 정차 타이머 사용 + + + Show a timer on the HUD when the car is at a standstill. + 차량이 정차 상태일 때 HUD에 타이머를 표시합니다. + + + Display Road Name + 도로 이름 표시 + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + 차량이 주행 중인 도로의 이름을 표시합니다. 도로 이름을 가져오려면 OSM 패널에서 해당 위치의 OpenStreetMap 데이터베이스를 다운로드해야 합니다. + + + Green Traffic Light Alert (Beta) + 녹색 신호 감지 알림 (베타) + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + 앞 신호등이 초록 신호로 바뀌고 전방에 차량이 없을 때, 알림음과 화면 경고가 표시됩니다. + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + 참고: 이 알림음은 단순한 알림 목적으로만 설계되었습니다. 주변 환경을 살피고 그에 따라 결정하는 것은 운전자의 책임입니다. + + + Lead Departure Alert (Beta) + 전방 차량 출발 알림 (베타) + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + 당신이 정차 중이고 전방 차량이 움직이기 시작할 때, 알림음과 화면 경고가 표시됩니다. + + + Speedometer: Always Display True Speed + 속도계: 항상 실제 속도 표시 + + + Always display the true vehicle current speed from wheel speed sensors. + 항상 휠 스피드 센서에서 얻은 실제 차량 속도를 표시합니다. + + + Speedometer: Hide from Onroad Screen + 속도계: 주행 화면에서 숨기기 + + + Right + 오른쪽 + + + Right && +Bottom + 오른쪽 && +아래 + + + Developer UI + 개발자 UI + + + Display real-time parameters and metrics from various sources. + 다양한 출처의 실시간 매개변수 및 측정 지표를 표시합니다. + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 0a886d435c..e820f472af 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -468,15 +476,6 @@ A calibração do atraso da direção foi concluída. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot Reiniciar @@ -521,10 +520,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -537,6 +532,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -598,6 +621,61 @@ This is the time after which settings UI closes automatically if user is not int MODO CHILL ON + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + VERIFICAR + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -649,6 +727,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp LIMITE + + HudRendererSP + + km/h + km/h + + + mph + mph + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + LIMITE + + HyundaiSettings @@ -763,6 +898,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -786,6 +933,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1044,6 +1219,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1161,10 +1348,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. Uma atualização para o sistema operacional do seu dispositivo está sendo baixada em segundo plano. Você será solicitado a atualizar quando estiver pronto para instalar. - - NVMe drive not mounted. - Unidade NVMe não montada. - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 Temperatura do dispositivo muito alta. O sistema está sendo resfriado antes de iniciar. A temperatura atual do componente interno é: %1 @@ -1207,6 +1390,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1581,6 +1768,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1675,6 +1915,10 @@ Warning: You are on a metered connection! Developer Desenvdor + + Display + + SetupWidget @@ -1911,6 +2155,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + Voltar + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + Voltar + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2293,6 +2615,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2303,6 +2679,10 @@ Warning: You are on a metered connection! Cancel Cancelar + + Favorites + + VisualsPanel @@ -2346,6 +2726,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index 7b89f2a694..67a5a5eaeb 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -464,15 +472,6 @@ Steering lag calibration is complete. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot รีบูต @@ -517,10 +516,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -533,6 +528,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -594,6 +617,61 @@ This is the time after which settings UI closes automatically if user is not int คุณกำลังใช้โหมดชิล + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + ตรวจสอบ + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -644,6 +722,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp สูงสุด + + HudRendererSP + + km/h + กม./ชม. + + + mph + ไมล์/ชม. + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + สูงสุด + + HyundaiSettings @@ -757,6 +892,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -780,6 +927,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1038,6 +1213,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1159,10 +1346,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. กำลังดาวน์โหลดอัปเดทสำหรับระบบปฏิบัติการอยู่เบื้องหลัง คุณจะได้รับการแจ้งเตือนเมื่อระบบพร้อมสำหรับการติดตั้ง - - NVMe drive not mounted. - ไม่ได้ติดตั้งไดร์ฟ NVMe - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. @@ -1201,6 +1384,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1572,6 +1759,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1666,6 +1906,10 @@ Warning: You are on a metered connection! Developer นักพัฒนา + + Display + + SetupWidget @@ -1902,6 +2146,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + ย้อนกลับ + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + ย้อนกลับ + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2284,6 +2606,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2294,6 +2670,10 @@ Warning: You are on a metered connection! Cancel ยกเลิก + + Favorites + + VisualsPanel @@ -2337,6 +2717,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_tr.ts b/selfdrive/ui/translations/main_tr.ts index 0598d08364..923ab69139 100644 --- a/selfdrive/ui/translations/main_tr.ts +++ b/selfdrive/ui/translations/main_tr.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -464,15 +472,6 @@ Steering lag calibration is complete. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot Yeniden başlat @@ -517,10 +516,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -533,6 +528,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -594,6 +617,61 @@ This is the time after which settings UI closes automatically if user is not int + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + KONTROL ET + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -644,6 +722,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX + + HudRendererSP + + km/h + km/h + + + mph + mph + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + MAX + + HyundaiSettings @@ -757,6 +892,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -780,6 +927,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1038,6 +1213,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1158,10 +1345,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - - NVMe drive not mounted. - - Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. @@ -1200,6 +1383,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1571,6 +1758,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1665,6 +1905,10 @@ Warning: You are on a metered connection! Developer + + Display + + SetupWidget @@ -1901,6 +2145,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2283,6 +2605,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2293,6 +2669,10 @@ Warning: You are on a metered connection! Cancel + + Favorites + + VisualsPanel @@ -2336,6 +2716,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 1f4db2d6d0..3be9377503 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -468,15 +476,6 @@ Steering lag calibration is complete. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot 重启 @@ -521,10 +520,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -537,6 +532,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -598,6 +621,61 @@ This is the time after which settings UI closes automatically if user is not int 轻松模式运行 + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + 查看 + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -648,6 +726,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp 最高定速 + + HudRendererSP + + km/h + km/h + + + mph + mph + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + 最高定速 + + HyundaiSettings @@ -761,6 +896,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -784,6 +931,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1042,6 +1217,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1159,10 +1346,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. 一个针对您设备的操作系统更新正在后台下载中。当更新准备好安装时,您将收到提示进行更新。 - - NVMe drive not mounted. - NVMe固态硬盘未被挂载。 - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 设备温度过高。系统正在冷却中,等冷却完毕后才会启动。目前内部组件温度:%1 @@ -1205,6 +1388,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1576,6 +1763,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1670,6 +1910,10 @@ Warning: You are on a metered connection! Developer 开发人员 + + Display + + SetupWidget @@ -1906,6 +2150,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + 返回 + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + 返回 + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2288,6 +2610,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2298,6 +2674,10 @@ Warning: You are on a metered connection! Cancel 取消 + + Favorites + + VisualsPanel @@ -2341,6 +2721,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 1a8784846c..fac29bed62 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -133,14 +133,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Brightness - - Brightness - - - - Overrides the brightness of the device. - - Auto (Dark) @@ -149,6 +141,14 @@ Please use caution when using this feature. Only use the blinker when traffic an Auto + + Global Brightness + + + + Overrides the brightness of the device. This applies to both onroad and offroad screens. + + ConfirmationDialog @@ -250,6 +250,14 @@ This only toggles the visibility of the controls; it does not toggle the actual Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + + Enable Copyparty service + + + + Copyparty is a very capable file server, you can use it to download your routes, view your logs and even make some edits on some files from your browser. Requires you to connect to your comma locally via it's IP. + + DevicePanel @@ -468,15 +476,6 @@ Steering lag calibration is complete. Wake-Up Behavior - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - Reboot 重新啟動 @@ -521,10 +520,6 @@ This is the time after which settings UI closes automatically if user is not int Exit Always Offroad - - Always Offroad - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. @@ -537,6 +532,34 @@ This is the time after which settings UI closes automatically if user is not int Controls state of the device after boot/sleep. + + Onroad Uploads + + + + Enable Always Offroad + + + + + DisplayPanel + + Onroad Screen: Reduced Brightness + + + + Turn off device screen or reduce brightness after driving starts. It automatically brightens again when screen is touched or a visible alert is displayed. + + + + Interactivity Timeout + + + + Apply a custom timeout for settings UI. +This is the time after which settings UI closes automatically if user is not interacting with the screen. + + DriveStats @@ -598,6 +621,61 @@ This is the time after which settings UI closes automatically if user is not int 輕鬆模式 ON + + ExternalStorageControl + + External Storage + + + + Extend your comma device's storage by inserting a USB drive into the aux port. + + + + CHECK + 檢查 + + + MOUNT + + + + UNMOUNT + + + + FORMAT + + + + Are you sure you want to format this drive? This will erase all data. + + + + Format + + + + formatting + + + + insert drive + + + + needs format + + + + mounting + + + + unmounting + + + FirehosePanel @@ -648,6 +726,63 @@ Firehose Mode allows you to maximize your training data uploads to improve openp 最高 + + HudRendererSP + + km/h + km/h + + + mph + mph + + + GREEN +LIGHT + + + + LEAD VEHICLE +DEPARTING + + + + SPEED + + + + LIMIT + + + + Near + + + + km + + + + m + + + + mi + + + + ft + + + + AHEAD + + + + MAX + 最高 + + HyundaiSettings @@ -761,6 +896,18 @@ Firehose Mode allows you to maximize your training data uploads to improve openp This platform supports limited MADS settings. + + Enforce Torque Lateral Control + + + + Enable this to enforce sunnypilot to steer with Torque lateral control. + + + + Customize Params + + LongitudinalPanel @@ -784,6 +931,34 @@ Firehose Mode allows you to maximize your training data uploads to improve openp Start the vehicle to check vehicle compatibility. + + Intelligent Cruise Button Management (ICBM) (Alpha) + + + + When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control. + + + + Smart Cruise Control - Vision + + + + Use vision path predictions to estimate the appropriate speed to drive through turns ahead. + + + + Smart Cruise Control - Map + + + + Use map data to estimate the appropriate speed to drive through turns ahead. + + + + Speed Limit + + MadsSettings @@ -1042,6 +1217,18 @@ The default software delay value is 0.2 Total Delay: + + Use Lane Turn Desires + + + + Adjust Lane Turn Speed + + + + Set the maximum speed for lane turn desires. Default is 19 %1. + + MultiOptionDialog @@ -1159,10 +1346,6 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. 一個有關操作系統的更新正在後台下載中。當更新準備好安裝時,您將收到提示進行更新。 - - NVMe drive not mounted. - NVMe 固態硬碟未被掛載。 - Device temperature too high. System cooling down before starting. Current internal component temperature: %1 裝置溫度過高。系統正在冷卻中,等冷卻完畢後才會啟動。目前內部組件溫度:%1 @@ -1205,6 +1388,10 @@ The default software delay value is 0.2 %1 + + <b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three. + + OffroadHome @@ -1576,6 +1763,59 @@ Warning: You are on a metered connection! sunnypilot + + None + + + + Fixed + + + + Percent + + + + Car +Only + + + + Map +Only + + + + Car +First + + + + Map +First + + + + Combined +Data + + + + Off + + + + Information + + + + Warning + + + + Assist + + SettingsWindow @@ -1670,6 +1910,10 @@ Warning: You are on a metered connection! Developer 開發人員 + + Display + + SetupWidget @@ -1906,6 +2150,84 @@ Warning: You are on a metered connection! + + SpeedLimitPolicy + + Back + 回上頁 + + + Speed Limit Source + + + + ⦿ Car Only: Use Speed Limit data only from Car + + + + ⦿ Map Only: Use Speed Limit data only from OpenStreetMaps + + + + ⦿ Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps + + + + ⦿ Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car + + + + ⦿ Combined: Use combined Speed Limit data from Car & OpenStreetMaps + + + + + SpeedLimitSettings + + Back + 回上頁 + + + Speed Limit + + + + Customize Source + + + + Speed Limit Offset + + + + ⦿ None: No Offset + + + + ⦿ Fixed: Adds a fixed offset [Speed Limit + Offset] + + + + ⦿ Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)] + + + + ⦿ Off: Disables the Speed Limit functions. + + + + ⦿ Information: Displays the current road's speed limit. + + + + ⦿ Warning: Provides a warning when exceeding the current road's speed limit. + + + + ⦿ Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons. + + + SshControl @@ -2288,6 +2610,60 @@ Warning: You are on a metered connection! + + TorqueLateralControlCustomParams + + Manual Real-Time Tuning + + + + Enforces the torque lateral controller to use the fixed values instead of the learned values from Self-Tune. Enabling this toggle overrides Self-Tune values. + + + + Lateral Acceleration Factor + + + + Friction + + + + Real-time and Offline + + + + Offline Only + + + + + TorqueLateralControlSettings + + Self-Tune + + + + Enables self-tune for Torque lateral control for platforms that do not use Torque lateral control by default. + + + + Less Restrict Settings for Self-Tune (Beta) + + + + Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values. + + + + Enable Custom Tuning + + + + Enables custom tuning for Torque lateral control. Modifying Lateral Acceleration Factor and Friction below will override the offline values indicated in the YAML files within "opendbc/car/torque_data". The values will also be used live when "Manual Real-Time Tuning" toggle is enabled. + + + TreeOptionDialog @@ -2298,6 +2674,10 @@ Warning: You are on a metered connection! Cancel 取消 + + Favorites + + VisualsPanel @@ -2341,6 +2721,91 @@ Warning: You are on a metered connection! Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). + + Enable Tesla Rainbow Mode + + + + A beautiful rainbow effect on the path the model wants to take. + + + + It + + + + does not + + + + affect driving in any way. + + + + Enable Standstill Timer + + + + Show a timer on the HUD when the car is at a standstill. + + + + Display Road Name + + + + Displays the name of the road the car is traveling on. The OpenStreetMap database of the location must be downloaded from the OSM panel to fetch the road name. + + + + Green Traffic Light Alert (Beta) + + + + A chime and on-screen alert will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. + + + + Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly. + + + + Lead Departure Alert (Beta) + + + + A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving. + + + + Speedometer: Always Display True Speed + + + + Always display the true vehicle current speed from wheel speed sensors. + + + + Speedometer: Hide from Onroad Screen + + + + Right + + + + Right && +Bottom + + + + Developer UI + + + + Display real-time parameters and metrics from various sources. + + WiFiPromptWidget diff --git a/sunnypilot/__init__.py b/sunnypilot/__init__.py index ab5441aa71..ccacd0be0a 100644 --- a/sunnypilot/__init__.py +++ b/sunnypilot/__init__.py @@ -4,4 +4,36 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. This file is part of sunnypilot and is licensed under the MIT License. See the LICENSE.md file in the root directory for more details. """ + +from enum import IntEnum +import hashlib + PARAMS_UPDATE_PERIOD = 3 # seconds + + +def get_file_hash(path: str) -> str: + sha256_hash = hashlib.sha256() + with open(path, "rb") as f: + for byte_block in iter(lambda: f.read(4096), b""): + sha256_hash.update(byte_block) + return sha256_hash.hexdigest() + + +class IntEnumBase(IntEnum): + @classmethod + def min(cls): + return min(cls) + + @classmethod + def max(cls): + return max(cls) + + +def get_sanitize_int_param(key: str, min_val: int, max_val: int, params) -> int: + val: int = params.get(key, return_default=True) + clipped_val = max(min_val, min(max_val, val)) + + if clipped_val != val: + params.put(key, clipped_val) + + return clipped_val diff --git a/sunnypilot/mads/mads.py b/sunnypilot/mads/mads.py index 21e7f7d3e7..7eab55e6ea 100644 --- a/sunnypilot/mads/mads.py +++ b/sunnypilot/mads/mads.py @@ -61,6 +61,7 @@ class ModularAssistiveDrivingSystem: self.unified_engagement_mode = self.params.get_bool("MadsUnifiedEngagementMode") def pedal_pressed_non_gas_pressed(self, CS: structs.CarState) -> bool: + # ignore `pedalPressed` events caused by gas presses if self.events.has(EventName.pedalPressed) and not (CS.gasPressed and not self.selfdrive.CS_prev.gasPressed and self.disengage_on_accelerator): return True diff --git a/sunnypilot/mapd/live_map_data/base_map_data.py b/sunnypilot/mapd/live_map_data/base_map_data.py index 25925937f5..723864dd2a 100644 --- a/sunnypilot/mapd/live_map_data/base_map_data.py +++ b/sunnypilot/mapd/live_map_data/base_map_data.py @@ -8,8 +8,12 @@ from abc import abstractmethod, ABC import cereal.messaging as messaging from openpilot.common.params import Params +from openpilot.common.constants import CV +from openpilot.selfdrive.car.cruise import V_CRUISE_UNSET from openpilot.sunnypilot.navd.helpers import coordinate_from_param +MAX_SPEED_LIMIT = V_CRUISE_UNSET * CV.KPH_TO_MS + class BaseMapData(ABC): def __init__(self): @@ -46,9 +50,9 @@ class BaseMapData(ABC): mapd_sp_send.valid = self.sm['liveLocationKalman'].gpsOK live_map_data = mapd_sp_send.liveMapDataSP - live_map_data.speedLimitValid = bool(speed_limit > 0) + live_map_data.speedLimitValid = bool(MAX_SPEED_LIMIT > speed_limit > 0) live_map_data.speedLimit = speed_limit - live_map_data.speedLimitAheadValid = bool(next_speed_limit > 0) + live_map_data.speedLimitAheadValid = bool(MAX_SPEED_LIMIT > next_speed_limit > 0) live_map_data.speedLimitAhead = next_speed_limit live_map_data.speedLimitAheadDistance = next_speed_limit_distance live_map_data.roadName = self.get_current_road_name() diff --git a/sunnypilot/mapd/mapd_installer.py b/sunnypilot/mapd/mapd_installer.py index e49ff8c64e..08d17376d6 100755 --- a/sunnypilot/mapd/mapd_installer.py +++ b/sunnypilot/mapd/mapd_installer.py @@ -22,7 +22,7 @@ from openpilot.system.version import is_prebuilt from openpilot.sunnypilot.mapd import MAPD_PATH, MAPD_BIN_DIR import openpilot.system.sentry as sentry -VERSION = 'v1.11.0' +VERSION = "v1.12.0" URL = f"https://github.com/pfeiferj/openpilot-mapd/releases/download/{VERSION}/mapd" diff --git a/sunnypilot/mapd/tests/__init__.py b/sunnypilot/mapd/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sunnypilot/mapd/tests/mapd_hash b/sunnypilot/mapd/tests/mapd_hash new file mode 100644 index 0000000000..0322ea97ca --- /dev/null +++ b/sunnypilot/mapd/tests/mapd_hash @@ -0,0 +1 @@ +fdb3b49ee19956e6ce09fdc3373cbba557f1263b2180e9f344c1d4053852284b \ No newline at end of file diff --git a/sunnypilot/mapd/tests/test_mapd_version.py b/sunnypilot/mapd/tests/test_mapd_version.py new file mode 100644 index 0000000000..5619d2ec29 --- /dev/null +++ b/sunnypilot/mapd/tests/test_mapd_version.py @@ -0,0 +1,19 @@ +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" +from openpilot.sunnypilot import get_file_hash +from openpilot.sunnypilot.mapd import MAPD_PATH +from openpilot.sunnypilot.mapd.update_version import MAPD_HASH_PATH + + +class TestMapdVersion: + def test_compare_versions(self): + mapd_hash = get_file_hash(MAPD_PATH) + + with open(MAPD_HASH_PATH) as f: + current_hash = f.read().strip() + + assert current_hash == mapd_hash, "Run sunnypilot/mapd/update_version.py to update the current mapd version and hash" diff --git a/sunnypilot/mapd/update_version.py b/sunnypilot/mapd/update_version.py new file mode 100755 index 0000000000..c5e08b3f8f --- /dev/null +++ b/sunnypilot/mapd/update_version.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" +import argparse +import os +import re + +from openpilot.sunnypilot import get_file_hash +from openpilot.common.basedir import BASEDIR +from openpilot.sunnypilot.mapd import MAPD_PATH + +MAPD_HASH_PATH = os.path.join(BASEDIR, "sunnypilot", "mapd", "tests", "mapd_hash") +MAPD_VERSION_PATH = os.path.join(BASEDIR, "sunnypilot", "mapd", "mapd_installer.py") + + +def update_mapd_hash(): + mapd_hash = get_file_hash(MAPD_PATH) + + with open(MAPD_HASH_PATH, "w") as f: + f.write(mapd_hash) + + print(f"Generated and updated new mapd hash to {MAPD_HASH_PATH}") + + +def get_current_mapd_version(path: str) -> str: + print("[GET CURRENT MAPD VERSION]") + with open(path) as f: + for line in f: + if line.strip().startswith("VERSION"): + # Match VERSION = 'v1.11.0' or VERSION="v1.11.0" (with optional spaces) + match = re.search(r'VERSION\s*=\s*[\'"]([^\'"]+)[\'"]', line) + if match: + ver = match.group(1) + print(f'Current mapd version: "{ver}"') + return ver + else: + print("[ERROR] VERSION line found but no quoted value detected.") + return "" + print("[ERROR] VERSION not found in file!") + return "" + + +def update_mapd_version(ver: str, path: str): + print("[CHANGE CURRENT MAPD VERSION]") + + with open(path) as f: + lines = f.readlines() + + found = False + new_lines = [] + for line in lines: + if not found and line.startswith("VERSION ="): + new_lines.append(f'VERSION = "{ver}"\n') + found = True + new_lines.extend(lines[lines.index(line) + 1:]) + break + else: + new_lines.append(line) + + if not found: + print("[ERROR] VERSION line not found! Aborting without writing.") + return + + with open(path, "w") as f: + f.writelines(new_lines) + + print(f'New mapd version: "{ver}"') + print("[DONE]") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Update mapd version and hash") + parser.add_argument("--new_ver", type=str, help="New mapd version") + args = parser.parse_args() + + if not args.new_ver: + print("Warning: No new mapd version provided. Use --new_ver to specify") + print("Example:") + print(" python sunnypilot/mapd/update_version.py --new_ver \"v1.12.0\"") + print("Current mapd version and hash will not be updated! (aborted)") + exit(0) + + current_ver = get_current_mapd_version(MAPD_VERSION_PATH) + new_ver = f"{args.new_ver}" + if current_ver == new_ver: + print(f'Proposed mapd version: "{new_ver}"') + confirm = input("Proposed mapd version is the same as the current mapd version. Confirm? (y/n): ").upper().strip() + if confirm != "Y": + print("Current mapd version and hash will not be updated! (aborted)") + exit(0) + + update_mapd_version(new_ver, MAPD_VERSION_PATH) + update_mapd_hash() diff --git a/sunnypilot/mapd/version.py b/sunnypilot/mapd/version.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sunnypilot/models/default_model.py b/sunnypilot/models/default_model.py index 718c910c5c..0260a3c3bc 100755 --- a/sunnypilot/models/default_model.py +++ b/sunnypilot/models/default_model.py @@ -3,6 +3,7 @@ import os import hashlib from openpilot.common.basedir import BASEDIR +from openpilot.sunnypilot import get_file_hash DEFAULT_MODEL_NAME_PATH = os.path.join(BASEDIR, "common", "model.h") MODEL_HASH_PATH = os.path.join(BASEDIR, "sunnypilot", "models", "tests", "model_hash") @@ -10,14 +11,6 @@ VISION_ONNX_PATH = os.path.join(BASEDIR, "selfdrive", "modeld", "models", "drivi POLICY_ONNX_PATH = os.path.join(BASEDIR, "selfdrive", "modeld", "models", "driving_policy.onnx") -def get_file_hash(path: str) -> str: - sha256_hash = hashlib.sha256() - with open(path, "rb") as f: - for byte_block in iter(lambda: f.read(4096), b""): - sha256_hash.update(byte_block) - return sha256_hash.hexdigest() - - def update_model_hash(): vision_hash = get_file_hash(VISION_ONNX_PATH) policy_hash = get_file_hash(POLICY_ONNX_PATH) diff --git a/sunnypilot/models/tests/test_default_model.py b/sunnypilot/models/tests/test_default_model.py index 5067dbaf46..7c2fde70a8 100644 --- a/sunnypilot/models/tests/test_default_model.py +++ b/sunnypilot/models/tests/test_default_model.py @@ -1,4 +1,12 @@ -from openpilot.sunnypilot.models.default_model import get_file_hash, MODEL_HASH_PATH, VISION_ONNX_PATH, POLICY_ONNX_PATH +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" + +from openpilot.sunnypilot import get_file_hash +from openpilot.sunnypilot.models.default_model import MODEL_HASH_PATH, VISION_ONNX_PATH, POLICY_ONNX_PATH import hashlib diff --git a/sunnypilot/selfdrive/car/interfaces.py b/sunnypilot/selfdrive/car/interfaces.py index 55244caa57..6a868ab85b 100644 --- a/sunnypilot/selfdrive/car/interfaces.py +++ b/sunnypilot/selfdrive/car/interfaces.py @@ -11,6 +11,7 @@ from opendbc.car.interfaces import CarInterfaceBase from openpilot.common.params import Params from openpilot.common.swaglog import cloudlog from openpilot.sunnypilot.selfdrive.controls.lib.nnlc.helpers import get_nn_model_path +from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Mode as SpeedLimitMode import openpilot.system.sentry as sentry @@ -22,8 +23,18 @@ def log_fingerprint(CP: structs.CarParams) -> None: sentry.capture_fingerprint(CP.carFingerprint, CP.brand) -def _initialize_neural_network_lateral_control(CI: CarInterfaceBase, CP: structs.CarParams, CP_SP: structs.CarParamsSP, - params: Params = None, enabled: bool = False) -> None: +def _enforce_torque_lateral_control(CP: structs.CarParams, params: Params = None, enabled: bool = False) -> bool: + if params is None: + params = Params() + + if CP.steerControlType != structs.CarParams.SteerControlType.angle: + enabled = params.get_bool("EnforceTorqueControl") + + return enabled + + +def _initialize_neural_network_lateral_control(CP: structs.CarParams, CP_SP: structs.CarParamsSP, + params: Params = None, enabled: bool = False) -> bool: if params is None: params = Params() @@ -35,13 +46,12 @@ def _initialize_neural_network_lateral_control(CI: CarInterfaceBase, CP: structs if nnlc_model_name != "MOCK" and CP.steerControlType != structs.CarParams.SteerControlType.angle: enabled = params.get_bool("NeuralNetworkLateralControl") - if enabled: - CI.configure_torque_tune(CP.carFingerprint, CP.lateralTuning) - CP_SP.neuralNetworkLateralControl.model.path = nnlc_model_path CP_SP.neuralNetworkLateralControl.model.name = nnlc_model_name CP_SP.neuralNetworkLateralControl.fuzzyFingerprint = not exact_match + return enabled + def _initialize_intelligent_cruise_button_management(CP: structs.CarParams, CP_SP: structs.CarParamsSP, params: Params = None) -> None: if params is None: @@ -52,12 +62,44 @@ def _initialize_intelligent_cruise_button_management(CP: structs.CarParams, CP_S CP_SP.pcmCruiseSpeed = False +def _initialize_torque_lateral_control(CI: CarInterfaceBase, CP: structs.CarParams, enforce_torque: bool, nnlc_enabled: bool) -> None: + if nnlc_enabled or enforce_torque: + CI.configure_torque_tune(CP.carFingerprint, CP.lateralTuning) + + +def _cleanup_unsupported_params(CP: structs.CarParams, CP_SP: structs.CarParamsSP, params: Params = None) -> None: + if params is None: + params = Params() + + if CP.steerControlType == structs.CarParams.SteerControlType.angle: + cloudlog.warning("SteerControlType is angle, cleaning up params") + params.remove("NeuralNetworkLateralControl") + params.remove("EnforceTorqueControl") + + if not CP_SP.intelligentCruiseButtonManagementAvailable or CP.openpilotLongitudinalControl: + cloudlog.warning("ICBM not available or openpilot Longitudinal Control enabled, cleaning up params") + params.remove("IntelligentCruiseButtonManagement") + + if not CP.openpilotLongitudinalControl and CP_SP.pcmCruiseSpeed: + cloudlog.warning("openpilot Longitudinal Control and ICBM not available, cleaning up params") + params.remove("DynamicExperimentalControl") + params.remove("CustomAccIncrementsEnabled") + params.remove("SmartCruiseControlVision") + params.remove("SmartCruiseControlMap") + + if params.get("SpeedLimitMode", return_default=True) == SpeedLimitMode.assist: + params.put("SpeedLimitMode", int(SpeedLimitMode.warning)) + + def setup_interfaces(CI: CarInterfaceBase, params: Params = None) -> None: CP = CI.CP CP_SP = CI.CP_SP - _initialize_neural_network_lateral_control(CI, CP, CP_SP, params) + enforce_torque = _enforce_torque_lateral_control(CP, params) + nnlc_enabled = _initialize_neural_network_lateral_control(CP, CP_SP, params) _initialize_intelligent_cruise_button_management(CP, CP_SP, params) + _initialize_torque_lateral_control(CI, CP, enforce_torque, nnlc_enabled) + _cleanup_unsupported_params(CP, CP_SP) def initialize_params(params) -> list[dict[str, Any]]: @@ -68,4 +110,10 @@ def initialize_params(params) -> list[dict[str, Any]]: "HyundaiLongitudinalTuning" ]) + # subaru + keys.extend([ + "SubaruStopAndGo", + "SubaruStopAndGoManualParkingBrake", + ]) + return [{k: params.get(k, return_default=True)} for k in keys] diff --git a/sunnypilot/selfdrive/controls/controlsd_ext.py b/sunnypilot/selfdrive/controls/controlsd_ext.py index e0f9326bf8..8caeeaeabc 100644 --- a/sunnypilot/selfdrive/controls/controlsd_ext.py +++ b/sunnypilot/selfdrive/controls/controlsd_ext.py @@ -10,7 +10,6 @@ from cereal import log, custom from opendbc.car import structs from openpilot.common.params import Params from openpilot.common.swaglog import cloudlog -from openpilot.sunnypilot.selfdrive.controls.lib.param_store import ParamStore from openpilot.sunnypilot.selfdrive.controls.lib.blinker_pause_lateral import BlinkerPauseLateral @@ -19,7 +18,6 @@ class ControlsExt: self.CP = CP self.params = params self.blinker_pause_lateral = BlinkerPauseLateral() - self.param_store = ParamStore(self.CP) self.get_params_sp() cloudlog.info("controlsd_ext is waiting for CarParamsSP") @@ -30,7 +28,6 @@ class ControlsExt: self.pm_services_ext = ['carControlSP'] def get_params_sp(self) -> None: - self.param_store.update(self.params) self.blinker_pause_lateral.get_params() def get_lat_active(self, sm: messaging.SubMaster) -> bool: @@ -73,8 +70,6 @@ class ControlsExt: # MADS state CC_SP.mads = sm['selfdriveStateSP'].mads - CC_SP.params = self.param_store.param_list - CC_SP.intelligentCruiseButtonManagement = sm['selfdriveStateSP'].intelligentCruiseButtonManagement return CC_SP diff --git a/sunnypilot/selfdrive/controls/lib/e2e_alerts_helper.py b/sunnypilot/selfdrive/controls/lib/e2e_alerts_helper.py index eedf8bccbb..944bf617e9 100644 --- a/sunnypilot/selfdrive/controls/lib/e2e_alerts_helper.py +++ b/sunnypilot/selfdrive/controls/lib/e2e_alerts_helper.py @@ -12,47 +12,159 @@ from openpilot.common.realtime import DT_MDL from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP -TRIGGER_THRESHOLD = 30 +GREEN_LIGHT_X_THRESHOLD = 30 +LEAD_DEPART_DIST_THRESHOLD = 1.0 +TRIGGER_TIMER_THRESHOLD = 0.3 + + +class E2EStates: + INACTIVE = 0 + ARMED = 1 + CONSUMED = 2 class E2EAlertsHelper: def __init__(self): self._params = Params() - self._frame = -1 + self.frame = -1 + self.green_light_state = E2EStates.INACTIVE + self.prev_green_light_state = E2EStates.INACTIVE + self.lead_depart_state = E2EStates.INACTIVE + self.prev_lead_depart_state = E2EStates.INACTIVE self.green_light_alert = False self.green_light_alert_enabled = self._params.get_bool("GreenLightAlert") self.lead_depart_alert = False self.lead_depart_alert_enabled = self._params.get_bool("LeadDepartAlert") + self.green_light_trigger_timer = 0 + self.lead_depart_trigger_timer = 0 + self.last_lead_distance = -1 + self.last_moving_frame = -1 + + self.allowed = False + self.last_allowed = False + self.has_lead = False + + self.lead_depart_arm_timer = 0 + self.lead_depart_confirmed_lead = False + self.lead_depart_armed = False + def _read_params(self) -> None: - if self._frame % int(PARAMS_UPDATE_PERIOD / DT_MDL) == 0: + if self.frame % int(PARAMS_UPDATE_PERIOD / DT_MDL) == 0: self.green_light_alert_enabled = self._params.get_bool("GreenLightAlert") self.lead_depart_alert_enabled = self._params.get_bool("LeadDepartAlert") - self._frame += 1 - - def update(self, sm: messaging.SubMaster, events_sp: EventsSP) -> None: - self._read_params() - - if not (self.green_light_alert_enabled or self.lead_depart_alert_enabled): - return - + def update_alert_trigger(self, sm: messaging.SubMaster): CS = sm['carState'] CC = sm['carControl'] model_x = sm['modelV2'].position.x max_idx = len(model_x) - 1 - has_lead = sm['radarState'].leadOne.status - lead_vRel: float = sm['radarState'].leadOne.vRel + self.has_lead = sm['radarState'].leadOne.status + lead_dRel = sm['radarState'].leadOne.dRel - # Green light alert - self.green_light_alert = (self.green_light_alert_enabled and model_x[max_idx] > TRIGGER_THRESHOLD - and not has_lead and CS.standstill and not CS.gasPressed and not CC.enabled) + standstill = CS.standstill + moving = not standstill and CS.vEgo > 0.1 + + if moving: + self.last_moving_frame = self.frame + recent_moving = self.last_moving_frame == -1 or (self.frame - self.last_moving_frame) * DT_MDL < 2.0 + + self.allowed = not moving and not CS.gasPressed and not CC.enabled and not recent_moving + + # Green Light Alert + green_light_trigger = False + if self.green_light_state == E2EStates.ARMED: + if model_x[max_idx] > GREEN_LIGHT_X_THRESHOLD: + self.green_light_trigger_timer += 1 + else: + self.green_light_trigger_timer = 0 + + if self.green_light_trigger_timer * DT_MDL > TRIGGER_TIMER_THRESHOLD: + green_light_trigger = True + elif self.green_light_state != E2EStates.ARMED: + self.green_light_trigger_timer = 0 # Lead Departure Alert - self.lead_depart_alert = (self.lead_depart_alert_enabled and CS.standstill and model_x[max_idx] > 30 - and has_lead and lead_vRel > 1 and not CS.gasPressed) + close_lead_valid = self.has_lead and lead_dRel < 8.0 + if self.allowed and not self.last_allowed and close_lead_valid: + self.lead_depart_confirmed_lead = True + elif not self.allowed: + self.lead_depart_confirmed_lead = False - if self.green_light_alert or self.green_light_alert: + if self.allowed and self.lead_depart_confirmed_lead and close_lead_valid: + self.lead_depart_arm_timer += 1 + + if self.lead_depart_arm_timer * DT_MDL >= 1.0: + self.lead_depart_armed = True + else: + self.lead_depart_arm_timer = 0 + self.lead_depart_armed = False + + lead_depart_trigger = False + if self.lead_depart_state == E2EStates.ARMED: + if self.last_lead_distance == -1 or lead_dRel < self.last_lead_distance: + self.last_lead_distance = lead_dRel + + if self.last_lead_distance != -1 and (lead_dRel - self.last_lead_distance > LEAD_DEPART_DIST_THRESHOLD): + self.lead_depart_trigger_timer += 1 + else: + self.lead_depart_trigger_timer = 0 + + if self.lead_depart_trigger_timer * DT_MDL > TRIGGER_TIMER_THRESHOLD: + lead_depart_trigger = True + elif self.lead_depart_state != E2EStates.ARMED: + self.last_lead_distance = -1 + self.lead_depart_trigger_timer = 0 + + self.last_allowed = self.allowed + + return green_light_trigger, lead_depart_trigger + + @staticmethod + def update_state_machine(state: int, enabled: bool, allowed: bool, triggered: bool) -> tuple[int, bool]: + if state != E2EStates.INACTIVE: + if not allowed or not enabled: + state = E2EStates.INACTIVE + + else: + if state == E2EStates.ARMED: + if triggered: + state = E2EStates.CONSUMED + + elif state == E2EStates.CONSUMED: + pass + + elif state == E2EStates.INACTIVE: + if allowed and enabled: + state = E2EStates.ARMED + + return state, triggered + + def update(self, sm: messaging.SubMaster, events_sp: EventsSP) -> None: + self._read_params() + + green_light_trigger, lead_depart_trigger = self.update_alert_trigger(sm) + + self.prev_green_light_state = self.green_light_state + self.prev_lead_depart_state = self.lead_depart_state + + self.green_light_state, self.green_light_alert = self.update_state_machine( + self.green_light_state, + self.green_light_alert_enabled, + self.allowed and not self.has_lead, + green_light_trigger + ) + + self.lead_depart_state, self.lead_depart_alert = self.update_state_machine( + self.lead_depart_state, + self.lead_depart_alert_enabled, + self.allowed and self.lead_depart_armed, + lead_depart_trigger + ) + + if self.green_light_alert or self.lead_depart_alert: events_sp.add(custom.OnroadEventSP.EventName.e2eChime) + + self.frame += 1 diff --git a/sunnypilot/selfdrive/controls/lib/lane_turn_desire.py b/sunnypilot/selfdrive/controls/lib/lane_turn_desire.py index 00ce026abb..fa35ebb125 100644 --- a/sunnypilot/selfdrive/controls/lib/lane_turn_desire.py +++ b/sunnypilot/selfdrive/controls/lib/lane_turn_desire.py @@ -9,13 +9,15 @@ from cereal import custom from openpilot.common.constants import CV from openpilot.common.params import Params +TurnDirection = custom.ModelDataV2SP.TurnDirection + LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS class LaneTurnController: def __init__(self, desire_helper): self.DH = desire_helper - self.turn_direction = custom.TurnDirection.none + self.turn_direction = TurnDirection.none self.params = Params() self.lane_turn_value = float(self.params.get("LaneTurnValue", return_default=True)) * CV.MPH_TO_MS self.param_read_counter = 0 @@ -33,13 +35,13 @@ class LaneTurnController: def update_lane_turn(self, blindspot_left: bool, blindspot_right: bool, left_blinker: bool, right_blinker: bool, v_ego: float) -> None: if left_blinker and not right_blinker and v_ego < self.lane_turn_value and not blindspot_left: - self.turn_direction = custom.TurnDirection.turnLeft + self.turn_direction = TurnDirection.turnLeft elif right_blinker and not left_blinker and v_ego < self.lane_turn_value and not blindspot_right: - self.turn_direction = custom.TurnDirection.turnRight + self.turn_direction = TurnDirection.turnRight else: - self.turn_direction = custom.TurnDirection.none + self.turn_direction = TurnDirection.none def get_turn_direction(self): if not self.enabled: - return custom.TurnDirection.none + return TurnDirection.none return self.turn_direction diff --git a/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext.py b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext.py index 6e134276e5..39525b3b8e 100644 --- a/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext.py +++ b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext.py @@ -6,11 +6,13 @@ See the LICENSE.md file in the root directory for more details. """ from openpilot.sunnypilot.selfdrive.controls.lib.nnlc.nnlc import NeuralNetworkLateralControl +from openpilot.sunnypilot.selfdrive.controls.lib.latcontrol_torque_ext_override import LatControlTorqueExtOverride -class LatControlTorqueExt(NeuralNetworkLateralControl): +class LatControlTorqueExt(NeuralNetworkLateralControl, LatControlTorqueExtOverride): def __init__(self, lac_torque, CP, CP_SP, CI): - super().__init__(lac_torque, CP, CP_SP, CI) + NeuralNetworkLateralControl.__init__(self, lac_torque, CP, CP_SP, CI) + LatControlTorqueExtOverride.__init__(self, CP) def update(self, CS, VM, pid, params, ff, pid_log, setpoint, measurement, calibrated_pose, roll_compensation, desired_lateral_accel, actual_lateral_accel, lateral_accel_deadzone, gravity_adjusted_lateral_accel, diff --git a/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py index 1965d50b51..609d2f78b6 100644 --- a/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py +++ b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py @@ -58,7 +58,8 @@ class LatControlTorqueExtBase: self.torque_from_lateral_accel_in_torque_space = CI.torque_from_lateral_accel_in_torque_space() self._ff = 0.0 - self._pid = PIDController(0.0, 0.0, k_f=0.0) + self._pid = PIDController(self.torque_params.kp, self.torque_params.ki, + k_f=self.torque_params.kf) self._pid_log = None self._setpoint = 0.0 self._measurement = 0.0 diff --git a/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_override.py b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_override.py new file mode 100644 index 0000000000..f07a7292c1 --- /dev/null +++ b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_override.py @@ -0,0 +1,34 @@ +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" + +from openpilot.common.params import Params + + +class LatControlTorqueExtOverride: + def __init__(self, CP): + self.CP = CP + self.params = Params() + self.enforce_torque_control_toggle = self.params.get_bool("EnforceTorqueControl") # only during init + self.torque_override_enabled = self.params.get_bool("TorqueParamsOverrideEnabled") + self.frame = -1 + + def update_override_torque_params(self, torque_params) -> bool: + if not self.enforce_torque_control_toggle: + return False + + self.frame += 1 + if self.frame % 300 == 0: + self.torque_override_enabled = self.params.get_bool("TorqueParamsOverrideEnabled") + + if not self.torque_override_enabled: + return False + + torque_params.latAccelFactor = float(self.params.get("TorqueParamsOverrideLatAccelFactor", return_default=True)) + torque_params.friction = float(self.params.get("TorqueParamsOverrideFriction", return_default=True)) + return True + + return False diff --git a/sunnypilot/selfdrive/controls/lib/param_store.py b/sunnypilot/selfdrive/controls/lib/param_store.py deleted file mode 100644 index 65a0175340..0000000000 --- a/sunnypilot/selfdrive/controls/lib/param_store.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - -This file is part of sunnypilot and is licensed under the MIT License. -See the LICENSE.md file in the root directory for more details. -""" -from cereal import custom -from opendbc.car import structs -from openpilot.common.params import Params - -from sunnypilot.sunnylink.utils import get_param_as_byte - - -class ParamStore: - keys: list[str] - _params: dict[str, custom.CarControlSP.Param] - - def __init__(self, CP: structs.CarParams): - universal_params: list[str] = [] - brand_params: list[str] = [] - - self.keys = universal_params + brand_params - self._params = {} - - self.frame = 0 - - def update(self, params: Params) -> None: - self.frame += 1 - if self.frame % 300 != 0: - return - - for key in self.keys: - param_type = params.get_type(key).name.lower() # Using string instead of number because its "loose" dependency, and could change by OP at anytime. - - # Over engineering opportunity: It's possible this conversion is slow, we may check the value as params returns it for cache purposes. Not today. - param_value = get_param_as_byte(key, params) - if (existing_param := self._params.get(key)) is not None and existing_param.value == param_value: - continue - - self._params[key] = custom.CarControlSP.Param(key=key, value=param_value, type=param_type) - - @property - def param_list(self) -> list[custom.CarControlSP.Param]: - return [v for k,v in self._params.items()] diff --git a/sunnypilot/selfdrive/controls/lib/speed_limit/common.py b/sunnypilot/selfdrive/controls/lib/speed_limit/common.py index baf9328032..c46768464e 100644 --- a/sunnypilot/selfdrive/controls/lib/speed_limit/common.py +++ b/sunnypilot/selfdrive/controls/lib/speed_limit/common.py @@ -4,10 +4,11 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. This file is part of sunnypilot and is licensed under the MIT License. See the LICENSE.md file in the root directory for more details. """ -from enum import IntEnum + +from openpilot.sunnypilot import IntEnumBase -class Policy(IntEnum): +class Policy(IntEnumBase): car_state_only = 0 map_data_only = 1 car_state_priority = 2 @@ -15,13 +16,13 @@ class Policy(IntEnum): combined = 4 -class OffsetType(IntEnum): +class OffsetType(IntEnumBase): off = 0 fixed = 1 percentage = 2 -class Mode(IntEnum): +class Mode(IntEnumBase): off = 0 information = 1 warning = 2 diff --git a/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_assist.py b/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_assist.py index 302d8cd14d..b948452059 100644 --- a/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_assist.py +++ b/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_assist.py @@ -27,7 +27,11 @@ ACTIVE_STATES = (SpeedLimitAssistState.active, SpeedLimitAssistState.adapting) ENABLED_STATES = (SpeedLimitAssistState.preActive, SpeedLimitAssistState.pending, *ACTIVE_STATES) DISABLED_GUARD_PERIOD = 0.5 # secs. -PRE_ACTIVE_GUARD_PERIOD = 15 # secs. Time to wait after activation before considering temp deactivation signal. +# secs. Time to wait after activation before considering temp deactivation signal. +PRE_ACTIVE_GUARD_PERIOD = { + True: 15, + False: 5, +} SPEED_LIMIT_CHANGED_HOLD_PERIOD = 1 # secs. Time to wait after speed limit change before switching to preActive. LIMIT_MIN_ACC = -1.5 # m/s^2 Maximum deceleration allowed for limit controllers to provide. @@ -109,6 +113,16 @@ class SpeedLimitAssist: def target_set_speed_confirmed(self) -> bool: return bool(self.v_cruise_cluster_conv == self.target_set_speed_conv) + @property + def v_cruise_cluster_below_confirm_speed_threshold(self) -> bool: + return bool(self.v_cruise_cluster_conv < CONFIRM_SPEED_THRESHOLD[self.is_metric]) + + def update_active_event(self, events_sp: EventsSP) -> None: + if self.v_cruise_cluster_below_confirm_speed_threshold: + events_sp.add(EventNameSP.speedLimitChanged) + else: + events_sp.add(EventNameSP.speedLimitActive) + def get_v_target_from_control(self) -> float: if self._has_speed_limit: if self.pcm_op_long and self.is_enabled: @@ -175,7 +189,7 @@ class SpeedLimitAssist: @property def apply_confirm_speed_threshold(self) -> bool: # below CST: always require user confirmation - if self.v_cruise_cluster_conv < CONFIRM_SPEED_THRESHOLD[self.is_metric]: + if self.v_cruise_cluster_below_confirm_speed_threshold: return True # at/above CST: @@ -231,7 +245,7 @@ class SpeedLimitAssist: self.state = SpeedLimitAssistState.inactive elif self.speed_limit_changed and self.apply_confirm_speed_threshold: self.state = SpeedLimitAssistState.preActive - self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL) + self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL) elif self._has_speed_limit and self.v_offset < LIMIT_SPEED_OFFSET_TH: self.state = SpeedLimitAssistState.adapting @@ -241,7 +255,7 @@ class SpeedLimitAssist: self.state = SpeedLimitAssistState.inactive elif self.speed_limit_changed and self.apply_confirm_speed_threshold: self.state = SpeedLimitAssistState.preActive - self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL) + self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL) elif self.v_offset >= LIMIT_SPEED_OFFSET_TH: self.state = SpeedLimitAssistState.active @@ -251,7 +265,7 @@ class SpeedLimitAssist: self._update_confirmed_state() elif self.speed_limit_changed: self.state = SpeedLimitAssistState.preActive - self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL) + self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL) # PRE_ACTIVE elif self.state == SpeedLimitAssistState.preActive: @@ -277,7 +291,7 @@ class SpeedLimitAssist: self._update_confirmed_state() elif self._has_speed_limit: self.state = SpeedLimitAssistState.preActive - self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL) + self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL) else: self.state = SpeedLimitAssistState.pending @@ -303,7 +317,7 @@ class SpeedLimitAssist: elif self.speed_limit_changed and self.apply_confirm_speed_threshold: self.state = SpeedLimitAssistState.preActive - self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL) + self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL) # PRE_ACTIVE elif self.state == SpeedLimitAssistState.preActive: @@ -317,7 +331,7 @@ class SpeedLimitAssist: elif self.state == SpeedLimitAssistState.inactive: if self.speed_limit_changed: self.state = SpeedLimitAssistState.preActive - self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL) + self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL) elif self._update_non_pcm_long_confirmed_state(): self.state = SpeedLimitAssistState.active @@ -333,7 +347,7 @@ class SpeedLimitAssist: self.state = SpeedLimitAssistState.active elif self._has_speed_limit: self.state = SpeedLimitAssistState.preActive - self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL) + self.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.pcm_op_long] / DT_MDL) else: self.state = SpeedLimitAssistState.inactive @@ -351,15 +365,15 @@ class SpeedLimitAssist: if self.is_active: if self._state_prev not in ACTIVE_STATES: - events_sp.add(EventNameSP.speedLimitActive) + self.update_active_event(events_sp) # only notify if we acquire a valid speed limit # do not check has_speed_limit here elif self._speed_limit != self.speed_limit_prev: if self.speed_limit_prev <= 0: - events_sp.add(EventNameSP.speedLimitActive) + self.update_active_event(events_sp) elif self.speed_limit_prev > 0 and self._speed_limit > 0: - events_sp.add(EventNameSP.speedLimitChanged) + self.update_active_event(events_sp) def update(self, long_enabled: bool, long_override: bool, v_ego: float, a_ego: float, v_cruise_cluster: float, speed_limit: float, speed_limit_final_last: float, has_speed_limit: bool, distance: float, events_sp: EventsSP) -> None: diff --git a/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_resolver.py b/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_resolver.py index 51fb8f6d64..35965c0e18 100644 --- a/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_resolver.py +++ b/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_resolver.py @@ -12,7 +12,7 @@ from openpilot.common.constants import CV from openpilot.common.gps import get_gps_location_service from openpilot.common.params import Params from openpilot.common.realtime import DT_MDL -from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD +from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD, get_sanitize_int_param from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit import LIMIT_MAX_MAP_DATA_AGE, LIMIT_ADAPT_ACC from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Policy, OffsetType @@ -42,6 +42,12 @@ class SpeedLimitResolver: self.distance_solutions = {} # Store for distance to current speed limit start for different sources self.policy = self.params.get("SpeedLimitPolicy", return_default=True) + self.policy = get_sanitize_int_param( + "SpeedLimitPolicy", + Policy.min().value, + Policy.max().value, + self.params + ) self._policy_to_sources_map = { Policy.car_state_only: [SpeedLimitSource.car], Policy.map_data_only: [SpeedLimitSource.map], @@ -54,7 +60,12 @@ class SpeedLimitResolver: self._reset_limit_sources(source) self.is_metric = self.params.get_bool("IsMetric") - self.offset_type = self.params.get("SpeedLimitOffsetType", return_default=True) + self.offset_type = get_sanitize_int_param( + "SpeedLimitOffsetType", + OffsetType.min().value, + OffsetType.max().value, + self.params + ) self.offset_value = self.params.get("SpeedLimitValueOffset", return_default=True) self.speed_limit = 0. @@ -131,6 +142,7 @@ class SpeedLimitResolver: self.limit_solutions[SpeedLimitSource.map] = speed_limit self.distance_solutions[SpeedLimitSource.map] = 0. + # FIXME-SP: this is not working as expected if 0. < next_speed_limit < self.v_ego: adapt_time = (next_speed_limit - self.v_ego) / LIMIT_ADAPT_ACC adapt_distance = self.v_ego * adapt_time + 0.5 * LIMIT_ADAPT_ACC * adapt_time ** 2 diff --git a/sunnypilot/selfdrive/controls/lib/speed_limit/tests/test_speed_limit_assist.py b/sunnypilot/selfdrive/controls/lib/speed_limit/tests/test_speed_limit_assist.py index d2c7a4716d..168c53016b 100644 --- a/sunnypilot/selfdrive/controls/lib/speed_limit/tests/test_speed_limit_assist.py +++ b/sunnypilot/selfdrive/controls/lib/speed_limit/tests/test_speed_limit_assist.py @@ -39,7 +39,7 @@ class TestSpeedLimitAssist: self.events_sp = EventsSP() CI = self._setup_platform(TOYOTA.TOYOTA_RAV4_TSS2) self.sla = SpeedLimitAssist(CI.CP) - self.sla.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL) + self.sla.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.sla.pcm_op_long] / DT_MDL) self.pcm_long_max_set_speed = PCM_LONG_REQUIRED_MAX_SET_SPEED[self.sla.is_metric][1] # use 80 MPH for now self.speed_conv = CV.MS_TO_KPH if self.sla.is_metric else CV.MS_TO_MPH @@ -114,7 +114,7 @@ class TestSpeedLimitAssist: self.sla.state = SpeedLimitAssistState.preActive self.sla.update(True, False, SPEED_LIMITS['city'], 0, SPEED_LIMITS['highway'], SPEED_LIMITS['city'], SPEED_LIMITS['city'], True, 0, self.events_sp) - for _ in range(int(PRE_ACTIVE_GUARD_PERIOD / DT_MDL)): + for _ in range(int(PRE_ACTIVE_GUARD_PERIOD[self.sla.pcm_op_long] / DT_MDL)): self.sla.update(True, False, SPEED_LIMITS['city'], 0, SPEED_LIMITS['highway'], SPEED_LIMITS['city'], SPEED_LIMITS['city'], True, 0, self.events_sp) assert self.sla.state == SpeedLimitAssistState.inactive diff --git a/sunnypilot/selfdrive/controls/lib/tests/test_lane_turn_desire.py b/sunnypilot/selfdrive/controls/lib/tests/test_lane_turn_desire.py index 5633ed6efc..57fe7b684f 100644 --- a/sunnypilot/selfdrive/controls/lib/tests/test_lane_turn_desire.py +++ b/sunnypilot/selfdrive/controls/lib/tests/test_lane_turn_desire.py @@ -1,113 +1,113 @@ import pytest -from cereal import log +from cereal import log, custom from openpilot.common.params import Params from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper from openpilot.sunnypilot.selfdrive.controls.lib.lane_turn_desire import LaneTurnController, LANE_CHANGE_SPEED_MIN from openpilot.sunnypilot.selfdrive.controls.lib.auto_lane_change import AutoLaneChangeMode - -class TurnDirection: - none = 0 - turnLeft = 1 - turnRight = 2 +TurnDirection = custom.ModelDataV2SP.TurnDirection @pytest.mark.parametrize("left_blinker,right_blinker,v_ego,blindspot_left,blindspot_right,expected", [ - (True, False, 5, False, False, TurnDirection.turnLeft), - (False, True, 6, False, False, TurnDirection.turnRight), - (True, False, 9, False, False, TurnDirection.none), - (True, False, 7, True, False, TurnDirection.none), - (False, True, 6, False, True, TurnDirection.none), - (False, False, 5, False, False, TurnDirection.none), - (True, True, 5, False, False, TurnDirection.none), + (True, False, 5, False, False, TurnDirection.turnLeft), + (False, True, 6, False, False, TurnDirection.turnRight), + (True, False, 9, False, False, TurnDirection.none), + (True, False, 7, True, False, TurnDirection.none), + (False, True, 6, False, True, TurnDirection.none), + (False, False, 5, False, False, TurnDirection.none), + (True, True, 5, False, False, TurnDirection.none), ]) def test_lane_turn_desire_conditions(left_blinker, right_blinker, v_ego, blindspot_left, blindspot_right, expected): - dh = DesireHelper() - controller = LaneTurnController(dh) - controller.enabled = True - controller.lane_turn_value = LANE_CHANGE_SPEED_MIN - controller.turn_direction = TurnDirection.none - controller.update_lane_turn(blindspot_left, blindspot_right, left_blinker, right_blinker, v_ego) - assert controller.get_turn_direction() == expected + dh = DesireHelper() + controller = LaneTurnController(dh) + controller.enabled = True + controller.lane_turn_value = LANE_CHANGE_SPEED_MIN + controller.turn_direction = TurnDirection.none + controller.update_lane_turn(blindspot_left, blindspot_right, left_blinker, right_blinker, v_ego) + assert controller.get_turn_direction() == expected def test_lane_turn_desire_disabled(): - dh = DesireHelper() - controller = LaneTurnController(dh) - controller.enabled = False - controller.lane_turn_value = LANE_CHANGE_SPEED_MIN - controller.turn_direction = TurnDirection.none - controller.update_lane_turn(False, False, True, False, 7) - assert controller.get_turn_direction() == TurnDirection.none + dh = DesireHelper() + controller = LaneTurnController(dh) + controller.enabled = False + controller.lane_turn_value = LANE_CHANGE_SPEED_MIN + controller.turn_direction = TurnDirection.none + controller.update_lane_turn(False, False, True, False, 7) + assert controller.get_turn_direction() == TurnDirection.none def test_lane_turn_overrides_lane_change(): - dh = DesireHelper() - controller = LaneTurnController(dh) - controller.enabled = True - controller.lane_turn_value = LANE_CHANGE_SPEED_MIN - controller.turn_direction = TurnDirection.none - # left turn desire - controller.update_lane_turn(False, False, True, False, 5) - assert controller.get_turn_direction() == TurnDirection.turnLeft - # right turn desire - controller.update_lane_turn(False, False, False, True, 6) - assert controller.get_turn_direction() == TurnDirection.turnRight - # no turn - controller.update_lane_turn(False, False, False, False, 7) - assert controller.get_turn_direction() == TurnDirection.none + dh = DesireHelper() + controller = LaneTurnController(dh) + controller.enabled = True + controller.lane_turn_value = LANE_CHANGE_SPEED_MIN + controller.turn_direction = TurnDirection.none + # left turn desire + controller.update_lane_turn(False, False, True, False, 5) + assert controller.get_turn_direction() == TurnDirection.turnLeft + # right turn desire + controller.update_lane_turn(False, False, False, True, 6) + assert controller.get_turn_direction() == TurnDirection.turnRight + # no turn + controller.update_lane_turn(False, False, False, False, 7) + assert controller.get_turn_direction() == TurnDirection.none @pytest.mark.parametrize("v_ego,expected", [ - (8.93, TurnDirection.turnLeft), # just below threshold - (8.96, TurnDirection.none), # above threshold - (8.95, TurnDirection.none), # just above threshold + (8.93, TurnDirection.turnLeft), # just below threshold + (8.96, TurnDirection.none), # above threshold + (8.95, TurnDirection.none), # just above threshold ]) def test_lane_turn_desire_speed_boundary(v_ego, expected): - dh = DesireHelper() - controller = LaneTurnController(dh) - controller.enabled = True - controller.lane_turn_value = LANE_CHANGE_SPEED_MIN - controller.turn_direction = TurnDirection.none - controller.update_lane_turn(False, True, True, False, v_ego) - assert controller.get_turn_direction() == expected + dh = DesireHelper() + controller = LaneTurnController(dh) + controller.enabled = True + controller.lane_turn_value = LANE_CHANGE_SPEED_MIN + controller.turn_direction = TurnDirection.none + controller.update_lane_turn(False, True, True, False, v_ego) + assert controller.get_turn_direction() == expected class DummyCarState: - def __init__(self, vEgo=0, leftBlinker=False, rightBlinker=False, leftBlindspot=False, rightBlindspot=False, - steeringPressed=False, steeringTorque=0, brakePressed=False): - self.vEgo = vEgo - self.leftBlinker = leftBlinker - self.rightBlinker = rightBlinker - self.leftBlindspot = leftBlindspot - self.rightBlindspot = rightBlindspot - self.steeringPressed = steeringPressed - self.steeringTorque = steeringTorque - self.brakePressed = brakePressed + def __init__(self, vEgo=0, leftBlinker=False, rightBlinker=False, leftBlindspot=False, rightBlindspot=False, + steeringPressed=False, steeringTorque=0, brakePressed=False): + self.vEgo = vEgo + self.leftBlinker = leftBlinker + self.rightBlinker = rightBlinker + self.leftBlindspot = leftBlindspot + self.rightBlindspot = rightBlindspot + self.steeringPressed = steeringPressed + self.steeringTorque = steeringTorque + self.brakePressed = brakePressed + @pytest.fixture def set_lane_turn_params(): - params = Params() - params.put("LaneTurnDesire", True) - params.put("LaneTurnValue", 20.0) + params = Params() + params.put("LaneTurnDesire", True) + params.put("LaneTurnValue", 20.0) + @pytest.mark.parametrize("carstate, lateral_active, lane_change_prob, expected_desire", [ - # Lane turn desire overrides lane change desire - (DummyCarState(vEgo=5, leftBlinker=True, rightBlinker=False, leftBlindspot=False, rightBlindspot=False), True, 1.0, log.Desire.turnLeft), - (DummyCarState(vEgo=7, leftBlinker=False, rightBlinker=True, leftBlindspot=False, rightBlindspot=False), True, 1.0, log.Desire.turnRight), - # Lane change desire only (no turn desires) - (DummyCarState(vEgo=9, leftBlinker=True, rightBlinker=False, leftBlindspot=False, rightBlindspot=False, - steeringPressed=True, steeringTorque=1), True, 1.0, log.Desire.laneChangeLeft), - (DummyCarState(vEgo=9, leftBlinker=False, rightBlinker=True, leftBlindspot=False, rightBlindspot=False, - steeringPressed=True, steeringTorque=-1), True, 1.0, log.Desire.laneChangeRight), - # No desire (inactive) - (DummyCarState(vEgo=9, leftBlinker=False, rightBlinker=False), False, 1.0, log.Desire.none), - (DummyCarState(vEgo=4, leftBlinker=False, rightBlinker=False), True, 1.0, log.Desire.none), # No blinkers? no desire! + # Lane turn desire overrides lane change desire + (DummyCarState(vEgo=5, leftBlinker=True, rightBlinker=False, leftBlindspot=False, rightBlindspot=False), True, 1.0, + log.Desire.turnLeft), + (DummyCarState(vEgo=7, leftBlinker=False, rightBlinker=True, leftBlindspot=False, rightBlindspot=False), True, 1.0, + log.Desire.turnRight), + # Lane change desire only (no turn desires) + (DummyCarState(vEgo=9, leftBlinker=True, rightBlinker=False, leftBlindspot=False, rightBlindspot=False, + steeringPressed=True, steeringTorque=1), True, 1.0, log.Desire.laneChangeLeft), + (DummyCarState(vEgo=9, leftBlinker=False, rightBlinker=True, leftBlindspot=False, rightBlindspot=False, + steeringPressed=True, steeringTorque=-1), True, 1.0, log.Desire.laneChangeRight), + # No desire (inactive) + (DummyCarState(vEgo=9, leftBlinker=False, rightBlinker=False), False, 1.0, log.Desire.none), + (DummyCarState(vEgo=4, leftBlinker=False, rightBlinker=False), True, 1.0, log.Desire.none), # No blinkers? no desire! ]) def test_desire_helper_integration(carstate, lateral_active, lane_change_prob, expected_desire, set_lane_turn_params): - dh = DesireHelper() - dh.alc.lane_change_set_timer = AutoLaneChangeMode.NUDGE - for _ in range(10): - dh.update(carstate, lateral_active, lane_change_prob) - assert dh.desire == expected_desire # The first four tests were unit tests to test the controller, where this tests the integration in desire helpers + dh = DesireHelper() + dh.alc.lane_change_set_timer = AutoLaneChangeMode.NUDGE + for _ in range(10): + dh.update(carstate, lateral_active, lane_change_prob) + assert dh.desire == expected_desire # The first four tests were unit tests to test the controller, where this tests the integration in desire helpers diff --git a/sunnypilot/selfdrive/locationd/torqued_ext.py b/sunnypilot/selfdrive/locationd/torqued_ext.py new file mode 100644 index 0000000000..58a23da00e --- /dev/null +++ b/sunnypilot/selfdrive/locationd/torqued_ext.py @@ -0,0 +1,65 @@ +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" + +import numpy as np + +from cereal import car + +from openpilot.common.params import Params +from openpilot.common.realtime import DT_MDL +from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD + +RELAXED_MIN_BUCKET_POINTS = np.array([1, 200, 300, 500, 500, 300, 200, 1]) + +ALLOWED_CARS = ['toyota', 'hyundai', 'rivian', 'honda'] + + + +class TorqueEstimatorExt: + def __init__(self, CP: car.CarParams): + self.CP = CP + self._params = Params() + self.frame = -1 + + self.enforce_torque_control_toggle = self._params.get_bool("EnforceTorqueControl") # only during init + self.use_params = self.CP.brand in ALLOWED_CARS and self.CP.lateralTuning.which() == 'torque' + self.use_live_torque_params = self._params.get_bool("LiveTorqueParamsToggle") + self.torque_override_enabled = self._params.get_bool("TorqueParamsOverrideEnabled") + self.min_bucket_points = RELAXED_MIN_BUCKET_POINTS + self.factor_sanity = 0.0 + self.friction_sanity = 0.0 + self.offline_latAccelFactor = 0.0 + self.offline_friction = 0.0 + + def initialize_custom_params(self, decimated=False): + self.update_use_params() + + if self.enforce_torque_control_toggle: + if self._params.get_bool("LiveTorqueParamsRelaxedToggle"): + self.min_bucket_points = RELAXED_MIN_BUCKET_POINTS / (10 if decimated else 1) + self.factor_sanity = 0.5 if decimated else 1.0 + self.friction_sanity = 0.8 if decimated else 1.0 + + if self._params.get_bool("CustomTorqueParams"): + self.offline_latAccelFactor = float(self._params.get("TorqueParamsOverrideLatAccelFactor", return_default=True)) + self.offline_friction = float(self._params.get("TorqueParamsOverrideFriction", return_default=True)) + + def _update_params(self): + if self.frame % int(PARAMS_UPDATE_PERIOD / DT_MDL) == 0: + self.use_live_torque_params = self._params.get_bool("LiveTorqueParamsToggle") + self.torque_override_enabled = self._params.get_bool("TorqueParamsOverrideEnabled") + + def update_use_params(self): + self._update_params() + + if self.enforce_torque_control_toggle: + if self.torque_override_enabled: + self.use_params = False + else: + self.use_params = self.use_live_torque_params + + self.frame += 1 diff --git a/sunnypilot/selfdrive/selfdrived/events.py b/sunnypilot/selfdrive/selfdrived/events.py index e9f4b29bae..4edc0bd470 100644 --- a/sunnypilot/selfdrive/selfdrived/events.py +++ b/sunnypilot/selfdrive/selfdrived/events.py @@ -4,13 +4,13 @@ from openpilot.common.constants import CV from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \ NoEntryAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, AlertCallbackType, wrong_car_mode_alert from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit import PCM_LONG_REQUIRED_MAX_SET_SPEED, CONFIRM_SPEED_THRESHOLD -from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.helpers import compare_cluster_target AlertSize = log.SelfdriveState.AlertSize AlertStatus = log.SelfdriveState.AlertStatus VisualAlert = car.CarControl.HUDControl.VisualAlert AudibleAlert = car.CarControl.HUDControl.AudibleAlert +AudibleAlertSP = custom.SelfdriveStateSP.AudibleAlert EventNameSP = custom.OnroadEventSP.EventName @@ -33,6 +33,9 @@ def speed_limit_pre_active_alert(CP: car.CarParams, CS: car.CarState, sm: messag speed_conv = CV.MS_TO_KPH if metric else CV.MS_TO_MPH speed_limit_final_last = sm['longitudinalPlanSP'].speedLimit.resolver.speedLimitFinalLast speed_limit_final_last_conv = round(speed_limit_final_last * speed_conv) + alert_1_str = "" + alert_2_str = "" + alert_size = AlertSize.none if CP.openpilotLongitudinalControl and CP.pcmCruise: # PCM long @@ -40,25 +43,16 @@ def speed_limit_pre_active_alert(CP: car.CarParams, CS: car.CarState, sm: messag pcm_long_required_max = cst_low if speed_limit_final_last_conv < CONFIRM_SPEED_THRESHOLD[metric] else cst_high pcm_long_required_max_set_speed_conv = round(pcm_long_required_max * speed_conv) speed_unit = "km/h" if metric else "mph" + + alert_1_str = "Speed Limit Assist: Activation Required" alert_2_str = f"Manually change set speed to {pcm_long_required_max_set_speed_conv} {speed_unit} to activate" - else: - # Non PCM long - v_cruise_cluster = CS.vCruiseCluster * CV.KPH_TO_MS - - req_plus, req_minus = compare_cluster_target(v_cruise_cluster, speed_limit_final_last, metric) - arrow_str = "" - if req_plus: - arrow_str = "RES/+" - elif req_minus: - arrow_str = "SET/-" - - alert_2_str = f"Operate the {arrow_str} cruise control button to activate" + alert_size = AlertSize.mid return Alert( - "Speed Limit Assist: Activation Required", + alert_1_str, alert_2_str, - AlertStatus.normal, AlertSize.mid, - Priority.LOW, VisualAlert.none, AudibleAlert.none, .1) + AlertStatus.normal, alert_size, + Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleLow, .1) class EventsSP(EventsBase): @@ -202,7 +196,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = { "Automatically adjusting to the posted speed limit", "", AlertStatus.normal, AlertSize.small, - Priority.LOW, VisualAlert.none, AudibleAlert.none, 5.), + Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleHigh, 5.), }, EventNameSP.speedLimitChanged: { @@ -210,7 +204,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = { "Set speed changed", "", AlertStatus.normal, AlertSize.small, - Priority.LOW, VisualAlert.none, AudibleAlert.none, 5.), + Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleHigh, 5.), }, EventNameSP.speedLimitPreActive: { @@ -222,7 +216,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = { "Automatically adjusting to the last speed limit", "", AlertStatus.normal, AlertSize.small, - Priority.LOW, VisualAlert.none, AudibleAlert.none, 5.), + Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleHigh, 5.), }, EventNameSP.e2eChime: { @@ -230,6 +224,6 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = { "", "", AlertStatus.normal, AlertSize.none, - Priority.MID, VisualAlert.none, AudibleAlert.prompt, 0.1), + Priority.MID, VisualAlert.none, AudibleAlert.prompt, 3.), }, } diff --git a/sunnypilot/sunnylink/api.py b/sunnypilot/sunnylink/api.py index b7838a40b0..cd2a358c60 100644 --- a/sunnypilot/sunnylink/api.py +++ b/sunnypilot/sunnylink/api.py @@ -147,7 +147,7 @@ class SunnylinkApi(BaseApi): self.params.put("SunnylinkDongleId", sunnylink_dongle_id or UNREGISTERED_SUNNYLINK_DONGLE_ID) # Set the last ping time to the current time since we were just talking to the API - last_ping = int(time.monotonic() * 1e9) if successful_registration else start_time + last_ping = int((time.monotonic() if successful_registration else start_time) * 1e9) Params().put("LastSunnylinkPingTime", last_ping) # Disable sunnylink if registration was not successful diff --git a/sunnypilot/sunnylink/athena/sunnylinkd.py b/sunnypilot/sunnylink/athena/sunnylinkd.py index 25a77c367b..d1b38d656f 100755 --- a/sunnypilot/sunnylink/athena/sunnylinkd.py +++ b/sunnypilot/sunnylink/athena/sunnylinkd.py @@ -178,12 +178,29 @@ def getParamsAllKeys() -> list[str]: return keys +@dispatcher.add_method +def getParamsAllKeysV1() -> dict[str, str]: + available_keys: list[str] = [k.decode('utf-8') for k in Params().all_keys()] + + params_dict: dict[str, list[dict[str, str | bool | int | None]]] = {"params": []} + for key in available_keys: + value = get_param_as_byte(key, get_default=True) + params_dict["params"].append({ + "key": key, + "type": int(params.get_type(key).value), + "default_value": base64.b64encode(value).decode('utf-8') if value else None, + }) + + return {"keys": json.dumps(params_dict.get("params", []))} + + @dispatcher.add_method def getParams(params_keys: list[str], compression: bool = False) -> str | dict[str, str]: params = Params() + available_keys: list[str] = [k.decode('utf-8') for k in Params().all_keys()] try: - param_keys_validated = [key for key in params_keys if key in getParamsAllKeys()] + param_keys_validated = [key for key in params_keys if key in available_keys] params_dict: dict[str, list[dict[str, str | bool | int]]] = {"params": []} for key in param_keys_validated: value = get_param_as_byte(key) diff --git a/sunnypilot/sunnylink/registration_manager.py b/sunnypilot/sunnylink/registration_manager.py index 34323c2789..805d2482db 100755 --- a/sunnypilot/sunnylink/registration_manager.py +++ b/sunnypilot/sunnylink/registration_manager.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import time +from openpilot.common.params import Params from openpilot.common.realtime import Ratekeeper from openpilot.common.swaglog import cloudlog @@ -12,17 +13,22 @@ NetworkType = log.DeviceState.NetworkType def main(): """The main method is expected to be called by the manager when the device boots up.""" - rk = Ratekeeper(.5) - sm = messaging.SubMaster(['deviceState'], poll='deviceState') - while True: - sm.update(1000) - if sm['deviceState'].networkType != NetworkType.none: - break + try: + rk = Ratekeeper(.5) + sm = messaging.SubMaster(['deviceState'], poll='deviceState') + while True: + sm.update(1000) + if sm['deviceState'].networkType != NetworkType.none: + break - cloudlog.info(f"Waiting to become online... {time.monotonic()}") - rk.keep_time() + cloudlog.info(f"Waiting to become online... {time.monotonic()}") + rk.keep_time() - register_sunnylink() + register_sunnylink() + except Exception: + cloudlog.exception("Sunnylink registration failed") + Params().put_bool("SunnylinkTempFault", True) + raise if __name__ == "__main__": diff --git a/sunnypilot/sunnylink/utils.py b/sunnypilot/sunnylink/utils.py index 91c0788795..e86a795170 100644 --- a/sunnypilot/sunnylink/utils.py +++ b/sunnypilot/sunnylink/utils.py @@ -6,31 +6,32 @@ from openpilot.common.params import Params, ParamKeyType from openpilot.system.version import is_prebuilt -def get_sunnylink_status(params=None) -> tuple[bool, bool]: +def get_sunnylink_status(params=None) -> tuple[bool, bool, bool]: """Get the status of Sunnylink on the device. Returns a tuple of (is_sunnylink_enabled, is_registered).""" params = params or Params() is_sunnylink_enabled = params.get_bool("SunnylinkEnabled") is_registered = params.get("SunnylinkDongleId") not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) - return is_sunnylink_enabled, is_registered + is_on_temporary_fault = params.get_bool("SunnylinkTempFault") + return is_sunnylink_enabled, is_registered, is_on_temporary_fault def sunnylink_ready(params=None) -> bool: """Check if the device is ready to communicate with Sunnylink. That means it is enabled and registered.""" params = params or Params() - is_sunnylink_enabled, is_registered = get_sunnylink_status(params) - return is_sunnylink_enabled and is_registered + is_sunnylink_enabled, is_registered, is_on_temporary_fault = get_sunnylink_status(params) + return is_sunnylink_enabled and is_registered and not is_on_temporary_fault def use_sunnylink_uploader(params) -> bool: """Check if the device is ready to use Sunnylink and the uploader is enabled.""" - return sunnylink_ready(params) and params.get_bool("EnableSunnylinkUploader") + return not params.get_bool("NetworkMetered") and sunnylink_ready(params) and params.get_bool("EnableSunnylinkUploader") def sunnylink_need_register(params=None) -> bool: """Check if the device needs to be registered with Sunnylink.""" params = params or Params() - is_sunnylink_enabled, is_registered = get_sunnylink_status(params) - return is_sunnylink_enabled and not is_registered + is_sunnylink_enabled, is_registered, is_on_temporary_fault = get_sunnylink_status(params) + return is_sunnylink_enabled and not is_registered and not is_on_temporary_fault def register_sunnylink(): @@ -47,8 +48,12 @@ def register_sunnylink(): "timeout": 60 } - sunnylink_id = SunnylinkApi(None).register_device(None, **extra_args) - print(f"SunnyLinkId: {sunnylink_id}") + try: + sunnylink_id = SunnylinkApi(None).register_device(None, **extra_args) + print(f"SunnyLinkId: {sunnylink_id}") + except Exception: + Params().put_bool("SunnylinkTempFault", True) + raise def get_api_token(): @@ -60,14 +65,20 @@ def get_api_token(): print(f"API Token: {token}") -def get_param_as_byte(param_name: str, params=None) -> bytes | None: +def get_param_as_byte(param_name: str, params=None, get_default=False) -> bytes | None: """Get a parameter as bytes. Returns None if the parameter does not exist.""" - params = params or Params() # Use existing Params instance if provided - param = params.get(param_name) + params = params or Params() + param = params.get(param_name) if not get_default else params.get_default_value(param_name) + if param is None: return None param_type = params.get_type(param_name) + return _to_bytes(param, param_type) + + +def _to_bytes(param: bytes, param_type: ParamKeyType) -> bytes | None: + """Convert a parameter value to bytes based on its type.""" if param_type == ParamKeyType.BYTES: return bytes(param) elif param_type == ParamKeyType.JSON: diff --git a/system/manager/process_config.py b/system/manager/process_config.py index b1a2fa6e13..c5f20e511b 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -95,6 +95,12 @@ def is_stock_model(started, params, CP: car.CarParams) -> bool: def mapd_ready(started: bool, params: Params, CP: car.CarParams) -> bool: return bool(os.path.exists(Paths.mapd_root())) +def uploader_ready(started: bool, params: Params, CP: car.CarParams) -> bool: + if not params.get_bool("OnroadUploads"): + return only_offroad(started, params, CP) + + return always_run(started, params, CP) + def or_(*fns): return lambda *args: operator.or_(*(fn(*args) for fn in fns)) @@ -145,7 +151,7 @@ procs = [ PythonProcess("hardwared", "system.hardware.hardwared", always_run), PythonProcess("tombstoned", "system.tombstoned", always_run, enabled=not PC), PythonProcess("updated", "system.updated.updated", only_offroad, enabled=not PC), - PythonProcess("uploader", "system.loggerd.uploader", always_run), + PythonProcess("uploader", "system.loggerd.uploader", uploader_ready), PythonProcess("statsd", "system.statsd", always_run), PythonProcess("feedbackd", "selfdrive.ui.feedback.feedbackd", only_onroad), diff --git a/third_party/mapd_pfeiferj/mapd b/third_party/mapd_pfeiferj/mapd index eb2372ceed..c8b50b0791 100755 Binary files a/third_party/mapd_pfeiferj/mapd and b/third_party/mapd_pfeiferj/mapd differ