Merge branch 'master' into fp-KIA_FORTE_2019_NON_SCC

This commit is contained in:
royjr
2026-02-09 01:00:46 -05:00
28 changed files with 766 additions and 66 deletions
+1
View File
@@ -153,6 +153,7 @@ struct ModelManagerSP @0xaedffd8f31e7b55d {
navigation @1;
vision @2;
policy @3;
offPolicy @4;
}
}
+2 -1
View File
@@ -115,6 +115,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"SshEnabled", {PERSISTENT | BACKUP, BOOL}},
{"TermsVersion", {PERSISTENT, STRING}},
{"TorqueBar", {PERSISTENT | BACKUP, BOOL, "0"}},
{"TrainingVersion", {PERSISTENT, STRING}},
{"UbloxAvailable", {PERSISTENT, BOOL}},
{"UpdateAvailable", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
@@ -248,7 +249,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"OsmStateTitle", {PERSISTENT, STRING}},
{"OsmWayTest", {PERSISTENT, STRING}},
{"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING}},
{"RoadNameToggle", {PERSISTENT, STRING}},
{"RoadNameToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
// Speed Limit
{"SpeedLimitMode", {PERSISTENT | BACKUP, INT, "1"}},
+1 -10
View File
@@ -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.
# 344 Supported Cars
# 335 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video|Setup Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
@@ -23,10 +23,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Audi S3 2015-17">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EUV 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV 2022-23">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EV Non-ACC 2017|Adaptive Cruise Control (ACC)|Stock|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV Non-ACC 2017">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EV Non-ACC 2018-21|Adaptive Cruise Control (ACC)|Stock|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV Non-ACC 2018-21">Buy Here</a></sub></details>|||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Equinox 2019-22">Buy Here</a></sub></details>|||
|Chevrolet|Malibu Non-ACC 2016-23|Adaptive Cruise Control (ACC)|Stock|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu Non-ACC 2016-23">Buy Here</a></sub></details>|||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Silverado 1500 2020-21">Buy Here</a></sub></details>|||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Trailblazer 2021-22">Buy Here</a></sub></details>|||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2017-18">Buy Here</a></sub></details>|||
@@ -91,7 +88,6 @@ A supported vehicle is one that just works when you install a comma device. All
|Honda|Civic Hatchback Hybrid 2025-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid 2025-26">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid (Europe only) 2023">Buy Here</a></sub></details>|||
|Honda|Civic Hybrid 2025-26|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hybrid 2025-26">Buy Here</a></sub></details>|||
|Honda|Clarity 2018-21|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector + Honda Clarity Proxy Board<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://shop.retropilot.org/product/honda-clarity-proxy-board-kit">Buy Here</a></sub></details>|||
|Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2015-16">Buy Here</a></sub></details>|||
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|15 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2017-22">Buy Here</a></sub></details>|||
|Honda|CR-V 2023-26|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2023-26">Buy Here</a></sub></details>|||
@@ -122,7 +118,6 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra GT 2017-20">Buy Here</a></sub></details>|||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Non-SCC 2022">Buy Here</a></sub></details>|||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Genesis 2015-16">Buy Here</a></sub></details>|||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai i30 2017-19">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>|||
@@ -140,9 +135,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2018-21">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Kona Electric 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)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric Non-SCC 2019">Buy Here</a></sub></details>|||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Hybrid 2020">Buy Here</a></sub></details>|||
|Hyundai|Kona 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)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Non-SCC 2019">Buy Here</a></sub></details>|||
|Hyundai|Nexo 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Nexo 2021">Buy Here</a></sub></details>|||
|Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Cruz 2022-24">Buy Here</a></sub></details>|||
@@ -166,13 +159,11 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival 2022-24">Buy Here</a></sub></details>|||
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival (China only) 2023">Buy Here</a></sub></details>|||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed 2019-21">Buy Here</a></sub></details>|||
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed Plug-in Hybrid Non-SCC 2022">Buy Here</a></sub></details>|||
|Kia|EV6 (Southeast Asia only) 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>|||
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2019-21">Buy Here</a></sub></details>|||
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte 2022-23">Buy Here</a></sub></details>|||
|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)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Forte Non-SCC 2019">Buy Here</a></sub></details>|||
|Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 2021-24">Buy Here</a></sub></details>|||
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K5 Hybrid 2020-22">Buy Here</a></sub></details>|||
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Kia K8 Hybrid (with HDA II) 2023">Buy Here</a></sub></details>|||
+3 -1
View File
@@ -68,8 +68,10 @@ def generate_metadata(model_path: Path, output_dir: Path, short_name: str):
metadata_file = metadata_file.rename(output_path / f"{base}_{short_name.lower()}_metadata.pkl")
# Build the metadata structure
model_type = "offPolicy" if "off_policy" in base else base.split("_")[-1]
model_metadata = {
"type": base.split("_")[-1] if "dmonitoring" not in base else "dmonitoring",
"type": model_type,
"artifact": {
"file_name": tinygrad_file.name,
"download_uri": {
+9 -7
View File
@@ -146,9 +146,11 @@ def arc_bar_pts(cx: float, cy: float,
class TorqueBar(Widget):
def __init__(self, demo: bool = False):
def __init__(self, demo: bool = False, scale: float = 1.0, always: bool = False):
super().__init__()
self._demo = demo
self._scale = scale
self._always = always
self._torque_filter = FirstOrderFilter(0, 0.1, 1 / gui_app.target_fps)
self._torque_line_alpha_filter = FirstOrderFilter(0.0, 0.1, 1 / gui_app.target_fps)
@@ -180,8 +182,8 @@ class TorqueBar(Widget):
def _render(self, rect: rl.Rectangle) -> None:
# adjust y pos with torque
torque_line_offset = np.interp(abs(self._torque_filter.x), [0.5, 1], [22, 26])
torque_line_height = np.interp(abs(self._torque_filter.x), [0.5, 1], [14, 56])
torque_line_offset = np.interp(abs(self._torque_filter.x), [0.5, 1], [22 * self._scale, 26 * self._scale])
torque_line_height = np.interp(abs(self._torque_filter.x), [0.5, 1], [14 * self._scale, 56 * self._scale])
# animate alpha and angle span
if not self._demo:
@@ -195,7 +197,7 @@ class TorqueBar(Widget):
torque_line_bg_color = rl.Color(255, 255, 255, int(255 * 0.15 * self._torque_line_alpha_filter.x))
# draw curved line polygon torque bar
torque_line_radius = 1200
torque_line_radius = 1200 * self._scale
top_angle = -90
torque_bg_angle_span = self._torque_line_alpha_filter.x * TORQUE_ANGLE_SPAN
torque_start_angle = top_angle - torque_bg_angle_span / 2
@@ -207,13 +209,13 @@ class TorqueBar(Widget):
cy = rect.y + rect.height + torque_line_radius - torque_line_offset
# draw bg torque indicator line
bg_pts = arc_bar_pts(cx, cy, mid_r, torque_line_height, torque_start_angle, torque_end_angle)
bg_pts = arc_bar_pts(cx, cy, mid_r, torque_line_height, torque_start_angle, torque_end_angle, cap_radius=7 * self._scale)
draw_polygon(rect, bg_pts, color=torque_line_bg_color)
# draw torque indicator line
a0s = top_angle
a1s = a0s + torque_bg_angle_span / 2 * self._torque_filter.x
sl_pts = arc_bar_pts(cx, cy, mid_r, torque_line_height, a0s, a1s)
sl_pts = arc_bar_pts(cx, cy, mid_r, torque_line_height, a0s, a1s, cap_radius=7 * self._scale)
# draw beautiful gradient from center to 65% of the bg torque bar width
start_grad_pt = cx / rect.width
@@ -252,5 +254,5 @@ class TorqueBar(Widget):
# draw center torque bar dot
if abs(self._torque_filter.x) < 0.5:
dot_y = self._rect.y + self._rect.height - torque_line_offset - torque_line_height / 2
rl.draw_circle(int(cx), int(dot_y), 10 // 2,
rl.draw_circle(int(cx), int(dot_y), (10 // 2 * self._scale),
rl.Color(182, 182, 182, int(255 * 0.9 * self._torque_line_alpha_filter.x)))
+5 -3
View File
@@ -15,7 +15,7 @@ from openpilot.common.transformations.camera import DEVICE_CAMERAS, DeviceCamera
from openpilot.common.transformations.orientation import rot_from_euler
if gui_app.sunnypilot_ui():
from openpilot.selfdrive.ui.sunnypilot.onroad.augmented_road_view import BORDER_COLORS_SP
from openpilot.selfdrive.ui.sunnypilot.onroad.augmented_road_view import BORDER_COLORS_SP, AugmentedRoadViewSP
from openpilot.selfdrive.ui.sunnypilot.onroad.driver_state import DriverStateRendererSP as DriverStateRenderer
from openpilot.selfdrive.ui.sunnypilot.onroad.hud_renderer import HudRendererSP as HudRenderer
from openpilot.selfdrive.ui.sunnypilot.ui_state import OnroadTimerStatus
@@ -38,9 +38,10 @@ ROAD_CAM_MIN_SPEED = 15.0 # m/s (34 mph)
INF_POINT = np.array([1000.0, 0.0, 0.0])
class AugmentedRoadView(CameraView):
class AugmentedRoadView(CameraView, AugmentedRoadViewSP):
def __init__(self, stream_type: VisionStreamType = VisionStreamType.VISION_STREAM_ROAD):
super().__init__("camerad", stream_type)
CameraView.__init__(self, "camerad", stream_type)
AugmentedRoadViewSP.__init__(self)
self._set_placeholder_color(BORDER_COLORS[UIStatus.DISENGAGED])
self.device_camera: DeviceCameraConfig | None = None
@@ -92,6 +93,7 @@ class AugmentedRoadView(CameraView):
# Draw all UI overlays
self.model_renderer.render(self._content_rect)
AugmentedRoadViewSP.update_fade_out_bottom_overlay(self, self._content_rect)
self._hud_renderer.render(self._content_rect)
self.alert_renderer.render(self._content_rect)
self.driver_state_renderer.render(self._content_rect)
@@ -5,9 +5,18 @@ 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
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.multilang import tr, tr_noop
from openpilot.system.ui.sunnypilot.widgets.list_view import toggle_item_sp, multiple_button_item_sp
from openpilot.system.ui.widgets.scroller_tici import Scroller
from openpilot.system.ui.widgets import Widget
CHEVRON_INFO_DESCRIPTION = {
"enabled": tr_noop("Display useful metrics below the chevron that tracks the lead car " +
"only applicable to cars with sunnypilot longitudinal control."),
"disabled": tr_noop("This feature requires sunnypilot longitudinal control to be available.")
}
class VisualsLayout(Widget):
def __init__(self):
@@ -18,13 +27,128 @@ class VisualsLayout(Widget):
self._scroller = Scroller(items, line_separator=True, spacing=0)
def _initialize_items(self):
items = [
self._toggle_defs = {
"BlindSpot": (
lambda: tr("Show Blind Spot Warnings"),
tr("Enabling this will display warnings when a vehicle is detected in your " +
"blind spot as long as your car has BSM supported."),
None,
),
"TorqueBar": (
lambda: tr("Steering Arc"),
tr("Display steering arc on the driving screen when lateral control is enabled."),
None,
),
"RainbowMode": (
lambda: tr("Enable Tesla Rainbow Mode"),
tr("A beautiful rainbow effect on the path the model wants to take. " +
"It does not affect driving in any way."),
None,
),
"StandstillTimer": (
lambda: tr("Enable Standstill Timer"),
tr("Show a timer on the HUD when the car is at a standstill."),
None,
),
"RoadNameToggle": (
lambda: tr("Display Road Name"),
tr("Displays the name of the road the car is traveling on." +
"<br>The OpenStreetMap database of the location must be downloaded from " +
"the OSM panel to fetch the road name."),
None,
),
"GreenLightAlert": (
lambda: tr("Green Traffic Light Alert (Beta)"),
tr("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." +
"<br>Note: This chime is only designed as a notification. " +
"It is the driver's responsibility to observe their environment and make decisions accordingly."),
None,
),
"LeadDepartAlert": (
lambda: tr("Lead Departure Alert (Beta)"),
tr("A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving." +
"<br>Note: This chime is only designed as a notification. " +
"It is the driver's responsibility to observe their environment and make decisions accordingly."),
None,
),
"TrueVEgoUI": (
lambda: tr("Speedometer: Always Display True Speed"),
tr("For applicable vehicles, always display the true vehicle current speed from wheel speed sensors."),
None,
),
"HideVEgoUI": (
lambda: tr("Speedometer: Hide from Onroad Screen"),
tr("When enabled, the speedometer on the onroad screen is not displayed."),
None,
),
"ShowTurnSignals": (
lambda: tr("Display Turn Signals"),
tr("When enabled, visual turn indicators are drawn on the HUD."),
None,
),
"RocketFuel": (
lambda: tr("Real-time Acceleration Bar"),
tr("Show an indicator on the left side of the screen to display real-time vehicle acceleration and deceleration. " +
"This displays what the car is currently doing, not what the planner is requesting."),
None,
),
}
self._toggles = {}
for param, (title, desc, callback) in self._toggle_defs.items():
toggle = toggle_item_sp(
title=title,
description=desc,
param=param,
initial_state=ui_state.params.get_bool(param),
callback=callback,
)
self._toggles[param] = toggle
self._chevron_info = multiple_button_item_sp(
title=lambda: tr("Display Metrics Below Chevron"),
description="",
buttons=[lambda: tr("Off"), lambda: tr("Distance"), lambda: tr("Speed"), lambda: tr("Time"), lambda: tr("All")],
param="ChevronInfo",
inline=False
)
self._dev_ui_info = multiple_button_item_sp(
title=lambda: tr("Developer UI"),
description=lambda: tr("Display real-time parameters and metrics from various sources."),
buttons=[lambda: tr("Off"), lambda: tr("Bottom"), lambda: tr("Right"), lambda: tr("Right & Bottom")],
param="DevUIInfo",
button_width=350,
inline=False
)
items = list(self._toggles.values()) + [
self._chevron_info,
self._dev_ui_info,
]
return items
def _update_state(self):
super()._update_state()
for param in self._toggle_defs:
self._toggles[param].action_item.set_state(self._params.get_bool(param))
self._dev_ui_info.action_item.set_selected_button(ui_state.params.get("DevUIInfo", return_default=True))
if ui_state.has_longitudinal_control:
self._chevron_info.set_description(tr(CHEVRON_INFO_DESCRIPTION["enabled"]))
self._chevron_info.action_item.set_selected_button(ui_state.params.get("ChevronInfo", return_default=True))
self._chevron_info.action_item.set_enabled(True)
else:
self._chevron_info.set_description(tr(CHEVRON_INFO_DESCRIPTION["disabled"]))
self._chevron_info.action_item.set_enabled(False)
ui_state.params.put("ChevronInfo", 0)
def _render(self, rect):
self._scroller.render(rect)
def show_event(self):
self._scroller.show_event()
if not ui_state.has_longitudinal_control:
self._chevron_info.set_description(tr(CHEVRON_INFO_DESCRIPTION["disabled"]))
self._chevron_info.show_description(True)
@@ -0,0 +1,122 @@
"""
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 collections.abc import Callable
from cereal import custom
from openpilot.selfdrive.ui.mici.widgets.button import BigButton
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets import NavWidget, Widget
from openpilot.system.ui.widgets.scroller import Scroller
class ModelsLayoutMici(NavWidget):
def __init__(self, back_callback: Callable):
super().__init__()
self.set_back_callback(back_callback)
self.original_back_callback = back_callback
self.focused_widget = None
self.current_model_btn = BigButton(tr("current model"), "", "")
self.current_model_btn.set_click_callback(self._show_folders)
self.cancel_download_btn = BigButton(tr("cancel download"), "", "")
self.cancel_download_btn.set_click_callback(lambda: ui_state.params.remove("ModelManager_DownloadIndex"))
self.main_items: list[Widget] = [self.current_model_btn, self.cancel_download_btn]
self._scroller = Scroller(self.main_items, snap_items=False)
@property
def model_manager(self):
return ui_state.sm["modelManagerSP"]
def _get_grouped_bundles(self):
bundles = self.model_manager.availableBundles
folders = {}
for bundle in bundles:
folder = next((override.value for override in bundle.overrides if override.key == "folder"), "")
folders.setdefault(folder, []).append(bundle)
return folders
def _show_selection_view(self, items: list[Widget], back_callback: Callable):
self._scroller._items = items
for item in items:
item.set_touch_valid_callback(lambda: self._scroller.scroll_panel.is_touch_valid() and self._scroller.enabled)
self._scroller.scroll_panel.set_offset(0)
self.set_back_callback(back_callback)
def _show_folders(self):
self.focused_widget = self.current_model_btn
folders = self._get_grouped_bundles()
folder_buttons = []
default_btn = BigButton(tr("default model"), "", "")
default_btn.set_click_callback(self._select_default)
folder_buttons.append(default_btn)
for folder in sorted(folders.keys(), key=lambda f: max((bundle.index for bundle in folders[f]), default=-1), reverse=True):
if folder.lower() in ["release models", "master models"]:
btn = BigButton(folder.lower(), "", "")
btn.set_click_callback(lambda f=folder: self._select_folder(f))
folder_buttons.append(btn)
self._show_selection_view(folder_buttons, self._reset_main_view)
def _select_model(self, bundle):
ui_state.params.put("ModelManager_DownloadIndex", bundle.index)
self._reset_main_view()
def _select_default(self):
ui_state.params.remove("ModelManager_ActiveBundle")
self._reset_main_view()
def _select_folder(self, folder_name):
folders = self._get_grouped_bundles()
bundles = sorted(folders.get(folder_name, []), key=lambda b: b.index, reverse=True)
btns = []
for bundle in bundles:
txt = bundle.displayName.lower()
btn = BigButton(txt, "", "")
btn.set_click_callback(lambda b=bundle: self._select_model(b))
btns.append(btn)
self._show_selection_view(btns, self._show_folders)
def _reset_main_view(self):
self._scroller._items = self.main_items
self.set_back_callback(self.original_back_callback)
if self.focused_widget and self.focused_widget in self.main_items:
x = self._scroller._pad_start
for item in self.main_items:
if not item.is_visible:
continue
if item == self.focused_widget:
break
x += item.rect.width + self._scroller._spacing
self._scroller.scroll_panel.set_offset(0)
self._scroller.scroll_to(x)
self.focused_widget = None
else:
self._scroller.scroll_panel.set_offset(0)
def _update_state(self):
super()._update_state()
manager = self.model_manager
if manager.selectedBundle and manager.selectedBundle.status == custom.ModelManagerSP.DownloadStatus.downloading:
self.current_model_btn.set_value("downloading...")
self.cancel_download_btn.set_visible(True)
else:
self.current_model_btn.set_value(manager.activeBundle.internalName.lower() if manager.activeBundle else tr("default model"))
self.cancel_download_btn.set_visible(False)
self.current_model_btn.set_enabled(ui_state.is_offroad())
self.current_model_btn.set_text(tr("current model"))
def _render(self, rect):
self._scroller.render(rect)
def show_event(self):
super().show_event()
self._scroller.show_event()
@@ -9,6 +9,7 @@ from enum import IntEnum
from openpilot.selfdrive.ui.mici.layouts.settings import settings as OP
from openpilot.selfdrive.ui.mici.widgets.button import BigButton
from openpilot.selfdrive.ui.sunnypilot.mici.layouts.sunnylink import SunnylinkLayoutMici
from openpilot.selfdrive.ui.sunnypilot.mici.layouts.models import ModelsLayoutMici
ICON_SIZE = 70
@@ -16,6 +17,7 @@ OP.PanelType = IntEnum(
"PanelType",
[es.name for es in OP.PanelType] + [
"SUNNYLINK",
"MODELS",
],
start=0,
)
@@ -27,13 +29,19 @@ class SettingsLayoutSP(OP.SettingsLayout):
sunnylink_btn = BigButton("sunnylink", "", "icons_mici/settings/developer/ssh.png")
sunnylink_btn.set_click_callback(lambda: self._set_current_panel(OP.PanelType.SUNNYLINK))
models_btn = BigButton("models", "", "../../sunnypilot/selfdrive/assets/offroad/icon_models.png")
models_btn.set_click_callback(lambda: self._set_current_panel(OP.PanelType.MODELS))
self._panels.update({
OP.PanelType.SUNNYLINK: OP.PanelInfo("sunnylink", SunnylinkLayoutMici(back_callback=lambda: self._set_current_panel(None))),
OP.PanelType.MODELS: OP.PanelInfo("models", ModelsLayoutMici(back_callback=lambda: self._set_current_panel(None))),
})
items = self._scroller._items.copy()
items.insert(1, sunnylink_btn)
items.insert(2, models_btn)
self._scroller._items.clear()
for item in items:
self._scroller.add_widget(item)
@@ -5,9 +5,27 @@ 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 pyray as rl
from openpilot.selfdrive.ui.ui_state import UIStatus
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.selfdrive.ui.ui_state import UIStatus, ui_state
from openpilot.system.ui.lib.application import gui_app
BORDER_COLORS_SP = {
UIStatus.LAT_ONLY: rl.Color(0x00, 0xC8, 0xC8, 0xFF), # Cyan for lateral-only state
UIStatus.LONG_ONLY: rl.Color(0x96, 0x1C, 0xA8, 0xFF), # Purple for longitudinal-only state
}
class AugmentedRoadViewSP:
def __init__(self):
self._fade_texture = gui_app.texture("icons_mici/onroad/onroad_fade.png")
self._fade_alpha_filter = FirstOrderFilter(0, 0.1, 1 / gui_app.target_fps)
def update_fade_out_bottom_overlay(self, _content_rect):
# Fade out bottom of overlays for looks (only when engaged)
fade_alpha = self._fade_alpha_filter.update(ui_state.status != UIStatus.DISENGAGED)
if ui_state.torque_bar and fade_alpha > 1e-2:
# Scale the fade texture to the content rect
rl.draw_texture_pro(self._fade_texture,
rl.Rectangle(0, 0, self._fade_texture.width, self._fade_texture.height),
_content_rect, rl.Vector2(0, 0), 0.0,
rl.Color(255, 255, 255, int(255 * fade_alpha)))
@@ -31,6 +31,9 @@ class BlindSpotIndicators:
return self._blind_spot_left_alpha_filter.x > 0.01 or self._blind_spot_right_alpha_filter.x > 0.01
def render(self, rect: rl.Rectangle) -> None:
if not ui_state.blindspot:
return
BLIND_SPOT_MARGIN_X = 20 # Distance from edge of screen
BLIND_SPOT_Y_OFFSET = 100 # Distance from top of screen
@@ -0,0 +1,140 @@
"""
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 pyray as rl
from cereal import log
from openpilot.selfdrive.ui import UI_BORDER_SIZE
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.selfdrive.ui.sunnypilot.onroad.developer_ui import DeveloperUiRenderer
from openpilot.system.ui.lib.application import gui_app, FontWeight, FONT_SCALE
from openpilot.system.ui.lib.text_measure import measure_text_cached
class CircularAlertsRenderer:
def __init__(self):
self._green_light_alert_img = gui_app.texture("../../sunnypilot/selfdrive/assets/images/green_light.png", 250, 250)
self._lead_depart_alert_img = gui_app.texture("../../sunnypilot/selfdrive/assets/images/lead_depart.png", 250, 250)
self._e2e_alert_display_timer = 0
self._e2e_alert_frame = 0
self._green_light_alert = False
self._lead_depart_alert = False
self._standstill_elapsed_time = 0.0
self._is_standstill = False
self._alert_text = ""
self._alert_img = None
self._allow_e2e_alerts = False
def update(self) -> None:
sm = ui_state.sm
lp_sp = sm['longitudinalPlanSP']
car_state = sm['carState']
self._green_light_alert = lp_sp.e2eAlerts.greenLightAlert
self._lead_depart_alert = lp_sp.e2eAlerts.leadDepartAlert
self._is_standstill = car_state.standstill
if not ui_state.started:
self._standstill_elapsed_time = 0.0
self._allow_e2e_alerts = sm['selfdriveState'].alertSize == log.SelfdriveState.AlertSize.none and \
sm.recv_frame['driverStateV2'] > ui_state.started_frame
if self._green_light_alert or self._lead_depart_alert:
self._e2e_alert_display_timer = 3 * gui_app.target_fps
# reset onroad sleep timer for e2e alerts
ui_state.reset_onroad_sleep_timer()
if self._e2e_alert_display_timer > 0:
self._e2e_alert_frame += 1
self._e2e_alert_display_timer -= 1
if self._green_light_alert:
self._alert_text = "GREEN\nLIGHT"
self._alert_img = self._green_light_alert_img
elif self._lead_depart_alert:
self._alert_text = "LEAD VEHICLE\nDEPARTING"
self._alert_img = self._lead_depart_alert_img
elif ui_state.standstill_timer and self._is_standstill:
self._alert_img = None
self._standstill_elapsed_time += 1.0 / gui_app.target_fps
minute = int(self._standstill_elapsed_time / 60)
second = int(self._standstill_elapsed_time - (minute * 60))
self._alert_text = f"{minute:01d}:{second:02d}"
self._e2e_alert_frame += 1
else:
self._e2e_alert_frame = 0
if not self._is_standstill:
self._standstill_elapsed_time = 0.0
def render(self, rect: rl.Rectangle) -> None:
if not self._allow_e2e_alerts or (self._e2e_alert_display_timer <= 0 and not (ui_state.standstill_timer and self._is_standstill)):
return
e2e_alert_size = 250
dev_ui_width_adjustment = 180 if ui_state.developer_ui in (DeveloperUiRenderer.DEV_UI_RIGHT, DeveloperUiRenderer.DEV_UI_BOTH) else 100
x = rect.x + rect.width - e2e_alert_size - dev_ui_width_adjustment - (UI_BORDER_SIZE * 3)
y = rect.y + rect.height / 2 + 20
alert_rect = rl.Rectangle(x - e2e_alert_size, y - e2e_alert_size, e2e_alert_size * 2, e2e_alert_size * 2)
center = rl.Vector2(alert_rect.x + alert_rect.width / 2, alert_rect.y + alert_rect.height / 2)
# Pulse logic
is_pulsing = (self._e2e_alert_frame % gui_app.target_fps) < (gui_app.target_fps / 2.5)
# Standstill Timer (STOPPED) should be static white
if self._e2e_alert_display_timer == 0 and ui_state.standstill_timer and self._is_standstill:
frame_color = rl.Color(255, 255, 255, 75)
else:
frame_color = rl.Color(255, 255, 255, 75) if is_pulsing else rl.Color(0, 255, 0, 75)
# Draw Circle
rl.draw_circle_v(center, e2e_alert_size, rl.Color(0, 0, 0, 190))
# Draw Ring (Border)
rl.draw_ring(center, e2e_alert_size - 7.5, e2e_alert_size + 7.5, 0, 360, 0, frame_color)
# Draw Image
if self._alert_img and self._e2e_alert_display_timer > 0:
img_x = int(center.x - self._alert_img.width / 2)
img_y = int(center.y - self._alert_img.height / 2)
rl.draw_texture(self._alert_img, img_x, img_y, rl.WHITE)
# Draw Text
txt_color = rl.Color(255, 255, 255, 255) if is_pulsing else rl.Color(0, 255, 0, 190)
font = gui_app.font(FontWeight.BOLD)
text_size = 48
spacing = 0
lines = self._alert_text.split('\n')
# Position text at bottom of alert circle
bottom_y = (alert_rect.y + alert_rect.height) - (alert_rect.height / 7)
# Draw lines upwards from bottom
current_y = bottom_y - (len(lines) * text_size * FONT_SCALE)
if self._e2e_alert_display_timer == 0 and ui_state.standstill_timer and self._is_standstill:
# Standstill Timer Text
alert_alt_text = "STOPPED"
top_text_size = 80
measure_top = measure_text_cached(font, alert_alt_text, top_text_size, spacing)
top_y = alert_rect.y + alert_rect.height / 3.5
rl.draw_text_ex(font, alert_alt_text, rl.Vector2(center.x - measure_top.x / 2, top_y), top_text_size, spacing, rl.Color(255, 175, 3, 240))
# Timer
timer_text_size = 100
measure_timer = measure_text_cached(font, self._alert_text, timer_text_size, spacing)
timer_y = (alert_rect.y + alert_rect.height) - (alert_rect.height / 5) - measure_timer.y
rl.draw_text_ex(font, self._alert_text, rl.Vector2(center.x - measure_timer.x / 2, timer_y), timer_text_size, spacing, rl.WHITE)
else:
for line in lines:
measure = measure_text_cached(font, line, text_size, spacing)
line_x = center.x - measure.x / 2
rl.draw_text_ex(font, line, rl.Vector2(line_x, current_y), text_size, spacing, txt_color)
current_y += text_size * FONT_SCALE
@@ -10,7 +10,7 @@ from openpilot.selfdrive.ui.sunnypilot.onroad.developer_ui.elements import (
UiElement, RelDistElement, RelSpeedElement, SteeringAngleElement,
DesiredLateralAccelElement, ActualLateralAccelElement, DesiredSteeringAngleElement,
AEgoElement, LeadSpeedElement, FrictionCoefficientElement, LatAccelFactorElement,
SteeringTorqueEpsElement, BearingDegElement, AltitudeElement
SteeringTorqueEpsElement, BearingDegElement, AltitudeElement, DesiredSteeringPIDElement
)
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.text_measure import measure_text_cached
@@ -36,6 +36,7 @@ class DeveloperUiRenderer(Widget):
self.desired_lat_accel_elem = DesiredLateralAccelElement()
self.actual_lat_accel_elem = ActualLateralAccelElement()
self.desired_steer_elem = DesiredSteeringAngleElement()
self.desired_pid_steer_elem = DesiredSteeringPIDElement()
self.a_ego_elem = AEgoElement()
self.lead_speed_elem = LeadSpeedElement()
self.friction_elem = FrictionCoefficientElement()
@@ -85,8 +86,10 @@ class DeveloperUiRenderer(Widget):
]
if controls_state.lateralControlState.which() == 'torqueState':
elements.append(self.desired_lat_accel_elem.update(sm, ui_state.is_metric))
else:
elif controls_state.lateralControlState.which() == 'angleState':
elements.append(self.desired_steer_elem.update(sm, ui_state.is_metric))
elif controls_state.lateralControlState.which() == 'pidState':
elements.append(self.desired_pid_steer_elem.update(sm, ui_state.is_metric))
elements.append(self.actual_lat_accel_elem.update(sm, ui_state.is_metric))
@@ -191,6 +191,31 @@ class DesiredLateralAccelElement(LateralControlElement):
return UiElement(value, "DESIRED L.A.", self.unit, color)
class DesiredSteeringPIDElement(LateralControlElement):
def __init__(self):
self.unit = ""
def update(self, sm, is_metric: bool) -> UiElement:
car_state = sm['carState']
controls_state = sm['controlsState']
lat_active = sm['carControl'].latActive
angle_steers = car_state.steeringAngleDeg
steer_angle_desired = controls_state.lateralControlState.pidState.steeringAngleDesiredDeg
value = f"{steer_angle_desired:.1f}°" if lat_active else "-"
color = rl.WHITE
if lat_active:
if abs(angle_steers) > 180:
color = rl.RED
elif abs(angle_steers) > 90:
color = rl.Color(255, 188, 0, 255)
else:
color = rl.Color(0, 255, 0, 255)
return UiElement(value, "DESIRED STEER", self.unit, color)
class AEgoElement:
def __init__(self):
self.unit = "m/s^2"
+24 -3
View File
@@ -6,13 +6,17 @@ See the LICENSE.md file in the root directory for more details.
"""
import pyray as rl
from openpilot.selfdrive.ui.mici.onroad.torque_bar import TorqueBar
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.selfdrive.ui.onroad.hud_renderer import HudRenderer
from openpilot.selfdrive.ui.sunnypilot.onroad.developer_ui import DeveloperUiRenderer
from openpilot.selfdrive.ui.sunnypilot.onroad.road_name import RoadNameRenderer
from openpilot.selfdrive.ui.sunnypilot.onroad.rocket_fuel import RocketFuel
from openpilot.selfdrive.ui.sunnypilot.onroad.speed_limit import SpeedLimitRenderer
from openpilot.selfdrive.ui.sunnypilot.onroad.smart_cruise_control import SmartCruiseControlRenderer
from openpilot.selfdrive.ui.sunnypilot.onroad.turn_signal import TurnSignalController
from openpilot.selfdrive.ui.sunnypilot.onroad.circular_alerts import CircularAlertsRenderer
from openpilot.selfdrive.ui.sunnypilot.onroad.speed_renderer import SpeedRenderer
class HudRendererSP(HudRenderer):
@@ -22,20 +26,37 @@ class HudRendererSP(HudRenderer):
self.road_name_renderer = RoadNameRenderer()
self.rocket_fuel = RocketFuel()
self.speed_limit_renderer = SpeedLimitRenderer()
self.smart_cruise_control_renderer = SmartCruiseControlRenderer()
self.turn_signal_controller = TurnSignalController()
self.circular_alerts_renderer = CircularAlertsRenderer()
self.speed_renderer = SpeedRenderer()
self._torque_bar = TorqueBar(scale=3.0, always=True)
def _update_state(self) -> None:
super()._update_state()
self.road_name_renderer.update()
self.speed_limit_renderer.update()
self.smart_cruise_control_renderer.update()
self.turn_signal_controller.update()
self.circular_alerts_renderer.update()
self.speed_renderer.update()
def _draw_current_speed(self, rect: rl.Rectangle) -> None:
self.speed_renderer.render(rect)
def _render(self, rect: rl.Rectangle) -> None:
super()._render(rect)
if ui_state.torque_bar and ui_state.sm['controlsState'].lateralControlState.which() != 'angleState':
torque_rect = rect
if ui_state.developer_ui in (DeveloperUiRenderer.DEV_UI_BOTTOM, DeveloperUiRenderer.DEV_UI_BOTH):
torque_rect = rl.Rectangle(rect.x, rect.y, rect.width, rect.height - DeveloperUiRenderer.BOTTOM_BAR_HEIGHT)
self._torque_bar.render(torque_rect)
self.developer_ui.render(rect)
self.road_name_renderer.render(rect)
self.speed_limit_renderer.render(rect)
self.smart_cruise_control_renderer.render(rect)
self.turn_signal_controller.render(rect)
if ui_state.rocket_fuel:
self.rocket_fuel.render(rect, ui_state.sm)
self.circular_alerts_renderer.render(rect)
self.rocket_fuel.render(rect, ui_state.sm)
+1 -1
View File
@@ -31,7 +31,7 @@ class RoadNameRenderer(Widget):
self.road_name = lmd.roadName
def _render(self, rect: rl.Rectangle):
if not self.road_name:
if not self.road_name or not ui_state.road_name_toggle:
return
text = self.road_name
@@ -6,12 +6,17 @@ See the LICENSE.md file in the root directory for more details.
"""
import pyray as rl
from openpilot.selfdrive.ui.ui_state import ui_state
class RocketFuel:
def __init__(self):
self.vc_accel = 0.0
def render(self, rect: rl.Rectangle, sm) -> None:
if not ui_state.rocket_fuel:
return
vc_accel0 = sm['carState'].aEgo
# Smooth the acceleration
@@ -0,0 +1,131 @@
"""
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 pyray as rl
from openpilot.selfdrive.ui.onroad.hud_renderer import COLORS
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.text_measure import measure_text_cached
from openpilot.system.ui.widgets import Widget
class SmartCruiseControlRenderer(Widget):
def __init__(self):
super().__init__()
self.vision_enabled = False
self.vision_active = False
self.vision_frame = 0
self.map_enabled = False
self.map_active = False
self.map_frame = 0
self.long_override = False
self.font = gui_app.font(FontWeight.BOLD)
self.scc_tex = rl.load_render_texture(256, 128)
def update(self):
sm = ui_state.sm
if sm.updated["longitudinalPlanSP"]:
lp_sp = sm["longitudinalPlanSP"]
vision = lp_sp.smartCruiseControl.vision
map_ = lp_sp.smartCruiseControl.map
self.vision_enabled = vision.enabled
self.vision_active = vision.active
self.map_enabled = map_.enabled
self.map_active = map_.active
if sm.updated["carControl"]:
self.long_override = sm["carControl"].cruiseControl.override
if self.vision_active:
self.vision_frame += 1
else:
self.vision_frame = 0
if self.map_active:
self.map_frame += 1
else:
self.map_frame = 0
@staticmethod
def _pulse_element(frame):
return not (frame % gui_app.target_fps < (gui_app.target_fps / 2.5))
def _draw_icon(self, rect_center_x, rect_height, x_offset, y_offset, name):
text = name
font_size = 36
padding_v = 5
box_width = 160
sz = measure_text_cached(self.font, text, font_size)
box_height = int(sz.y + padding_v * 2)
texture_width = 256
texture_height = 128
rl.begin_texture_mode(self.scc_tex)
rl.clear_background(rl.Color(0, 0, 0, 0))
if self.long_override:
box_color = COLORS.OVERRIDE
else:
box_color = rl.Color(0, 255, 0, 255)
# Center box in texture
box_x = (texture_width - box_width) // 2
box_y = (texture_height - box_height) // 2
rl.draw_rectangle_rounded(rl.Rectangle(box_x, box_y, box_width, box_height), 0.2, 10, box_color)
# Draw text with custom blend mode to punch hole
rl.rl_set_blend_factors(rl.RL_ZERO, rl.RL_ONE_MINUS_SRC_ALPHA, 0x8006)
rl.rl_set_blend_mode(rl.BLEND_CUSTOM)
text_pos_x = box_x + (box_width - sz.x) / 2
text_pos_y = box_y + (box_height - sz.y) / 2
rl.draw_text_ex(self.font, text, rl.Vector2(text_pos_x, text_pos_y), font_size, 0, rl.WHITE)
rl.rl_set_blend_mode(rl.BLEND_ALPHA) # Reset
rl.end_texture_mode()
screen_y = rect_height / 4 + y_offset
dest_x = rect_center_x + x_offset - texture_width / 2
dest_y = screen_y - texture_height / 2
src_rect = rl.Rectangle(0, 0, texture_width, -texture_height)
dst_rect = rl.Rectangle(dest_x, dest_y, texture_width, texture_height)
rl.draw_texture_pro(self.scc_tex.texture, src_rect, dst_rect, rl.Vector2(0, 0), 0, rl.WHITE)
def _render(self, rect: rl.Rectangle):
x_offset = -260
y1_offset = -40
y2_offset = -100
orders = [y1_offset, y2_offset]
y_scc_v = 0
y_scc_m = 0
idx = 0
if self.vision_enabled:
y_scc_v = orders[idx]
idx += 1
if self.map_enabled:
y_scc_m = orders[idx]
idx += 1
scc_vision_pulse = self._pulse_element(self.vision_frame)
if (self.vision_enabled and not self.vision_active) or (self.vision_active and scc_vision_pulse):
self._draw_icon(rect.x + rect.width / 2, rect.height, x_offset, y_scc_v, "SCC-V")
scc_map_pulse = self._pulse_element(self.map_frame)
if (self.map_enabled and not self.map_active) or (self.map_active and scc_map_pulse):
self._draw_icon(rect.x + rect.width / 2, rect.height, x_offset, y_scc_m, "SCC-M")
@@ -0,0 +1,46 @@
"""
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 pyray as rl
from openpilot.common.constants import CV
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.lib.text_measure import measure_text_cached
from openpilot.selfdrive.ui.onroad.hud_renderer import FONT_SIZES, COLORS
class SpeedRenderer:
def __init__(self):
self.speed: float = 0.0
self.v_ego_cluster_seen: bool = False
self._font_bold: rl.Font = gui_app.font(FontWeight.BOLD)
self._font_medium: rl.Font = gui_app.font(FontWeight.MEDIUM)
def update(self) -> None:
car_state = ui_state.sm['carState']
v_ego_cluster = car_state.vEgoCluster
self.v_ego_cluster_seen = self.v_ego_cluster_seen or v_ego_cluster != 0.0
v_ego = v_ego_cluster if self.v_ego_cluster_seen and not ui_state.true_v_ego_ui else car_state.vEgo
speed_conversion = CV.MS_TO_KPH if ui_state.is_metric else CV.MS_TO_MPH
self.speed = max(0.0, v_ego * speed_conversion)
def render(self, rect: rl.Rectangle) -> None:
if ui_state.hide_v_ego_ui:
return
# Draw current speed and unit
speed_text = str(round(self.speed))
speed_text_size = measure_text_cached(self._font_bold, speed_text, FONT_SIZES.current_speed)
speed_pos = rl.Vector2(rect.x + rect.width / 2 - speed_text_size.x / 2, 180 - speed_text_size.y / 2)
rl.draw_text_ex(self._font_bold, speed_text, speed_pos, FONT_SIZES.current_speed, 0, COLORS.WHITE)
unit_text = tr("km/h") if ui_state.is_metric else tr("mph")
unit_text_size = measure_text_cached(self._font_medium, unit_text, FONT_SIZES.speed_unit)
unit_pos = rl.Vector2(rect.x + rect.width / 2 - unit_text_size.x / 2, 290 - unit_text_size.y / 2)
rl.draw_text_ex(self._font_medium, unit_text, unit_pos, FONT_SIZES.speed_unit, 0, COLORS.WHITE_TRANSLUCENT)
@@ -137,6 +137,9 @@ class TurnSignalController:
self._right_signal.deactivate()
def render(self, rect: rl.Rectangle):
if not ui_state.turn_signals:
return
x = rect.x + rect.width / 2
left_x = x - self._config.left_x - self._config.size
+13 -8
View File
@@ -120,18 +120,23 @@ class UIStateSP:
CP_SP_bytes = self.params.get("CarParamsSPPersistent")
if CP_SP_bytes is not None:
self.CP_SP = messaging.log_from_bytes(CP_SP_bytes, custom.CarParamsSP)
self.sunnylink_enabled = self.params.get_bool("SunnylinkEnabled")
self.developer_ui = self.params.get("DevUIInfo")
self.rocket_fuel = self.params.get_bool("RocketFuel")
self.rainbow_path = self.params.get_bool("RainbowMode")
self.chevron_metrics = self.params.get("ChevronInfo")
self.active_bundle = self.params.get("ModelManager_ActiveBundle")
self.blindspot = self.params.get_bool("BlindSpot")
self.chevron_metrics = self.params.get("ChevronInfo")
self.custom_interactive_timeout = self.params.get("InteractivityTimeout", return_default=True)
self.speed_limit_mode = self.params.get("SpeedLimitMode", return_default=True)
# Onroad Screen Brightness
self.developer_ui = self.params.get("DevUIInfo")
self.hide_v_ego_ui = self.params.get_bool("HideVEgoUI")
self.onroad_brightness = int(float(self.params.get("OnroadScreenOffBrightness", return_default=True)))
self.onroad_brightness_timer_param = self.params.get("OnroadScreenOffTimer", return_default=True)
self.rainbow_path = self.params.get_bool("RainbowMode")
self.road_name_toggle = self.params.get_bool("RoadNameToggle")
self.rocket_fuel = self.params.get_bool("RocketFuel")
self.speed_limit_mode = self.params.get("SpeedLimitMode", return_default=True)
self.standstill_timer = self.params.get_bool("StandstillTimer")
self.sunnylink_enabled = self.params.get_bool("SunnylinkEnabled")
self.torque_bar = self.params.get_bool("TorqueBar")
self.true_v_ego_ui = self.params.get_bool("TrueVEgoUI")
self.turn_signals = self.params.get_bool("ShowTurnSignals")
class DeviceSP:
+2 -2
View File
@@ -39,7 +39,7 @@ if PC:
model_dir = Dir("models").abspath
cmd = f'python3 {Dir("#sunnypilot/modeld_v2").abspath}/install_models_pc.py {model_dir}'
for model_name in ['supercombo', 'driving_vision', 'driving_policy']:
for model_name in ['supercombo', 'driving_vision', 'driving_off_policy', 'driving_policy']:
if File(f"models/{model_name}.onnx").exists():
inputs.append(File(f"models/{model_name}.onnx"))
inputs.append(File(f"models/{model_name}_tinygrad.pkl"))
@@ -57,7 +57,7 @@ def tg_compile(flags, model_name):
)
# Compile small models
for model_name in ['supercombo', 'driving_vision', 'driving_policy']:
for model_name in ['supercombo', 'driving_vision', 'driving_off_policy', 'driving_policy']:
if File(f"models/{model_name}.onnx").exists():
flags = {
'larch64': 'DEV=QCOM',
+1 -1
View File
@@ -44,7 +44,7 @@ def generate_metadata_pkl(model_path, output_path):
def install_models(model_dir):
model_dir = Path(model_dir)
models = ["driving_policy", "driving_vision"]
models = ["driving_off_policy", "driving_policy", "driving_vision"]
found_models = []
for model in models:
+1 -1
View File
@@ -116,7 +116,7 @@ class ModelCache:
class ModelFetcher:
"""Handles fetching and caching of model data from remote source"""
MODEL_URL = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-docs/refs/heads/gh-pages/docs/driving_models_v10.json"
MODEL_URL = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-docs/refs/heads/gh-pages/docs/driving_models_v11.json"
def __init__(self, params: Params):
self.params = params
@@ -13,6 +13,22 @@ SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
CUSTOM_MODEL_PATH = Paths.model_root()
class OffPolicyTinygrad(ModularRunner, ABC):
"""
A TinygradRunner specialized for off-policy models.
Uses a SplitParser to handle outputs specific to the off-policy part of a split model setup.
"""
def __init__(self):
self._off_policy_parser = SplitParser()
self.parser_method_dict[ModelType.offPolicy] = self._parse_off_policy_outputs
def _parse_off_policy_outputs(self, model_outputs: np.ndarray) -> NumpyDict:
"""Parses off-policy model outputs using SplitParser."""
result: NumpyDict = self._off_policy_parser.parse_policy_outputs(self._slice_outputs(model_outputs))
return result
class PolicyTinygrad(ModularRunner, ABC):
"""
A TinygradRunner specialized for policy-only models.
@@ -4,7 +4,7 @@ import numpy as np
from openpilot.sunnypilot.modeld_v2.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
from openpilot.sunnypilot.models.runners.constants import CLMemDict, FrameDict, NumpyDict, ModelType, ShapeDict, CUSTOM_MODEL_PATH, SliceDict
from openpilot.sunnypilot.models.runners.model_runner import ModelRunner
from openpilot.sunnypilot.models.runners.tinygrad.model_types import PolicyTinygrad, VisionTinygrad, SupercomboTinygrad
from openpilot.sunnypilot.models.runners.tinygrad.model_types import PolicyTinygrad, VisionTinygrad, SupercomboTinygrad, OffPolicyTinygrad
from openpilot.system.hardware import TICI
from openpilot.sunnypilot.models.split_model_constants import SplitModelConstants
from openpilot.sunnypilot.modeld_v2.constants import ModelConstants
@@ -12,7 +12,7 @@ from openpilot.sunnypilot.modeld_v2.constants import ModelConstants
from tinygrad.tensor import Tensor
class TinygradRunner(ModelRunner, SupercomboTinygrad, PolicyTinygrad, VisionTinygrad):
class TinygradRunner(ModelRunner, SupercomboTinygrad, PolicyTinygrad, VisionTinygrad, OffPolicyTinygrad):
"""
A ModelRunner implementation for executing Tinygrad models.
@@ -27,6 +27,7 @@ class TinygradRunner(ModelRunner, SupercomboTinygrad, PolicyTinygrad, VisionTiny
SupercomboTinygrad.__init__(self)
PolicyTinygrad.__init__(self)
VisionTinygrad.__init__(self)
OffPolicyTinygrad.__init__(self)
self._constants = ModelConstants
self._model_data = self.models.get(model_type)
if not self._model_data or not self._model_data.model:
@@ -106,13 +107,20 @@ class TinygradSplitRunner(ModelRunner):
self.is_20hz_3d = True
self.vision_runner = TinygradRunner(ModelType.vision)
self.policy_runner = TinygradRunner(ModelType.policy)
self.off_policy_runner = TinygradRunner(ModelType.offPolicy) if self.models.get(ModelType.offPolicy) else None
self._constants = SplitModelConstants
def _run_model(self) -> NumpyDict:
"""Runs both vision and policy models and merges their parsed outputs."""
policy_output = self.policy_runner.run_model()
vision_output = self.vision_runner.run_model()
return {**policy_output, **vision_output} # Combine results
outputs = {**policy_output, **vision_output}
if self.off_policy_runner:
off_policy_output = self.off_policy_runner.run_model()
outputs.update(off_policy_output)
return outputs
@property
def vision_input_names(self) -> list[str]:
@@ -122,12 +130,18 @@ class TinygradSplitRunner(ModelRunner):
@property
def input_shapes(self) -> ShapeDict:
"""Returns the combined input shapes from both vision and policy models."""
return {**self.policy_runner.input_shapes, **self.vision_runner.input_shapes}
shapes = {**self.policy_runner.input_shapes, **self.vision_runner.input_shapes}
if self.off_policy_runner:
shapes.update(self.off_policy_runner.input_shapes)
return shapes
@property
def output_slices(self) -> SliceDict:
"""Returns the combined output slices from both vision and policy models."""
return {**self.policy_runner.output_slices, **self.vision_runner.output_slices}
slices = {**self.policy_runner.output_slices, **self.vision_runner.output_slices}
if self.off_policy_runner:
slices.update(self.off_policy_runner.output_slices)
return slices
def prepare_inputs(self, imgs_cl: CLMemDict, numpy_inputs: NumpyDict, frames: FrameDict) -> dict:
"""Prepares inputs for both vision and policy models."""
@@ -135,5 +149,11 @@ class TinygradSplitRunner(ModelRunner):
self.policy_runner.prepare_policy_inputs(numpy_inputs)
# Vision inputs depend on imgs_cl and frames
self.vision_runner.prepare_vision_inputs(imgs_cl, frames)
inputs = {**self.policy_runner.inputs, **self.vision_runner.inputs}
if self.off_policy_runner:
self.off_policy_runner.prepare_policy_inputs(numpy_inputs)
inputs.update(self.off_policy_runner.inputs)
# Return combined inputs (though they are stored within respective runners)
return {**self.policy_runner.inputs, **self.vision_runner.inputs}
return inputs
+22 -18
View File
@@ -90,8 +90,8 @@
"description": ""
},
"BlindSpot": {
"title": "Blind Spot Detection",
"description": ""
"title": "[TIZI/TICI only] Blind Spot Detection",
"description": "Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported."
},
"BlinkerMinLateralControlSpeed": {
"title": "Blinker Min Lateral Control Speed",
@@ -339,8 +339,8 @@
"description": ""
},
"GreenLightAlert": {
"title": "Green Light Alert",
"description": ""
"title": "Green Traffic Light Alert (Beta)",
"description": "A chime and on-screen alert (TIZI/TICI only) will play when the traffic light you are waiting for turns green and you have no vehicle in front of you. <br>Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly."
},
"GsmApn": {
"title": "GSM APN",
@@ -367,8 +367,8 @@
"description": ""
},
"HideVEgoUI": {
"title": "Hide vEgo UI",
"description": ""
"title": "[TIZI/TICI only] Speedometer: Hide from Onroad Screen",
"description": "When enabled, the speedometer on the onroad screen is not displayed."
},
"HyundaiLongitudinalTuning": {
"title": "Hyundai Longitudinal Tuning",
@@ -585,8 +585,8 @@
"description": ""
},
"LeadDepartAlert": {
"title": "Lead Depart Alert",
"description": ""
"title": "Lead Departure Alert (Beta)",
"description": "A chime and on-screen alert (TIZI/TICI only) will play when you are stopped, and the vehicle in front of you start moving. <br>Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly."
},
"LiveDelay": {
"title": "Live Delay",
@@ -1079,12 +1079,12 @@
"description": ""
},
"RoadNameToggle": {
"title": "Display Road Name",
"description": ""
"title": "[TIZI/TICI only] Display Road Name",
"description": "Displays the name of the road the car is traveling on. <br>The OpenStreetMap database of the location must be downloaded to fetch the road name."
},
"RocketFuel": {
"title": "Display Rocket Fuel Bar",
"description": "Show an indicator on the left side of the screen to display real-time vehicle acceleration and deceleration."
"title": "[TIZI/TICI only] Real-time Acceleration Bar",
"description": "Show an indicator on the left side of the screen to display real-time vehicle acceleration and deceleration. This displays what the car is currently doing, not what the planner is requesting."
},
"RouteCount": {
"title": "Route Count",
@@ -1103,8 +1103,8 @@
"description": ""
},
"ShowTurnSignals": {
"title": "Show Turn Signals",
"description": ""
"title": "[TIZI/TICI only] Display Turn Signals",
"description": "When enabled, visual turn indicators are drawn on the HUD."
},
"SmartCruiseControlMap": {
"title": "Smart Cruise Control - Map",
@@ -1196,8 +1196,8 @@
"description": ""
},
"StandstillTimer": {
"title": "Standstill Timer",
"description": ""
"title": "[TIZI/TICI only] Standstill Timer",
"description": "Show a timer on the HUD when the car is at a standstill."
},
"SubaruStopAndGo": {
"title": "Subaru Stop and Go",
@@ -1239,6 +1239,10 @@
"title": "Tesla Coop Steering",
"description": ""
},
"TorqueBar": {
"title": "[TIZI/TICI only] Steering Arc",
"description": "Display steering arc on the driving screen when lateral control is enabled."
},
"TorqueParamsOverrideEnabled": {
"title": "Manual Real-Time Tuning",
"description": ""
@@ -1267,8 +1271,8 @@
"description": ""
},
"TrueVEgoUI": {
"title": "True vEgo UI",
"description": ""
"title": "[TIZI/TICI only] Speedometer: Always Display True Speed",
"description": "For applicable vehicles, always display the true vehicle current speed from wheel speed sensors."
},
"UbloxAvailable": {
"title": "Ublox Available",
+7
View File
@@ -20,6 +20,7 @@ from openpilot.system.athena.registration import register, UNREGISTERED_DONGLE_I
from openpilot.common.swaglog import cloudlog, add_file_handler
from openpilot.system.version import get_build_metadata
from openpilot.system.hardware.hw import Paths
from openpilot.system.hardware import PC
def manager_init() -> None:
@@ -39,6 +40,12 @@ def manager_init() -> None:
if params.get("DeviceBootMode") == 1: # start in Always Offroad mode
params.put_bool("OffroadMode", True)
# quick boot
if params.get_bool("QuickBootToggle") and not PC:
prebuilt_path = "/data/openpilot/prebuilt"
if not os.path.exists(prebuilt_path):
open(prebuilt_path, 'x').close()
if params.get_bool("RecordFrontLock"):
params.put_bool("RecordFront", True)