mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-20 15:54:13 +08:00
Subuwu
This commit is contained in:
@@ -208,7 +208,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"CECurves", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
|
||||
{"CECurvesLead", {PERSISTENT, BOOL, "0", "0", 1}},
|
||||
{"CELead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||
{"CEModelStopTime", {PERSISTENT, FLOAT, "9.0", "0.0", 2, SETTINGS_SIMPLE}},
|
||||
{"CEModelStopTime", {PERSISTENT, FLOAT, "7.7", "0.0", 2, SETTINGS_SIMPLE}},
|
||||
{"CESignalLaneDetection", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"CESignalSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
|
||||
{"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||
|
||||
+115
-10
@@ -1,24 +1,36 @@
|
||||
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
|
||||
|
||||
# Support Information for 384 Known Cars
|
||||
# Support Information for 489 Known Cars
|
||||
|
||||
|Make|Model|Package|Support Level|
|
||||
|---|---|---|:---:|
|
||||
|Acura|ADX 2025-26|All|[Upstream](#upstream)|
|
||||
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|[Upstream](#upstream)|
|
||||
|Acura|ILX 2019|All|[Upstream](#upstream)|
|
||||
|Acura|Integra 2023-25|All|[Community](#community)|
|
||||
|Acura|Integra 2023-26|All|[Upstream](#upstream)|
|
||||
|Acura|MDX 2014-16|Advance Package|[Upstream](#upstream)|
|
||||
|Acura|MDX 2015-16|Advance Package|[Community](#community)|
|
||||
|Acura|MDX 2017-19|All|[Upstream](#upstream)|
|
||||
|Acura|MDX 2017-20|All|[Community](#community)|
|
||||
|Acura|MDX 2020|All|[Upstream](#upstream)|
|
||||
|Acura|MDX 2022-24|All|[Upstream](#upstream)|
|
||||
|Acura|MDX 2022-24|All|[Community](#community)|
|
||||
|Acura|MDX 2025|All except Type S|[Upstream](#upstream)|
|
||||
|Acura|MDX Hybrid 2017-19|All|[Upstream](#upstream)|
|
||||
|Acura|MDX Hybrid 2020|All|[Upstream](#upstream)|
|
||||
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)|
|
||||
|Acura|RDX 2019-21|All|[Upstream](#upstream)|
|
||||
|Acura|RDX 2022-25|All|[Community](#community)|
|
||||
|Acura|RDX 2022-26|All|[Upstream](#upstream)|
|
||||
|Acura|RLX 2017|Advance Package or Technology Package|[Community](#community)|
|
||||
|Acura|TLX 2015-17|Advance Package|[Upstream](#upstream)|
|
||||
|Acura|TLX 2015-17|Advance Package|[Community](#community)|
|
||||
|Acura|TLX 2018-20|All|[Upstream](#upstream)|
|
||||
|Acura|TLX 2018-20|All|[Community](#community)|
|
||||
|Acura|TLX 2021|All|[Upstream](#upstream)|
|
||||
|Acura|TLX 2022-23|All|[Community](#community)|
|
||||
|Acura|TLX 2024-25|All|[Upstream](#upstream)|
|
||||
|Acura|ZDX 2024|All|[Not compatible](#can-bus-security)|
|
||||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
@@ -29,11 +41,37 @@
|
||||
|Audi|Q5 2017-24|All|[Not compatible](#flexray)|
|
||||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|[Upstream](#upstream)|
|
||||
|Buick|Baby Enclave 2020-23|Driver Assist Package|[Upstream](#upstream)|
|
||||
|Buick|LaCrosse ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Buick|LaCrosse US ASCM Harness 2019|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Cadillac|CT6 No-ACC 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Cadillac|Escalade ASCM Harness 2018|Driver Assist Package|[Upstream](#upstream)|
|
||||
|Cadillac|Escalade ESV Platinum ASCM Harness 2019|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|
||||
|Cadillac|XT4 No-ACC 2023|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Cadillac|XT5 No-ACC 2022|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Cadillac|XT6 2020|Driver Assist Package|[Upstream](#upstream)|
|
||||
|Chevrolet|Blazer 2019-25|Driver Assist Package|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EV & EUV ACC 2022-23|Premier or Premier Redline Trim without Super Cruise Package|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EV & EUV ACC w Pedal 2022-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EV & EUV No-ACC 2022-23|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EV No-ACC 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EV No-ACC 2018-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Equinox No-ACC 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Malibu 2019|SDGM Harness (Optional SASCM)|[Upstream](#upstream)|
|
||||
|Chevrolet|Malibu ASCM Harness 2017-19|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Malibu Hybrid No-ACC 2017|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Malibu No-ACC 2023|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|[Upstream](#upstream)|
|
||||
|Chevrolet|Silverado 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Suburban Premier 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Suburban Premier No-ACC 2016-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Trailblazer No-ACC 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|TRAX 2024|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Volt ASCM Harness 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Volt Camera Harness 2017-18|Flashed camera-forward integration with ACC|[Upstream](#upstream)|
|
||||
|Chevrolet|Volt No-ACC 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)|
|
||||
@@ -67,9 +105,11 @@
|
||||
|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|
||||
|Ford|Mustang Mach-E 2021-24|All|[Upstream](#upstream)|
|
||||
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||
|Ford|Transit 2025|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Genesis|G70 2018|All|[Upstream](#upstream)|
|
||||
|Genesis|G70 2019-21|All|[Upstream](#upstream)|
|
||||
|Genesis|G70 2022-23|All|[Upstream](#upstream)|
|
||||
|Genesis|G70 Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Genesis|G80 2017|All|[Upstream](#upstream)|
|
||||
|Genesis|G80 2018-19|All|[Upstream](#upstream)|
|
||||
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
@@ -78,14 +118,22 @@
|
||||
|Genesis|GV60 (Performance Trim) 2022-23|All|[Upstream](#upstream)|
|
||||
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|[Upstream](#upstream)|
|
||||
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|[Upstream](#upstream)|
|
||||
|Genesis|GV70 Electrified 2026|All|[Upstream](#upstream)|
|
||||
|Genesis|GV70 Electrified (Australia Only) 2022|All|[Upstream](#upstream)|
|
||||
|Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Genesis|GV80 2023|All|[Upstream](#upstream)|
|
||||
|Genesis|GV80 (3.5T Prestige Trim, with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||
|Genesis|GV80 Coupe (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||
|GMC|Acadia ASCM Harness 2018|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|GMC|Sierra 1500 2020-21|Driver Alert Package II|[Upstream](#upstream)|
|
||||
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Dashcam mode](#dashcam)|
|
||||
|GMC|Sierra 1500 No-ACC 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Upstream](#upstream)|
|
||||
|GMC|Yukon No-ACC 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Honda|Accord 2016-17|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Accord 2016-17|Honda Sensing|[Community](#community)|
|
||||
|Honda|Accord 2018-22|All|[Upstream](#upstream)|
|
||||
|Honda|Accord 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|Accord Hybrid 2017|All|[Upstream](#upstream)|
|
||||
|Honda|Accord Hybrid 2018-22|All|[Upstream](#upstream)|
|
||||
|Honda|Accord Hybrid 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|City (Brazil only) 2023|All|[Upstream](#upstream)|
|
||||
@@ -98,6 +146,7 @@
|
||||
|Honda|Civic Hatchback Hybrid 2025-26|All|[Upstream](#upstream)|
|
||||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|[Upstream](#upstream)|
|
||||
|Honda|Civic Hybrid 2025-26|All|[Upstream](#upstream)|
|
||||
|Honda|Clarity 2018-21|All|[Upstream](#upstream)|
|
||||
|Honda|Clarity 2018-21|All|[Community](#community)|
|
||||
|Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)|
|
||||
|Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)|
|
||||
@@ -106,6 +155,8 @@
|
||||
|Honda|CR-V Hybrid 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|e 2020|All|[Upstream](#upstream)|
|
||||
|Honda|Fit 2018-20|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Fit (Taiwan) 2021|All|[Upstream](#upstream)|
|
||||
|Honda|Fit (Taiwan) 2024-25|All|[Upstream](#upstream)|
|
||||
|Honda|Freed 2020|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|HR-V 2019-22|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|HR-V 2023-25|All|[Upstream](#upstream)|
|
||||
@@ -114,27 +165,40 @@
|
||||
|Honda|N-Box 2018|All|[Upstream](#upstream)|
|
||||
|Honda|Odyssey 2018-20|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Odyssey 2021-26|All|[Upstream](#upstream)|
|
||||
|Honda|Odyssey (Singapore) 2021|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Odyssey (Taiwan) 2018-19|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Passport 2019-25|All|[Upstream](#upstream)|
|
||||
|Honda|Passport 2026|All|[Upstream](#upstream)|
|
||||
|Honda|Pilot 2016-22|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Pilot 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|Prelude 2026|All|[Upstream](#upstream)|
|
||||
|Honda|Prologue 2024-25|All|[Not compatible](#can-bus-security)|
|
||||
|Honda|Ridgeline 2017-25|Honda Sensing|[Upstream](#upstream)|
|
||||
|Hyundai|Azera 2022|All|[Upstream](#upstream)|
|
||||
|Hyundai|Azera Hybrid 2019|All|[Upstream](#upstream)|
|
||||
|Hyundai|Azera Hybrid 2020|All|[Upstream](#upstream)|
|
||||
|Hyundai|Azera Hybrid (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||
|Hyundai|Bayon Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Custin 2023|All|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra Hybrid 2024-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|i30 Hybrid 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 5 N (with HDA II) 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 5 PE (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 9 (with HDA II & LFA2) 2025-26|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Electric 2020|All|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
@@ -143,40 +207,68 @@
|
||||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|[Upstream](#upstream)|
|
||||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Dashcam mode](#dashcam)|
|
||||
|Hyundai|Kona (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric (without HDA II) 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Hybrid (without HDA II) 2024|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Nexo 2021|All|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade 2020-22|All|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade 2023-24|HDA2|[Community](#community)|
|
||||
|Hyundai|Palisade (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade (without HDA II) 2023-25|Highway Driving Assist|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Cruz (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe 2019-20|All|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe 2021-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe Hybrid 2022-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe Hybrid (with HDA II & LFA2) 2024-25|Highway Driving Assist II & Lane Follow Assist 2|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe Hybrid (without HDA II, LFA2) 2025-26|Lane Follow Assist 2|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Sonata 2020-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Sonata (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Sonata Hybrid 2020-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Sonata Hybrid (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Staria 2023|All|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson 2023-24|All|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson (without HDA II) 2025-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson Hybrid 2022-24|All|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson Hybrid (without HDA II) 2025-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson Plug-in Hybrid 2024|All|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson Plug-in Hybrid (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Carnival 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Carnival (with HDA II) 2025|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Kia|Carnival Hybrid 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Carnival Hybrid 2026|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Carnival Hybrid (with HDA II) 2025-26|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Kia|EV6 (Southeast Asia only) 2022-24|All|[Upstream](#upstream)|
|
||||
|Kia|EV6 (with HDA I) 2025|Highway Driving Assist I|[Upstream](#upstream)|
|
||||
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|
||||
|Kia|EV9 2025-26|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Kia|Forte Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Kia|K4 (with HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|K4 (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|K5 2021-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|K5 (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Kia|Niro EV 2019|All|[Upstream](#upstream)|
|
||||
@@ -198,17 +290,25 @@
|
||||
|Kia|Optima Hybrid 2017|Advanced Smart Cruise Control|[Dashcam mode](#dashcam)|
|
||||
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Seltos 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Seltos Non-SCC 2023-24|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|[Upstream](#upstream)|
|
||||
|Kia|Sorento 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sorento 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sorento (without HDA II) 2024-25|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sorento Hybrid 2021-23|All|[Upstream](#upstream)|
|
||||
|Kia|Sorento Hybrid 2026|All|[Upstream](#upstream)|
|
||||
|Kia|Sorento Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|
||||
|Kia|Sportage 2023-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sportage (without HDA II) 2026|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sportage Hybrid 2026|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Stinger 2022-23|All|[Upstream](#upstream)|
|
||||
|Kia|Telluride 2020-22|All|[Upstream](#upstream)|
|
||||
|Kia|Telluride 2023-24|HDA2|[Community](#community)|
|
||||
|Kia|Telluride (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Kia|Telluride (without HDA II) 2023-25|Highway Driving Assist|[Upstream](#upstream)|
|
||||
|Kia|XCeed Plug-in Hybrid 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|[Upstream](#upstream)|
|
||||
|Lexus|ES 2017-18|All|[Upstream](#upstream)|
|
||||
|Lexus|ES 2019-25|All|[Upstream](#upstream)|
|
||||
@@ -244,6 +344,7 @@
|
||||
|Mazda|CX-9 2021-23|All|[Upstream](#upstream)|
|
||||
|Nissan|Altima 2019-20, 2024|ProPILOT Assist|[Upstream](#upstream)|
|
||||
|Nissan|Leaf 2018-25|ProPILOT Assist|[Upstream](#upstream)|
|
||||
|Nissan|Leaf Instrument Cluster 2018-25|ProPILOT Assist|[Upstream](#upstream)|
|
||||
|Nissan|Rogue 2018-20|ProPILOT Assist|[Upstream](#upstream)|
|
||||
|Nissan|X-Trail 2017|ProPILOT Assist|[Upstream](#upstream)|
|
||||
|Peugeot|208 2019-25|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
@@ -257,22 +358,24 @@
|
||||
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Subaru|Ascent 2019-21|All|[Upstream](#upstream)|
|
||||
|Subaru|Ascent 2023|All|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Ascent 2023-25|All|[Upstream](#upstream)|
|
||||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Crosstrek 2025|All|[Upstream](#upstream)|
|
||||
|Subaru|Crosstrek Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Forester 2017-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Forester 2019-21|All|[Upstream](#upstream)|
|
||||
|Subaru|Forester 2022-24|All|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Forester 2022-24|All|[Upstream](#upstream)|
|
||||
|Subaru|Forester Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Legacy 2020-22|All|[Upstream](#upstream)|
|
||||
|Subaru|Legacy 2025|All|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2015-17|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Outback 2018-19|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Outback 2020-22|All|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2023|All|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Outback 2023-24|All|[Upstream](#upstream)|
|
||||
|Subaru|Solterra 2023-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Subaru|XV 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|XV 2020-21|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
@@ -286,7 +389,8 @@
|
||||
|Škoda|Scala 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Tesla|Model 3 (with HW3) 2019-23|All|[Upstream](#upstream)|
|
||||
|Tesla|Model 3 (with HW4) 2024-25|All|[Upstream](#upstream)|
|
||||
|Tesla|Model 3 (with HW4) 2024-26|All|[Upstream](#upstream)|
|
||||
|Tesla|Model S (Pre-AP) 2012-14|All|[Community](#community)|
|
||||
|Tesla|Model X (with HW4) 2024|All|[Dashcam mode](#dashcam)|
|
||||
|Tesla|Model Y (with HW3) 2020-23|All|[Upstream](#upstream)|
|
||||
|Tesla|Model Y (with HW4) 2024-25|All|[Upstream](#upstream)|
|
||||
@@ -321,6 +425,7 @@
|
||||
|Toyota|Highlander 2025|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Highlander Hybrid 2017-19|All|[Upstream](#upstream)|
|
||||
|Toyota|Highlander Hybrid 2020-23|All|[Upstream](#upstream)|
|
||||
|Toyota|Matrix Retrofit 2005|Custom retrofit|[Community](#community)|
|
||||
|Toyota|Mirai 2021|All|[Upstream](#upstream)|
|
||||
|Toyota|Prius 2016|Toyota Safety Sense P|[Upstream](#upstream)|
|
||||
|Toyota|Prius 2017-20|All|[Upstream](#upstream)|
|
||||
@@ -342,7 +447,7 @@
|
||||
|Toyota|RAV4 Prime 2024-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Sequoia 2023-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Sienna 2018-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Sienna 2021-23|All|[Community](#community)|
|
||||
|Toyota|Sienna 2021-25|All|[Community](#community)|
|
||||
|Toyota|Sienna 2024-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Tundra 2022-25|Any|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Venza 2021-25|Any|[Not compatible](#can-bus-security)|
|
||||
@@ -444,4 +549,4 @@ Toyota, and the GM Global B platform.
|
||||
All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a
|
||||
CAN bus isn't the only way that the computers in your car can communicate. Most, if not all, vehicles from the following
|
||||
manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars
|
||||
may one day be supported, but we have no immediate plans to support FlexRay.
|
||||
may one day be supported, but we have no immediate plans to support FlexRay.
|
||||
@@ -671,7 +671,7 @@ class CarController(CarControllerBase):
|
||||
stopping, hud_control, CS, CC, starpilot_toggles, lka_icon, lfa_icon))
|
||||
else:
|
||||
can_sends.extend(self.create_can_msgs(apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel,
|
||||
stopping, hud_control, actuators, CS, CC, lfa_icon))
|
||||
stopping, hud_control, actuators, CS, CC, lka_icon, lfa_icon))
|
||||
|
||||
new_actuators = actuators.as_builder()
|
||||
if self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
|
||||
@@ -686,7 +686,7 @@ class CarController(CarControllerBase):
|
||||
self.frame += 1
|
||||
return new_actuators, can_sends
|
||||
|
||||
def create_can_msgs(self, apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, stopping, hud_control, actuators, CS, CC, lfa_icon):
|
||||
def create_can_msgs(self, apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, stopping, hud_control, actuators, CS, CC, lka_icon, lfa_icon):
|
||||
can_sends = []
|
||||
can_canfd_blended = bool(self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED)
|
||||
|
||||
@@ -711,7 +711,7 @@ class CarController(CarControllerBase):
|
||||
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
|
||||
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||
left_lane_warning, right_lane_warning))
|
||||
left_lane_warning, right_lane_warning, lka_icon))
|
||||
|
||||
# Button messages
|
||||
if not self.long_active_ecu:
|
||||
|
||||
@@ -49,6 +49,15 @@ def calculate_canfd_speed_limit(CP, FPCP, cp, cp_cam, speed_factor):
|
||||
return 0.0
|
||||
|
||||
|
||||
def get_canfd_cruise_available(CP, cp, scc_available: bool) -> bool:
|
||||
# The EV9 fallback keeps stock ACC active when ECU disable is skipped. Its
|
||||
# SCC status remains inactive in that mode, while TCS still reports whether
|
||||
# ACC is fault-free and available.
|
||||
if CP.carFingerprint == CAR.KIA_EV9 and not CP.openpilotLongitudinalControl:
|
||||
return cp.vl["TCS"]["ACCEnable"] == 0
|
||||
return scc_available
|
||||
|
||||
|
||||
def decode_ioniq_6_blindspot_radar_state(state: int) -> tuple[bool, bool]:
|
||||
state_int = int(state)
|
||||
return bool(state_int & IONIQ_6_BLINDSPOT_LEFT_MASK), bool(state_int & IONIQ_6_BLINDSPOT_RIGHT_MASK)
|
||||
@@ -522,7 +531,8 @@ class CarState(CarStateBase):
|
||||
ret.cruiseState.standstill = False
|
||||
else:
|
||||
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
|
||||
ret.cruiseState.available = cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1
|
||||
ret.cruiseState.available = get_canfd_cruise_available(
|
||||
self.CP, cp, cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1)
|
||||
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
|
||||
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
|
||||
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
|
||||
|
||||
@@ -8,7 +8,7 @@ hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf)
|
||||
def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
torque_fault, lkas11, sys_warning, sys_state, enabled,
|
||||
left_lane, right_lane,
|
||||
left_lane_depart, right_lane_depart):
|
||||
left_lane_depart, right_lane_depart, lka_icon):
|
||||
values = {s: lkas11[s] for s in [
|
||||
"CF_Lkas_LdwsActivemode",
|
||||
"CF_Lkas_LdwsSysState",
|
||||
@@ -51,7 +51,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
# FcwOpt_USM 2 = Green car + lanes
|
||||
# FcwOpt_USM 1 = White car + lanes
|
||||
# FcwOpt_USM 0 = No car + lanes
|
||||
values["CF_Lkas_FcwOpt_USM"] = 2 if enabled else 1
|
||||
values["CF_Lkas_FcwOpt_USM"] = lka_icon if CP.carFingerprint == CAR.GENESIS_G70_2020 else 2 if enabled else 1
|
||||
|
||||
# SysWarning 4 = keep hands on wheel
|
||||
# SysWarning 5 = keep hands on wheel (red)
|
||||
|
||||
@@ -17,7 +17,8 @@ from opendbc.car.hyundai.carcontroller import CarController, Ioniq6LongitudinalT
|
||||
should_reset_ev6_gt_line_longitudinal_tuning, reset_ev6_gt_line_longitudinal_tuning, \
|
||||
direct_angle_request_allowed, get_angle_smoothing_alpha, \
|
||||
should_use_ev6_gt_line_stop_direct_tracking
|
||||
from opendbc.car.hyundai.carstate import CarState, decode_canfd_camera_lead, decode_ioniq_6_blindspot_radar_state
|
||||
from opendbc.car.hyundai.carstate import CarState, decode_canfd_camera_lead, decode_ioniq_6_blindspot_radar_state, \
|
||||
get_canfd_cruise_available
|
||||
from opendbc.car.hyundai.interface import CarInterface, KIA_EV9_ACCEL_MAX
|
||||
from opendbc.car.hyundai import hyundaican, hyundaicanfd
|
||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
@@ -480,13 +481,35 @@ class TestHyundaiFingerprint:
|
||||
CC = SimpleNamespace(enabled=True, cruiseControl=SimpleNamespace(cancel=False, resume=False))
|
||||
actuators = SimpleNamespace(longControlState=LongCtrlState.off)
|
||||
|
||||
msgs = controller.create_can_msgs(True, 100, False, 0.0, 0.0, False, hud_control, actuators, CS, CC, 2)
|
||||
msgs = controller.create_can_msgs(True, 100, False, 0.0, 0.0, False, hud_control, actuators, CS, CC, 2, 2)
|
||||
msg_addrs_buses = {(addr, bus) for addr, _, bus in msgs}
|
||||
|
||||
assert (0x50, 0) in msg_addrs_buses
|
||||
assert (0x2A4, 0) in msg_addrs_buses
|
||||
assert not ({0x340, 0x364} & {addr for addr, _, _ in msgs})
|
||||
|
||||
def test_g70_aol_uses_active_lkas_icon(self):
|
||||
CP = CarInterface.get_params(CAR.GENESIS_G70_2020, gen_empty_fingerprint(), [], False, False, False, None)
|
||||
controller = CarController(DBC[CP.carFingerprint], CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS11", 0)], 0)
|
||||
|
||||
hud_control = SimpleNamespace(
|
||||
visualAlert=CarControl.HUDControl.VisualAlert.none,
|
||||
leftLaneVisible=True,
|
||||
rightLaneVisible=True,
|
||||
leftLaneDepart=False,
|
||||
rightLaneDepart=False,
|
||||
)
|
||||
CS = SimpleNamespace(lkas11=parser.vl["LKAS11"])
|
||||
CC = SimpleNamespace(enabled=False, cruiseControl=SimpleNamespace(cancel=False, resume=False))
|
||||
actuators = SimpleNamespace(longControlState=LongCtrlState.off)
|
||||
|
||||
msgs = controller.create_can_msgs(True, 100, False, 0.0, 0.0, False, hud_control, actuators, CS, CC, 2, 0)
|
||||
lkas11 = next(msg for msg in msgs if msg[0] == 0x340)
|
||||
parser.update([(1, [lkas11])])
|
||||
|
||||
assert parser.vl["LKAS11"]["CF_Lkas_FcwOpt_USM"] == 2
|
||||
|
||||
@pytest.mark.parametrize("candidate", (CAR.HYUNDAI_ELANTRA_2024, CAR.HYUNDAI_ELANTRA_HEV_2024))
|
||||
def test_hyundai_can_refresh_platforms_use_refresh_dbc_and_safety_param(self, candidate):
|
||||
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], False, False, False, None)
|
||||
@@ -728,6 +751,18 @@ class TestHyundaiFingerprint:
|
||||
ret.buttonEvents = [structs.CarState.ButtonEvent(pressed=True, type=ButtonType.mainCruise)]
|
||||
assert not CarState.update_main_cruise(car_state, ret)
|
||||
|
||||
def test_ev9_stock_fallback_uses_tcs_cruise_availability(self):
|
||||
CP = SimpleNamespace(carFingerprint=CAR.KIA_EV9, openpilotLongitudinalControl=False)
|
||||
cp = SimpleNamespace(vl={"TCS": {"ACCEnable": 0}})
|
||||
|
||||
assert get_canfd_cruise_available(CP, cp, False)
|
||||
|
||||
cp.vl["TCS"]["ACCEnable"] = 1
|
||||
assert not get_canfd_cruise_available(CP, cp, True)
|
||||
|
||||
other_cp = SimpleNamespace(carFingerprint=CAR.HYUNDAI_IONIQ_6, openpilotLongitudinalControl=False)
|
||||
assert not get_canfd_cruise_available(other_cp, cp, False)
|
||||
|
||||
def test_palisade_2023_cancel_release_enables_from_standby(self):
|
||||
toggles = get_test_toggles()
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_PALISADE_2023, gen_empty_fingerprint(), [], True, False, False, toggles)
|
||||
|
||||
@@ -35,7 +35,7 @@ class CarController(CarControllerBase):
|
||||
self.packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
self.main_bus = CanBus.main_for_cp(CP)
|
||||
self.angle_bus = CanBus.angle_for_cp(CP)
|
||||
self.status_bus = CanBus.camera if CP.flags & SubaruFlags.D_PLATFORM else CanBus.main
|
||||
self.status_bus = CanBus.main
|
||||
|
||||
if CP.flags & SubaruFlags.LKAS_ANGLE:
|
||||
self.VM = VehicleModel(get_safety_CP())
|
||||
|
||||
@@ -21,7 +21,7 @@ class CarState(CarStateBase):
|
||||
cp_cam = can_parsers[Bus.cam]
|
||||
cp_alt = can_parsers[Bus.alt]
|
||||
cp_main = can_parsers[Bus.main] if self.CP.flags & SubaruFlags.D_PLATFORM else cp
|
||||
cp_angle = cp_cam if self.CP.flags & SubaruFlags.D_PLATFORM else cp
|
||||
cp_angle = cp_main if self.CP.flags & SubaruFlags.D_PLATFORM else cp
|
||||
ret = structs.CarState()
|
||||
|
||||
throttle_msg = cp.vl["Throttle"] if not (self.CP.flags & SubaruFlags.HYBRID) else cp_alt.vl["Throttle_Hybrid"]
|
||||
|
||||
@@ -37,15 +37,19 @@ FW_VERSIONS = {
|
||||
CAR.SUBARU_ASCENT_2023: {
|
||||
(Ecu.abs, 0x7b0, None): [
|
||||
b'\xa5 #\x03\x00',
|
||||
b'\xa5 %\x03\x01',
|
||||
],
|
||||
(Ecu.eps, 0x746, None): [
|
||||
b'%\xc0\xd0\x11',
|
||||
b'\x55\xc0\xd0\x10',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x787, None): [
|
||||
b'\x05!\x08\x1dK\x05!\x08\x01/',
|
||||
b'\x17!\x08\x01A\x12!\x08\x00;',
|
||||
],
|
||||
(Ecu.engine, 0x7a2, None): [
|
||||
b'\xe5,\xa0P\x07',
|
||||
b'\x11,\xa00\x07',
|
||||
],
|
||||
(Ecu.transmission, 0x7a3, None): [
|
||||
b'\x04\xfe\xf3\x00\x00',
|
||||
|
||||
@@ -99,6 +99,17 @@ class TestSubaruFingerprint:
|
||||
assert exact
|
||||
assert matches == {CAR.SUBARU_LEGACY_2025}
|
||||
|
||||
def test_ascent_2025_firmware(self):
|
||||
car_fw = [
|
||||
CarParams.CarFw(ecu=CarParams.Ecu.abs, fwVersion=b'\xa5 %\x03\x01', address=0x7b0, brand="subaru"),
|
||||
CarParams.CarFw(ecu=CarParams.Ecu.eps, fwVersion=b'\x55\xc0\xd0\x10', address=0x746, brand="subaru"),
|
||||
CarParams.CarFw(ecu=CarParams.Ecu.fwdCamera, fwVersion=b'\x17!\x08\x01A\x12!\x08\x00;', address=0x787, brand="subaru"),
|
||||
CarParams.CarFw(ecu=CarParams.Ecu.engine, fwVersion=b'\x11,\xa00\x07', address=0x7a2, brand="subaru"),
|
||||
]
|
||||
exact, matches = match_fw_to_car(car_fw, "4S4WMAAD9S3414980", allow_fuzzy=False, log=False)
|
||||
assert exact
|
||||
assert matches == {CAR.SUBARU_ASCENT_2023}
|
||||
|
||||
|
||||
ANGLE_PLATFORMS = (
|
||||
CAR.SUBARU_FORESTER_2022,
|
||||
@@ -136,13 +147,13 @@ def test_outback_2023_uses_d_platform_bus_layout():
|
||||
assert CP.flags & SubaruFlags.D_PLATFORM
|
||||
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.D_PLATFORM
|
||||
assert CanBus.main_for_cp(CP) == CanBus.alt
|
||||
assert CanBus.angle_for_cp(CP) == CanBus.camera
|
||||
assert CanBus.angle_for_cp(CP) == CanBus.main
|
||||
assert parsers[Bus.pt].bus == CanBus.alt
|
||||
assert parsers[Bus.cam].bus == CanBus.camera
|
||||
assert parsers[Bus.alt].bus == CanBus.alt
|
||||
assert parsers[Bus.main].bus == CanBus.main
|
||||
assert controller.angle_bus == CanBus.camera
|
||||
assert controller.status_bus == CanBus.camera
|
||||
assert controller.angle_bus == CanBus.main
|
||||
assert controller.status_bus == CanBus.main
|
||||
|
||||
|
||||
def test_legacy_2025_uses_d_platform_bus_layout():
|
||||
@@ -153,13 +164,30 @@ def test_legacy_2025_uses_d_platform_bus_layout():
|
||||
assert CP.flags & SubaruFlags.D_PLATFORM
|
||||
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.D_PLATFORM
|
||||
assert CanBus.main_for_cp(CP) == CanBus.alt
|
||||
assert CanBus.angle_for_cp(CP) == CanBus.camera
|
||||
assert CanBus.angle_for_cp(CP) == CanBus.main
|
||||
assert parsers[Bus.pt].bus == CanBus.alt
|
||||
assert parsers[Bus.cam].bus == CanBus.camera
|
||||
assert parsers[Bus.alt].bus == CanBus.alt
|
||||
assert parsers[Bus.main].bus == CanBus.main
|
||||
assert controller.angle_bus == CanBus.camera
|
||||
assert controller.status_bus == CanBus.camera
|
||||
assert controller.angle_bus == CanBus.main
|
||||
assert controller.status_bus == CanBus.main
|
||||
|
||||
|
||||
def test_ascent_2023_uses_d_platform_bus_layout():
|
||||
CP = CarInterface.get_non_essential_params(CAR.SUBARU_ASCENT_2023)
|
||||
parsers = CarState.get_can_parsers(CP)
|
||||
controller = CarController({}, CP)
|
||||
|
||||
assert CP.flags & SubaruFlags.D_PLATFORM
|
||||
assert CP.safetyConfigs[0].safetyParam & SubaruSafetyFlags.D_PLATFORM
|
||||
assert CanBus.main_for_cp(CP) == CanBus.alt
|
||||
assert CanBus.angle_for_cp(CP) == CanBus.main
|
||||
assert parsers[Bus.pt].bus == CanBus.alt
|
||||
assert parsers[Bus.cam].bus == CanBus.camera
|
||||
assert parsers[Bus.alt].bus == CanBus.alt
|
||||
assert parsers[Bus.main].bus == CanBus.main
|
||||
assert controller.angle_bus == CanBus.main
|
||||
assert controller.status_bus == CanBus.main
|
||||
|
||||
|
||||
def test_other_angle_platforms_keep_existing_bus_layout():
|
||||
|
||||
@@ -113,8 +113,9 @@ class CanBus:
|
||||
|
||||
@staticmethod
|
||||
def angle_for_cp(CP):
|
||||
# D-platform angle LKAS is exchanged with the camera ECU on the camera bus.
|
||||
return CanBus.camera if CP.flags & SubaruFlags.D_PLATFORM else CanBus.main
|
||||
# D-platform angle commands reach the EPS through the main bus. The camera
|
||||
# bus still carries the stock angle message and remains receive-only.
|
||||
return CanBus.main
|
||||
|
||||
|
||||
class Footnote(Enum):
|
||||
@@ -244,9 +245,9 @@ class CAR(Platforms):
|
||||
flags=SubaruFlags.LKAS_ANGLE | SubaruFlags.D_PLATFORM,
|
||||
)
|
||||
SUBARU_ASCENT_2023 = SubaruGen2PlatformConfig(
|
||||
[SubaruCarDocs("Subaru Ascent 2023", "All", car_parts=CarParts.common([CarHarness.subaru_d]))],
|
||||
[SubaruCarDocs("Subaru Ascent 2023-25", "All", car_parts=CarParts.common([CarHarness.subaru_d]))],
|
||||
SUBARU_ASCENT.specs,
|
||||
flags=SubaruFlags.LKAS_ANGLE,
|
||||
flags=SubaruFlags.LKAS_ANGLE | SubaruFlags.D_PLATFORM,
|
||||
)
|
||||
SUBARU_CROSSTREK_2025 = SubaruGen2PlatformConfig(
|
||||
[SubaruCarDocs("Subaru Crosstrek 2025", "All", car_parts=CarParts.common([CarHarness.subaru_d]))],
|
||||
|
||||
@@ -56,10 +56,10 @@
|
||||
{MSG_SUBARU_ES_Distance, alt_bus, 8, .check_relay = false}, \
|
||||
|
||||
#define SUBARU_D_PLATFORM_ANGLE_TX_MSGS() \
|
||||
{MSG_SUBARU_ES_LKAS_ANGLE, SUBARU_CAM_BUS, 8, .check_relay = true}, \
|
||||
{MSG_SUBARU_ES_DashStatus, SUBARU_CAM_BUS, 8, .check_relay = true}, \
|
||||
{MSG_SUBARU_ES_LKAS_State, SUBARU_CAM_BUS, 8, .check_relay = true}, \
|
||||
{MSG_SUBARU_ES_Infotainment, SUBARU_CAM_BUS, 8, .check_relay = true}, \
|
||||
{MSG_SUBARU_ES_LKAS_ANGLE, SUBARU_MAIN_BUS, 8, .check_relay = true}, \
|
||||
{MSG_SUBARU_ES_DashStatus, SUBARU_MAIN_BUS, 8, .check_relay = true}, \
|
||||
{MSG_SUBARU_ES_LKAS_State, SUBARU_MAIN_BUS, 8, .check_relay = true}, \
|
||||
{MSG_SUBARU_ES_Infotainment, SUBARU_MAIN_BUS, 8, .check_relay = true}, \
|
||||
|
||||
#define SUBARU_COMMON_LONG_TX_MSGS(alt_bus) \
|
||||
{MSG_SUBARU_ES_Distance, alt_bus, 8, .check_relay = true}, \
|
||||
@@ -93,8 +93,8 @@
|
||||
|
||||
#define SUBARU_D_PLATFORM_ANGLE_RX_CHECKS() \
|
||||
{.msg = {{MSG_SUBARU_Throttle, SUBARU_ALT_BUS, 8, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{MSG_SUBARU_Steering_Torque, SUBARU_CAM_BUS, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{MSG_SUBARU_Steering_2, SUBARU_CAM_BUS, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{MSG_SUBARU_Steering_Torque, SUBARU_MAIN_BUS, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{MSG_SUBARU_Steering_2, SUBARU_MAIN_BUS, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{MSG_SUBARU_Wheel_Speeds, SUBARU_ALT_BUS, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{MSG_SUBARU_Brake_Status, SUBARU_ALT_BUS, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{MSG_SUBARU_ES_Brake, SUBARU_ALT_BUS, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
@@ -127,7 +127,7 @@ static uint32_t subaru_compute_checksum(const CANPacket_t *msg) {
|
||||
static void subaru_rx_hook(const CANPacket_t *msg) {
|
||||
const unsigned int alt_main_bus = subaru_gen2 ? SUBARU_ALT_BUS : SUBARU_MAIN_BUS;
|
||||
const unsigned int status_bus = subaru_gen2 ? SUBARU_ALT_BUS : SUBARU_CAM_BUS;
|
||||
const unsigned int steering_bus = subaru_d_platform ? SUBARU_CAM_BUS : SUBARU_MAIN_BUS;
|
||||
const unsigned int steering_bus = SUBARU_MAIN_BUS;
|
||||
const unsigned int main_bus = subaru_d_platform ? SUBARU_ALT_BUS : SUBARU_MAIN_BUS;
|
||||
|
||||
if ((msg->addr == MSG_SUBARU_Steering_Torque) && (msg->bus == steering_bus)) {
|
||||
|
||||
@@ -970,6 +970,10 @@ class SafetyTest(SafetyTestBase):
|
||||
if 'TestSubaruDPlatformAngleSafety' in {attr, current_test} and \
|
||||
'Angle' in attr and 'Angle' in current_test:
|
||||
continue
|
||||
if 'TestSubaruDPlatformAngleSafety' in {attr, current_test}:
|
||||
# D-platform uses the same main-bus HUD messages as the other
|
||||
# Subaru modes, so those modes cannot be distinguished by ID.
|
||||
tx = list(filter(lambda m: not (m[1] == 0 and m[0] in [0x321, 0x322, 0x323]), tx))
|
||||
if attr.startswith('TestSubaruPreglobal') and current_test.startswith('TestSubaruPreglobal'):
|
||||
continue
|
||||
if {attr, current_test}.issubset({'TestVolkswagenPqSafety', 'TestVolkswagenPqStockSafety', 'TestVolkswagenPqLongSafety'}):
|
||||
|
||||
@@ -343,15 +343,16 @@ class TestSubaruGen2AngleStockLongitudinalSafety(TestSubaruStockLongitudinalSafe
|
||||
class TestSubaruDPlatformAngleSafety(TestSubaruStockLongitudinalSafetyBase, TestSubaruAngleSafetyBase):
|
||||
FLAGS = SubaruSafetyFlags.GEN2 | SubaruSafetyFlags.LKAS_ANGLE | SubaruSafetyFlags.D_PLATFORM
|
||||
ALT_MAIN_BUS = SUBARU_ALT_BUS
|
||||
TX_MSGS = [[SubaruMsg.ES_LKAS_ANGLE, SUBARU_CAM_BUS],
|
||||
[SubaruMsg.ES_DashStatus, SUBARU_CAM_BUS],
|
||||
[SubaruMsg.ES_LKAS_State, SUBARU_CAM_BUS],
|
||||
[SubaruMsg.ES_Infotainment, SUBARU_CAM_BUS],
|
||||
TX_MSGS = [[SubaruMsg.ES_LKAS_ANGLE, SUBARU_MAIN_BUS],
|
||||
[SubaruMsg.ES_DashStatus, SUBARU_MAIN_BUS],
|
||||
[SubaruMsg.ES_LKAS_State, SUBARU_MAIN_BUS],
|
||||
[SubaruMsg.ES_Infotainment, SUBARU_MAIN_BUS],
|
||||
[SubaruMsg.ES_Distance, SUBARU_ALT_BUS]]
|
||||
RELAY_MALFUNCTION_ADDRS = {SUBARU_CAM_BUS: (SubaruMsg.ES_LKAS_ANGLE, SubaruMsg.ES_DashStatus,
|
||||
RELAY_MALFUNCTION_ADDRS = {SUBARU_MAIN_BUS: (SubaruMsg.ES_LKAS_ANGLE,
|
||||
SubaruMsg.ES_DashStatus,
|
||||
SubaruMsg.ES_LKAS_State, SubaruMsg.ES_Infotainment)}
|
||||
FWD_BLACKLISTED_ADDRS = {
|
||||
SUBARU_MAIN_BUS: [SubaruMsg.ES_LKAS_ANGLE, SubaruMsg.ES_DashStatus, SubaruMsg.ES_LKAS_State, SubaruMsg.ES_Infotainment],
|
||||
SUBARU_CAM_BUS: [SubaruMsg.ES_LKAS_ANGLE, SubaruMsg.ES_DashStatus, SubaruMsg.ES_LKAS_State, SubaruMsg.ES_Infotainment],
|
||||
}
|
||||
|
||||
def _torque_driver_msg(self, torque):
|
||||
@@ -365,10 +366,10 @@ class TestSubaruDPlatformAngleSafety(TestSubaruStockLongitudinalSafetyBase, Test
|
||||
self.safety.set_timer(self.angle_cmd_cnt * int(1e6 / self.LATERAL_FREQUENCY))
|
||||
self.angle_cmd_cnt += 1
|
||||
values = {"LKAS_Output": angle, "LKAS_Request": enabled, "SET_3": 3}
|
||||
return self.packer.make_can_msg_safety("ES_LKAS_ANGLE", SUBARU_CAM_BUS, values)
|
||||
return self.packer.make_can_msg_safety("ES_LKAS_ANGLE", SUBARU_MAIN_BUS, values)
|
||||
|
||||
def _angle_meas_msg(self, angle):
|
||||
return self.packer.make_can_msg_safety("Steering_2", SUBARU_CAM_BUS, {"Steering_Angle": angle})
|
||||
return self.packer.make_can_msg_safety("Steering_2", SUBARU_MAIN_BUS, {"Steering_Angle": angle})
|
||||
|
||||
|
||||
class TestSubaruGen2LongitudinalSafety(TestSubaruLongitudinalSafetyBase, TestSubaruGen2TorqueSafetyBase):
|
||||
|
||||
+57
-30
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import codecs
|
||||
import ctypes
|
||||
import glob
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
@@ -42,8 +44,17 @@ MODEL_RUN_FREQ = 20
|
||||
MODEL_CONTEXT_FREQ = 5
|
||||
REPOSITORY_FILE_LIMIT = 100 * 1024 * 1024
|
||||
DEFAULT_MULTIPART_SIZE = 95 * 1024 * 1024
|
||||
USBGPU_PROBE_ATTEMPTS = 3
|
||||
USBGPU_PROBE_TIMEOUT = 10
|
||||
USBGPU_PROBE_ATTEMPTS = 10
|
||||
USBGPU_PROBE_TIMEOUT = 2
|
||||
USBDEVFS_CONTROL = 0xC0185500
|
||||
USBGPU_VID_PIDS = (("add1", "0001"), ("3801", "0001"))
|
||||
|
||||
|
||||
class _UsbdevfsControl(ctypes.Structure):
|
||||
_fields_ = [("request_type", ctypes.c_uint8), ("request", ctypes.c_uint8),
|
||||
("value", ctypes.c_uint16), ("index", ctypes.c_uint16),
|
||||
("length", ctypes.c_uint16), ("timeout", ctypes.c_uint32),
|
||||
("data", ctypes.c_void_p)]
|
||||
|
||||
|
||||
def build_compile_env() -> dict[str, str]:
|
||||
@@ -65,49 +76,65 @@ def build_compile_env() -> dict[str, str]:
|
||||
return env
|
||||
|
||||
|
||||
def _probe_external_gpu_link_once() -> tuple[bool, str]:
|
||||
"""Probe the bridge without initializing tinygrad or resetting the USB device."""
|
||||
import fcntl
|
||||
|
||||
diagnostics: list[str] = []
|
||||
for path in glob.glob("/sys/bus/usb/devices/*"):
|
||||
try:
|
||||
vendor = Path(path, "idVendor").read_text().strip().lower()
|
||||
product = Path(path, "idProduct").read_text().strip().lower()
|
||||
if (vendor, product) not in USBGPU_VID_PIDS:
|
||||
continue
|
||||
bus = int(Path(path, "busnum").read_text())
|
||||
device = int(Path(path, "devnum").read_text())
|
||||
location = f"usb:{bus}-{device}"
|
||||
fd = os.open(f"/dev/bus/usb/{bus:03d}/{device:03d}", os.O_RDWR)
|
||||
except (OSError, ValueError) as exc:
|
||||
diagnostics.append(f"{path}: open failed ({exc})")
|
||||
continue
|
||||
|
||||
try:
|
||||
fcntl.ioctl(fd, USBDEVFS_CONTROL, _UsbdevfsControl(0x40, 0xF3, 1, 0, 0, USBGPU_PROBE_TIMEOUT * 1000, None))
|
||||
state = (ctypes.c_ubyte * 1)()
|
||||
fcntl.ioctl(fd, USBDEVFS_CONTROL, _UsbdevfsControl(0xC0, 0xE4, 0xB450, 0, 1, 1000, ctypes.cast(state, ctypes.c_void_p)))
|
||||
if state[0] == 0x78:
|
||||
return True, f"{location}: LTSSM=0x78"
|
||||
diagnostics.append(f"{location}: LTSSM=0x{state[0]:02X}")
|
||||
except OSError as exc:
|
||||
diagnostics.append(f"{location}: control probe failed ({exc})")
|
||||
finally:
|
||||
os.close(fd)
|
||||
return False, diagnostics[-1] if diagnostics else "no ASM2464PD device found"
|
||||
|
||||
|
||||
def wait_for_external_gpu(compile_env: dict[str, str]) -> bool:
|
||||
"""Wait for the USB GPU's PCIe link before starting the large model build.
|
||||
|
||||
The dock can enumerate on USB before its PCIe link has finished training.
|
||||
OpenPilot probes the tinygrad device in a short-lived process and retries;
|
||||
doing the same here avoids making the model compiler lose its one chance at
|
||||
initialization while keeping all non-GPU builds unchanged.
|
||||
Probe the bridge's control endpoint directly, like upstream openpilot. Do
|
||||
not instantiate tinygrad here: opening the GPU resets/claims the USB
|
||||
interface, and doing that in a probe process can leave the bridge in a state
|
||||
where the authoritative compiler cannot train the link.
|
||||
"""
|
||||
probe = [sys.executable, "-c", "from tinygrad.device import Device; Device[Device.DEFAULT]; import os; os._exit(0)"]
|
||||
probe_env = {**compile_env, "DEV": "USB+AMD"}
|
||||
del compile_env # retained in the public helper signature for callers/tests
|
||||
diagnostics: list[str] = []
|
||||
|
||||
for attempt in range(USBGPU_PROBE_ATTEMPTS):
|
||||
if attempt:
|
||||
time.sleep(1)
|
||||
try:
|
||||
result = subprocess.run(
|
||||
probe,
|
||||
cwd=REPO_ROOT,
|
||||
env=probe_env,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=USBGPU_PROBE_TIMEOUT,
|
||||
check=False,
|
||||
)
|
||||
except subprocess.TimeoutExpired as exc:
|
||||
partial = exc.stderr or exc.stdout or ""
|
||||
if isinstance(partial, bytes):
|
||||
partial = partial.decode(errors="replace")
|
||||
partial = partial.strip()
|
||||
diagnostics.append(
|
||||
f"probe timed out after {USBGPU_PROBE_TIMEOUT}s" + (f": {partial[-2000:]}" if partial else "")
|
||||
)
|
||||
continue
|
||||
|
||||
if result.returncode == 0:
|
||||
ready, detail = _probe_external_gpu_link_once()
|
||||
except Exception as exc: # probe is advisory; compile_modeld remains authoritative
|
||||
ready, detail = False, str(exc)
|
||||
if ready:
|
||||
return True
|
||||
detail = (result.stderr or result.stdout).strip()
|
||||
diagnostics.append((detail[-2000:] if detail else f"probe exited with status {result.returncode}"))
|
||||
diagnostics.append(detail)
|
||||
|
||||
detail = diagnostics[-1] if diagnostics else "unknown error"
|
||||
print(
|
||||
f"Warning: external GPU probe did not become ready after {USBGPU_PROBE_ATTEMPTS} probes: {detail}\n"
|
||||
f"Warning: external GPU link did not become ready after {USBGPU_PROBE_ATTEMPTS} probes: {detail}\n"
|
||||
" Continuing; compile_modeld will perform the authoritative link wait and initialization."
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -49,6 +49,9 @@ class VCruiseHelper:
|
||||
}
|
||||
self.button_hard_states = dict.fromkeys(self.button_timers, False)
|
||||
self.button_change_states = {btn: {"standstill": False, "enabled": False} for btn in self.button_timers}
|
||||
# Keep the confirmation button from leaking into cruise-speed handling when the
|
||||
# planner clears the confirmation state between the press and release events.
|
||||
self.confirmation_button_suppressed = set()
|
||||
|
||||
self.gm_cc_only = self.CP.carFingerprint in CC_ONLY_CAR and self.CP.flags & GMFlags.CC_LONG.value
|
||||
self.redneck_non_pcm = bool(FPCP is not None and
|
||||
@@ -120,6 +123,15 @@ class VCruiseHelper:
|
||||
|
||||
v_cruise_delta = 1. if is_metric else IMPERIAL_INCREMENT
|
||||
|
||||
for b in CS.buttonEvents:
|
||||
event_button_type = b.type.raw
|
||||
if event_button_type in self.button_timers:
|
||||
if speed_limit_changed and b.pressed:
|
||||
self.confirmation_button_suppressed.add(event_button_type)
|
||||
elif not b.pressed and event_button_type in self.confirmation_button_suppressed:
|
||||
self.confirmation_button_suppressed.remove(event_button_type)
|
||||
return
|
||||
|
||||
for b in CS.buttonEvents:
|
||||
if b.type.raw in self.button_timers and not b.pressed:
|
||||
if self.button_timers[b.type.raw] > CRUISE_LONG_PRESS:
|
||||
@@ -138,6 +150,9 @@ class VCruiseHelper:
|
||||
if button_type is None:
|
||||
return
|
||||
|
||||
if button_type in self.confirmation_button_suppressed:
|
||||
return
|
||||
|
||||
# Don't adjust speed when pressing to confirm or deny speed limit changes
|
||||
if speed_limit_changed:
|
||||
return
|
||||
|
||||
@@ -2,6 +2,7 @@ from cereal import car
|
||||
from opendbc.car import apply_hysteresis
|
||||
from openpilot.common.constants import CV
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
from openpilot.selfdrive.car.cruise import V_CRUISE_UNSET
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
|
||||
@@ -50,6 +51,10 @@ def select_redneck_target_speed(v_cruise_kph: float, speed_cluster_ms: float,
|
||||
target_speed_ms = float(speed_cluster_ms)
|
||||
if slc_target_speed_ms > 0:
|
||||
target_speed_ms = float(slc_target_speed_ms)
|
||||
# SLC is an upper bound for the button-spammed stock setpoint. A driver-set
|
||||
# speed below the posted target must still be able to slow the car down.
|
||||
if 0 < v_cruise_kph < V_CRUISE_UNSET:
|
||||
target_speed_ms = min(target_speed_ms, float(v_cruise_kph) * CV.KPH_TO_MS)
|
||||
elif v_cruise_kph > 0:
|
||||
target_speed_ms = float(v_cruise_kph) * CV.KPH_TO_MS
|
||||
elif starpilot_target_speed_ms > 0:
|
||||
|
||||
@@ -330,6 +330,35 @@ class TestVCruiseHelper:
|
||||
|
||||
assert self.v_cruise_helper.v_cruise_kph == initial_v_cruise_kph
|
||||
|
||||
def test_speed_limit_confirmation_press_release_does_not_leak_after_acceptance(self):
|
||||
for button_type in (ButtonType.accelCruise, ButtonType.decelCruise):
|
||||
self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False)
|
||||
initial_v_cruise_kph = self.v_cruise_helper.v_cruise_kph
|
||||
|
||||
pressed_cs = car.CarState(cruiseState={"available": True})
|
||||
pressed_cs.buttonEvents = [ButtonEvent(type=button_type, pressed=True)]
|
||||
self.v_cruise_helper.update_v_cruise(
|
||||
pressed_cs,
|
||||
enabled=True,
|
||||
is_metric=False,
|
||||
speed_limit_changed=True,
|
||||
starpilot_toggles=self.starpilot_toggles,
|
||||
)
|
||||
|
||||
# The planner may have consumed the confirmation by the time the physical
|
||||
# button release arrives. The release must remain confirmation-only.
|
||||
released_cs = car.CarState(cruiseState={"available": True})
|
||||
released_cs.buttonEvents = [ButtonEvent(type=button_type, pressed=False)]
|
||||
self.v_cruise_helper.update_v_cruise(
|
||||
released_cs,
|
||||
enabled=True,
|
||||
is_metric=False,
|
||||
speed_limit_changed=False,
|
||||
starpilot_toggles=self.starpilot_toggles,
|
||||
)
|
||||
|
||||
assert self.v_cruise_helper.v_cruise_kph == initial_v_cruise_kph
|
||||
|
||||
def test_stale_speed_limit_change_does_adjust_cruise(self):
|
||||
self.enable(V_CRUISE_INITIAL * CV.KPH_TO_MS, False)
|
||||
initial_v_cruise_kph = self.v_cruise_helper.v_cruise_kph
|
||||
|
||||
@@ -170,8 +170,8 @@ class TestRedneckCruise(unittest.TestCase):
|
||||
)
|
||||
self.assertAlmostEqual(104.4 * CV.KPH_TO_MS, target_speed)
|
||||
|
||||
def test_target_speed_follows_resolved_slc_target(self):
|
||||
for internal_mph, slc_mph in ((55.0, 65.0), (65.0, 55.0)):
|
||||
def test_target_speed_respects_manual_lower_set_speed_with_slc(self):
|
||||
for internal_mph, slc_mph, expected_mph in ((55.0, 65.0, 55.0), (65.0, 55.0, 55.0)):
|
||||
with self.subTest(internal_mph=internal_mph, slc_mph=slc_mph):
|
||||
target_speed = select_redneck_target_speed(
|
||||
internal_mph * CV.MPH_TO_KPH,
|
||||
@@ -182,7 +182,20 @@ class TestRedneckCruise(unittest.TestCase):
|
||||
allow_plan_decrease=False,
|
||||
slc_target_speed_ms=slc_mph * CV.MPH_TO_MS,
|
||||
)
|
||||
self.assertAlmostEqual(slc_mph * CV.MPH_TO_MS, target_speed)
|
||||
self.assertAlmostEqual(expected_mph * CV.MPH_TO_MS, target_speed)
|
||||
|
||||
def test_target_speed_keeps_slc_limit_when_manual_set_speed_is_higher(self):
|
||||
target_speed = select_redneck_target_speed(
|
||||
75.0 * CV.MPH_TO_KPH,
|
||||
65.0 * CV.MPH_TO_MS,
|
||||
0.0,
|
||||
[],
|
||||
10,
|
||||
allow_plan_decrease=False,
|
||||
slc_target_speed_ms=65.0 * CV.MPH_TO_MS,
|
||||
)
|
||||
|
||||
self.assertAlmostEqual(65.0 * CV.MPH_TO_MS, target_speed)
|
||||
|
||||
def test_card_target_speed_uses_longitudinal_acceleration(self):
|
||||
sm = MagicMock()
|
||||
|
||||
@@ -113,6 +113,7 @@ class LatControlTorque(LatControl):
|
||||
self.is_ioniq_5 = CP.carFingerprint in IONIQ_5_CARS
|
||||
self.is_ioniq_ev_old = CP.carFingerprint in IONIQ_EV_OLD_CARS
|
||||
self.is_ioniq_6 = CP.carFingerprint in IONIQ_6_CARS
|
||||
self.is_ioniq_6_2025 = is_ioniq_6_2025_model(CP)
|
||||
self.is_sonata = CP.carFingerprint in SONATA_CARS
|
||||
self.is_sonata_hybrid = CP.carFingerprint in SONATA_HYBRID_CARS
|
||||
self.is_elantra_non_scc = CP.carFingerprint in ELANTRA_NON_SCC_CARS
|
||||
@@ -251,9 +252,10 @@ class LatControlTorque(LatControl):
|
||||
delay_frames = int(np.clip(lat_delay / self.dt, 1, self.request_buffer_len))
|
||||
expected_lateral_accel = self.curvature_request_buffer[-delay_frames] * CS.vEgo ** 2
|
||||
self.curvature_request_buffer.append(desired_curvature)
|
||||
lateral_jerk_limit = RAM_1500_MAX_LAT_JERK_UP if self.is_ram_1500 else MAX_LAT_JERK_UP
|
||||
raw_lateral_jerk = (future_desired_lateral_accel - expected_lateral_accel) / max(lat_delay, self.dt)
|
||||
raw_lateral_jerk = np.clip(raw_lateral_jerk, -MAX_LAT_JERK_UP, MAX_LAT_JERK_UP)
|
||||
desired_lateral_jerk = np.clip(self.jerk_filter.update(raw_lateral_jerk), -MAX_LAT_JERK_UP, MAX_LAT_JERK_UP)
|
||||
raw_lateral_jerk = np.clip(raw_lateral_jerk, -lateral_jerk_limit, lateral_jerk_limit)
|
||||
desired_lateral_jerk = np.clip(self.jerk_filter.update(raw_lateral_jerk), -lateral_jerk_limit, lateral_jerk_limit)
|
||||
gravity_adjusted_future_lateral_accel = future_desired_lateral_accel - roll_compensation
|
||||
setpoint = expected_lateral_accel + desired_lateral_jerk * lat_delay
|
||||
desired_lateral_accel_rate = (setpoint - self.prev_desired_lateral_accel) / self.dt
|
||||
@@ -393,6 +395,8 @@ class LatControlTorque(LatControl):
|
||||
friction_scale = get_ioniq_6_friction_scale(CS.vEgo, setpoint, desired_lateral_jerk)
|
||||
friction_scale = 1.0 + ((friction_scale - 1.0) * ioniq_6_center_taper)
|
||||
friction_scale *= get_ioniq_6_friction_center_fade_scale(setpoint, CS.vEgo)
|
||||
if self.is_ioniq_6_2025:
|
||||
friction_scale *= IONIQ_6_2025_FRICTION_SCALE_MULT
|
||||
elif sonata_active:
|
||||
ff *= get_sonata_ff_scale(setpoint, desired_lateral_jerk, CS.vEgo) * sonata_center_taper
|
||||
elif sonata_hybrid_active:
|
||||
@@ -416,6 +420,8 @@ class LatControlTorque(LatControl):
|
||||
elif kia_carnival_active:
|
||||
friction_threshold = get_kia_carnival_friction_threshold(CS.vEgo, setpoint, desired_lateral_jerk)
|
||||
friction_scale *= get_kia_carnival_friction_center_fade_scale(setpoint, CS.vEgo)
|
||||
elif self.is_kona_non_scc:
|
||||
friction_threshold = get_kona_non_scc_friction_threshold(CS.vEgo, setpoint, desired_lateral_jerk)
|
||||
elif tucson_4th_gen_active:
|
||||
friction_threshold = get_tucson_4th_gen_friction_threshold(CS.vEgo, setpoint, desired_lateral_jerk)
|
||||
elif self.is_silverado:
|
||||
@@ -442,7 +448,14 @@ class LatControlTorque(LatControl):
|
||||
if trailer_load_kg > 0.0:
|
||||
ff *= get_trailer_lateral_ff_scale(trailer_load_kg, CS.vEgo, setpoint)
|
||||
friction_scale *= get_trailer_lateral_friction_scale(trailer_load_kg, CS.vEgo, setpoint)
|
||||
vehicle_friction_jerk_deadzone = IONIQ_6_FRICTION_JERK_DEADZONE if ioniq_6_active else 0.0
|
||||
if ioniq_6_active:
|
||||
vehicle_friction_jerk_deadzone = (
|
||||
IONIQ_6_2025_FRICTION_JERK_DEADZONE if self.is_ioniq_6_2025 else IONIQ_6_FRICTION_JERK_DEADZONE
|
||||
)
|
||||
elif prius_active:
|
||||
vehicle_friction_jerk_deadzone = get_prius_friction_jerk_deadzone(CS.vEgo, setpoint)
|
||||
else:
|
||||
vehicle_friction_jerk_deadzone = 0.0
|
||||
friction_jerk_deadzone = get_center_chatter_friction_jerk_deadzone(
|
||||
CS.vEgo, setpoint, vehicle_friction_jerk_deadzone
|
||||
)
|
||||
@@ -486,6 +499,8 @@ class LatControlTorque(LatControl):
|
||||
if ioniq_6_active:
|
||||
output_torque *= get_ioniq_6_highway_output_taper_scale(setpoint, CS.vEgo)
|
||||
output_torque *= get_ioniq_6_highway_transition_output_taper_scale(setpoint, desired_lateral_jerk, CS.vEgo)
|
||||
if self.is_ioniq_6_2025:
|
||||
output_torque *= get_ioniq_6_2025_center_output_scale(setpoint, CS.vEgo)
|
||||
elif self.is_ram_1500 and output_torque * setpoint > 0.0:
|
||||
output_torque *= get_ram_1500_transition_output_scale(setpoint, desired_lateral_jerk, CS.vEgo)
|
||||
elif self.is_kona_non_scc:
|
||||
@@ -500,6 +515,7 @@ class LatControlTorque(LatControl):
|
||||
output_torque *= get_sienna_4th_gen_high_speed_output_taper_scale(CS.vEgo)
|
||||
elif prius_active:
|
||||
output_torque *= prius_center_taper
|
||||
output_torque *= get_prius_high_speed_output_taper_scale(setpoint, CS.vEgo)
|
||||
elif volt_standard_test_active:
|
||||
output_torque *= volt_standard_center_taper
|
||||
elif volt_plexy_test_active:
|
||||
|
||||
@@ -104,6 +104,24 @@ IONIQ_EV_OLD_CARS = (
|
||||
IONIQ_6_CARS = (
|
||||
HYUNDAI_CAR.HYUNDAI_IONIQ_6,
|
||||
)
|
||||
|
||||
|
||||
def is_ioniq_6_2025_model(CP) -> bool:
|
||||
"""Identify the newer Ioniq 6 firmware without changing the legacy 2023 path."""
|
||||
if getattr(CP, "carFingerprint", None) not in IONIQ_6_CARS:
|
||||
return False
|
||||
|
||||
versions = []
|
||||
try:
|
||||
for fw in CP.carFw:
|
||||
value = fw.fwVersion
|
||||
versions.append(value.decode("ascii", errors="ignore") if isinstance(value, bytes) else str(value))
|
||||
except (AttributeError, TypeError, ValueError):
|
||||
return False
|
||||
|
||||
return any("230915" in version for version in versions) and any("240206" in version for version in versions)
|
||||
|
||||
|
||||
SONATA_HYBRID_CARS = (
|
||||
HYUNDAI_CAR.HYUNDAI_SONATA_HYBRID,
|
||||
)
|
||||
@@ -722,6 +740,14 @@ IONIQ_6_FRICTION_CENTER_FADE_LAT = 0.15
|
||||
IONIQ_6_FRICTION_CENTER_FADE_LAT_WIDTH = 0.06
|
||||
IONIQ_6_FRICTION_CENTER_FADE_SPEED = 18.0
|
||||
IONIQ_6_FRICTION_CENTER_FADE_SPEED_WIDTH = 2.5
|
||||
# Newer Ioniq 6 highway center-chatter correction; activation is firmware-gated.
|
||||
IONIQ_6_2025_FRICTION_SCALE_MULT = 0.80
|
||||
IONIQ_6_2025_FRICTION_JERK_DEADZONE = 0.45
|
||||
IONIQ_6_2025_CENTER_OUTPUT_TAPER_MAX = 0.18
|
||||
IONIQ_6_2025_CENTER_OUTPUT_TAPER_LAT = 0.35
|
||||
IONIQ_6_2025_CENTER_OUTPUT_TAPER_LAT_WIDTH = 0.10
|
||||
IONIQ_6_2025_CENTER_OUTPUT_TAPER_SPEED = 22.0
|
||||
IONIQ_6_2025_CENTER_OUTPUT_TAPER_SPEED_WIDTH = 2.5
|
||||
IONIQ_6_HEAVY_DIRECTIONAL_TAPER_LAT_START = 0.90
|
||||
IONIQ_6_HEAVY_DIRECTIONAL_TAPER_LAT_WIDTH = 0.18
|
||||
IONIQ_6_HEAVY_DIRECTIONAL_TAPER_BASE_LEFT = 0.03
|
||||
@@ -774,7 +800,7 @@ KIA_EV6_CENTER_TAPER_LAT = 0.16
|
||||
KIA_EV6_CENTER_TAPER_LAT_WIDTH = 0.04
|
||||
KIA_EV6_CENTER_TAPER_SPEED = 17.0
|
||||
KIA_EV6_CENTER_TAPER_SPEED_WIDTH = 2.8
|
||||
KIA_EV6_CENTER_FRICTION_THRESHOLD_GAIN = 0.08
|
||||
KIA_EV6_CENTER_FRICTION_THRESHOLD_GAIN = 0.14
|
||||
KIA_EV6_CENTER_FRICTION_THRESHOLD_LAT = 0.30
|
||||
KIA_EV6_CENTER_FRICTION_THRESHOLD_LAT_WIDTH = 0.07
|
||||
KIA_EV6_CENTER_FRICTION_THRESHOLD_SPEED = 18.0
|
||||
@@ -816,7 +842,7 @@ PRIUS_TURN_IN_FRICTION_BOOST_RIGHT = 0.06
|
||||
PRIUS_UNWIND_FRICTION_REDUCTION_LEFT = 0.22
|
||||
PRIUS_UNWIND_FRICTION_REDUCTION_RIGHT = 0.30
|
||||
PRIUS_CENTER_TAPER_MAX = 0.15
|
||||
PRIUS_CENTER_TAPER_LAT = 0.16
|
||||
PRIUS_CENTER_TAPER_LAT = 0.24
|
||||
PRIUS_CENTER_TAPER_LAT_WIDTH = 0.035
|
||||
PRIUS_CENTER_TAPER_SPEED = 18.0
|
||||
PRIUS_CENTER_TAPER_SPEED_WIDTH = 2.2
|
||||
@@ -825,6 +851,16 @@ PRIUS_CENTER_FRICTION_THRESHOLD_LAT = 0.30
|
||||
PRIUS_CENTER_FRICTION_THRESHOLD_LAT_WIDTH = 0.07
|
||||
PRIUS_CENTER_FRICTION_THRESHOLD_SPEED = 18.0
|
||||
PRIUS_CENTER_FRICTION_THRESHOLD_SPEED_WIDTH = 2.2
|
||||
PRIUS_FRICTION_JERK_DEADZONE_MAX = 0.24
|
||||
PRIUS_FRICTION_JERK_DEADZONE_LAT = 0.30
|
||||
PRIUS_FRICTION_JERK_DEADZONE_LAT_WIDTH = 0.07
|
||||
PRIUS_FRICTION_JERK_DEADZONE_SPEED = 18.0
|
||||
PRIUS_FRICTION_JERK_DEADZONE_SPEED_WIDTH = 2.2
|
||||
PRIUS_HIGH_SPEED_OUTPUT_TAPER_MAX = 0.06
|
||||
PRIUS_HIGH_SPEED_OUTPUT_TAPER_LAT = 0.30
|
||||
PRIUS_HIGH_SPEED_OUTPUT_TAPER_LAT_WIDTH = 0.35
|
||||
PRIUS_HIGH_SPEED_OUTPUT_TAPER_SPEED = 22.0
|
||||
PRIUS_HIGH_SPEED_OUTPUT_TAPER_SPEED_WIDTH = 2.5
|
||||
|
||||
CAMRY_CENTER_FRICTION_THRESHOLD_GAIN = 0.09
|
||||
CAMRY_CENTER_FRICTION_THRESHOLD_LAT = 0.22
|
||||
@@ -873,6 +909,9 @@ SIENNA_4TH_GEN_FRICTION_SPEED_ONSET = 3.0
|
||||
SIENNA_4TH_GEN_FRICTION_SPEED_WIDTH = 1.5
|
||||
SIENNA_4TH_GEN_FRICTION_SPEED_MAX = 14.0
|
||||
SIENNA_4TH_GEN_FRICTION_SPEED_MAX_WIDTH = 2.0
|
||||
SIENNA_4TH_GEN_HIGH_SPEED_FRICTION_THRESHOLD_GAIN = 0.14
|
||||
SIENNA_4TH_GEN_HIGH_SPEED_FRICTION_SPEED_ONSET = 18.0
|
||||
SIENNA_4TH_GEN_HIGH_SPEED_FRICTION_SPEED_WIDTH = 2.5
|
||||
SIENNA_4TH_GEN_CENTER_TAPER_MAX = 0.12
|
||||
SIENNA_4TH_GEN_CENTER_TAPER_LAT = 0.20
|
||||
SIENNA_4TH_GEN_CENTER_TAPER_LAT_WIDTH = 0.06
|
||||
@@ -910,13 +949,14 @@ RAM_1500_TRANSITION_JERK_ONSET = 0.35
|
||||
RAM_1500_TRANSITION_JERK_FULL = 1.10
|
||||
RAM_1500_TRANSITION_LAT_FADE_START = 0.65
|
||||
RAM_1500_TRANSITION_LAT_FADE_END = 1.85
|
||||
RAM_1500_MAX_LAT_JERK_UP = 2.10
|
||||
RAM_1500_PHASE_SCALE = 0.12
|
||||
RAM_1500_PHASE_SPEED_ONSET = 8.0
|
||||
RAM_1500_PHASE_SPEED_FULL = 15.0
|
||||
RAM_1500_PHASE_LAT_ONSET = 0.25
|
||||
RAM_1500_PHASE_LAT_WIDTH = 0.12
|
||||
RAM_1500_TURN_IN_FF_BOOST = 0.06
|
||||
RAM_1500_UNWIND_FF_REDUCTION = 0.10
|
||||
RAM_1500_UNWIND_FF_REDUCTION = 0.05
|
||||
|
||||
# The Kona route is exceptionally accurate below highway speed, but Pop V2
|
||||
# reverses the requested lateral acceleration roughly once per second at
|
||||
@@ -934,6 +974,11 @@ KONA_NON_SCC_CENTER_TAPER_MAX = 0.14
|
||||
KONA_NON_SCC_CENTER_TAPER_LAT = 0.28
|
||||
KONA_NON_SCC_CENTER_TAPER_SPEED_ONSET = 12.0
|
||||
KONA_NON_SCC_CENTER_TAPER_SPEED_FULL = 24.0
|
||||
KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_GAIN = 0.14
|
||||
KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_LAT = 0.28
|
||||
KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_LAT_WIDTH = 0.07
|
||||
KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_SPEED_ONSET = 11.0
|
||||
KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_SPEED_WIDTH = 2.5
|
||||
|
||||
TRAILER_LOAD_FULL_ASSIST_KG = 15000.0 * CV.LB_TO_KG
|
||||
TRAILER_LATERAL_MIN_SPEED = 15.0 * CV.MPH_TO_MS
|
||||
@@ -1194,6 +1239,22 @@ def get_prius_center_taper_scale(desired_lateral_accel: float, v_ego: float) ->
|
||||
return 1.0 - reduction
|
||||
|
||||
|
||||
def get_prius_friction_jerk_deadzone(v_ego: float, desired_lateral_accel: float) -> float:
|
||||
speed_weight = _prius_sigmoid((v_ego - PRIUS_FRICTION_JERK_DEADZONE_SPEED) /
|
||||
PRIUS_FRICTION_JERK_DEADZONE_SPEED_WIDTH)
|
||||
center_weight = _prius_sigmoid((PRIUS_FRICTION_JERK_DEADZONE_LAT - abs(desired_lateral_accel)) /
|
||||
PRIUS_FRICTION_JERK_DEADZONE_LAT_WIDTH)
|
||||
return PRIUS_FRICTION_JERK_DEADZONE_MAX * speed_weight * center_weight
|
||||
|
||||
|
||||
def get_prius_high_speed_output_taper_scale(desired_lateral_accel: float, v_ego: float) -> float:
|
||||
speed_weight = _prius_sigmoid((v_ego - PRIUS_HIGH_SPEED_OUTPUT_TAPER_SPEED) /
|
||||
PRIUS_HIGH_SPEED_OUTPUT_TAPER_SPEED_WIDTH)
|
||||
curve_weight = _prius_sigmoid((abs(desired_lateral_accel) - PRIUS_HIGH_SPEED_OUTPUT_TAPER_LAT) /
|
||||
PRIUS_HIGH_SPEED_OUTPUT_TAPER_LAT_WIDTH)
|
||||
return 1.0 - PRIUS_HIGH_SPEED_OUTPUT_TAPER_MAX * speed_weight * curve_weight
|
||||
|
||||
|
||||
def get_camry_friction_threshold(v_ego: float, desired_lateral_accel: float = 0.0,
|
||||
desired_lateral_jerk: float = 0.0) -> float:
|
||||
del desired_lateral_jerk
|
||||
@@ -1312,8 +1373,13 @@ def get_sienna_4th_gen_friction_threshold(v_ego: float, desired_lateral_accel: f
|
||||
del desired_lateral_jerk
|
||||
center_weight = _sigmoid((SIENNA_4TH_GEN_FRICTION_CENTER_LAT - abs(desired_lateral_accel)) /
|
||||
SIENNA_4TH_GEN_FRICTION_CENTER_LAT_WIDTH)
|
||||
high_speed_weight = _sigmoid((v_ego - SIENNA_4TH_GEN_HIGH_SPEED_FRICTION_SPEED_ONSET) /
|
||||
SIENNA_4TH_GEN_HIGH_SPEED_FRICTION_SPEED_WIDTH)
|
||||
return get_standard_friction_threshold(v_ego) * (
|
||||
1.0 + SIENNA_4TH_GEN_FRICTION_THRESHOLD_GAIN * center_weight * _sienna_4th_gen_friction_speed_weight(v_ego)
|
||||
1.0 + center_weight * (
|
||||
SIENNA_4TH_GEN_FRICTION_THRESHOLD_GAIN * _sienna_4th_gen_friction_speed_weight(v_ego) +
|
||||
SIENNA_4TH_GEN_HIGH_SPEED_FRICTION_THRESHOLD_GAIN * high_speed_weight
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -1392,6 +1458,18 @@ def get_kona_non_scc_highway_transition_output_scale(desired_lateral_accel: floa
|
||||
return 1.0 - (taper_max * speed_weight * jerk_weight * lat_weight)
|
||||
|
||||
|
||||
def get_kona_non_scc_friction_threshold(v_ego: float, desired_lateral_accel: float = 0.0,
|
||||
desired_lateral_jerk: float = 0.0) -> float:
|
||||
del desired_lateral_jerk
|
||||
speed_weight = _sigmoid((v_ego - KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_SPEED_ONSET) /
|
||||
KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_SPEED_WIDTH)
|
||||
center_weight = _sigmoid((KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_LAT - abs(desired_lateral_accel)) /
|
||||
KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_LAT_WIDTH)
|
||||
return get_standard_friction_threshold(v_ego) * (
|
||||
1.0 + KONA_NON_SCC_CENTER_FRICTION_THRESHOLD_GAIN * speed_weight * center_weight
|
||||
)
|
||||
|
||||
|
||||
def get_kona_non_scc_center_taper_scale(desired_lateral_accel: float, v_ego: float) -> float:
|
||||
speed_weight = float(np.interp(v_ego, [KONA_NON_SCC_CENTER_TAPER_SPEED_ONSET, KONA_NON_SCC_CENTER_TAPER_SPEED_FULL], [0.0, 1.0]))
|
||||
center_weight = float(np.interp(abs(desired_lateral_accel), [0.0, KONA_NON_SCC_CENTER_TAPER_LAT], [1.0, 0.0]))
|
||||
@@ -2684,6 +2762,14 @@ def get_ioniq_6_friction_center_fade_scale(desired_lateral_accel: float, v_ego:
|
||||
return 1.0 - IONIQ_6_FRICTION_CENTER_FADE_MAX * speed_weight * center_weight
|
||||
|
||||
|
||||
def get_ioniq_6_2025_center_output_scale(desired_lateral_accel: float, v_ego: float) -> float:
|
||||
speed_weight = _ioniq_6_sigmoid((v_ego - IONIQ_6_2025_CENTER_OUTPUT_TAPER_SPEED) /
|
||||
IONIQ_6_2025_CENTER_OUTPUT_TAPER_SPEED_WIDTH)
|
||||
center_weight = _ioniq_6_sigmoid((IONIQ_6_2025_CENTER_OUTPUT_TAPER_LAT - abs(desired_lateral_accel)) /
|
||||
IONIQ_6_2025_CENTER_OUTPUT_TAPER_LAT_WIDTH)
|
||||
return 1.0 - IONIQ_6_2025_CENTER_OUTPUT_TAPER_MAX * speed_weight * center_weight
|
||||
|
||||
|
||||
def get_ioniq_6_center_taper_scale(desired_lateral_accel: float, v_ego: float) -> float:
|
||||
speed_weight = _ioniq_6_sigmoid((v_ego - IONIQ_6_CENTER_TAPER_SPEED) / IONIQ_6_CENTER_TAPER_SPEED_WIDTH)
|
||||
center_weight = _ioniq_6_sigmoid((IONIQ_6_CENTER_TAPER_LAT - abs(desired_lateral_accel)) / IONIQ_6_CENTER_TAPER_LAT_WIDTH)
|
||||
|
||||
@@ -286,6 +286,9 @@ class LongControl:
|
||||
|
||||
else: # LongCtrlState.pid
|
||||
a_target = self.vehicle_tuning.shape_gm_truck_accel_target(a_target, CS.vEgo, should_stop)
|
||||
a_target = self.vehicle_tuning.shape_toyota_corolla_accel_target(
|
||||
a_target, CS.vEgo, should_stop, self.last_output_accel,
|
||||
)
|
||||
a_target = self.vehicle_tuning.shape_toyota_sienna_accel_target(
|
||||
a_target, CS.vEgo, should_stop, leads=leads,
|
||||
)
|
||||
|
||||
@@ -34,6 +34,11 @@ TOYOTA_SIENNA_COMFORT_FILTER_MIN_TTC = 4.5
|
||||
TOYOTA_SIENNA_COMFORT_FILTER_MAX_CLOSING_SPEED = 4.0
|
||||
TOYOTA_SIENNA_COMFORT_FILTER_MAX_LEAD_BRAKE = 2.5
|
||||
TOYOTA_SIENNA_COMFORT_FILTER_BRAKE_BYPASS = -2.5
|
||||
TOYOTA_COROLLA_TARGET_FILTER_MAX_SPEED = 3.0
|
||||
TOYOTA_COROLLA_TARGET_FILTER_UP_TAU = 0.30
|
||||
TOYOTA_COROLLA_TARGET_FILTER_DOWN_TAU = 0.18
|
||||
TOYOTA_COROLLA_TARGET_FILTER_BRAKE_BYPASS = -0.75
|
||||
TOYOTA_COROLLA_TARGET_FILTER_DROP_BYPASS = 0.45
|
||||
VOLT_CRUISE_INTEGRATOR_MIN_SPEED = 8.0
|
||||
VOLT_CRUISE_INTEGRATOR_TARGET_MAX = 0.12
|
||||
VOLT_CRUISE_INTEGRATOR_ERROR_MAX = 0.12
|
||||
@@ -106,6 +111,10 @@ class LongControlVehicleTuning:
|
||||
CP.brand == "toyota" and
|
||||
getattr(CP, "carFingerprint", None) == TOYOTA_CAR.TOYOTA_SIENNA_4TH_GEN
|
||||
)
|
||||
self.is_toyota_corolla_tss2 = bool(
|
||||
CP.brand == "toyota" and
|
||||
getattr(CP, "carFingerprint", None) == TOYOTA_CAR.TOYOTA_COROLLA_TSS2
|
||||
)
|
||||
self.is_bolt_acc_pedal_friction_car = bool(
|
||||
CP.brand == "gm" and
|
||||
CP.enableGasInterceptorDEPRECATED and
|
||||
@@ -121,6 +130,8 @@ class LongControlVehicleTuning:
|
||||
self.gm_truck_target_filter_initialized = False
|
||||
self.toyota_sienna_filtered_a_target = 0.0
|
||||
self.toyota_sienna_target_filter_initialized = False
|
||||
self.toyota_corolla_filtered_a_target = 0.0
|
||||
self.toyota_corolla_target_filter_initialized = False
|
||||
self.bolt_start_handoff_frames = 0
|
||||
|
||||
def apply_bolt_start_handoff_floor(self, output_accel, last_output_accel, a_target, v_ego,
|
||||
@@ -226,6 +237,31 @@ class LongControlVehicleTuning:
|
||||
self.toyota_sienna_filtered_a_target += alpha * (float(a_target) - self.toyota_sienna_filtered_a_target)
|
||||
return self.toyota_sienna_filtered_a_target
|
||||
|
||||
def shape_toyota_corolla_accel_target(self, a_target, v_ego, should_stop, last_output_accel):
|
||||
"""Smooth low-speed Corolla TSS2 stop releases without delaying hard braking."""
|
||||
if not self.is_toyota_corolla_tss2 or should_stop or v_ego >= TOYOTA_COROLLA_TARGET_FILTER_MAX_SPEED:
|
||||
self.toyota_corolla_target_filter_initialized = False
|
||||
return a_target
|
||||
|
||||
if not self.toyota_corolla_target_filter_initialized:
|
||||
self.toyota_corolla_filtered_a_target = float(last_output_accel)
|
||||
self.toyota_corolla_target_filter_initialized = True
|
||||
|
||||
bypass_filter = (
|
||||
a_target <= TOYOTA_COROLLA_TARGET_FILTER_BRAKE_BYPASS or
|
||||
a_target < self.toyota_corolla_filtered_a_target - TOYOTA_COROLLA_TARGET_FILTER_DROP_BYPASS
|
||||
)
|
||||
if bypass_filter:
|
||||
self.toyota_corolla_filtered_a_target = float(a_target)
|
||||
return float(a_target)
|
||||
|
||||
tau = (TOYOTA_COROLLA_TARGET_FILTER_DOWN_TAU
|
||||
if a_target < self.toyota_corolla_filtered_a_target
|
||||
else TOYOTA_COROLLA_TARGET_FILTER_UP_TAU)
|
||||
alpha = DT_CTRL / (tau + DT_CTRL)
|
||||
self.toyota_corolla_filtered_a_target += alpha * (float(a_target) - self.toyota_corolla_filtered_a_target)
|
||||
return self.toyota_corolla_filtered_a_target
|
||||
|
||||
def get_integrator_freeze(self, last_output_accel, a_target, error, v_ego, accel_limits):
|
||||
volt_test_tune_handoff = self.is_volt and testing_ground.use_2
|
||||
|
||||
|
||||
@@ -786,7 +786,7 @@ class LongitudinalMpc:
|
||||
|
||||
def get_vision_follow_cruise_hold(self, prev_source, lead_one, lead_two,
|
||||
lead_0_obstacle, lead_1_obstacle, cruise_obstacle,
|
||||
v_ego, t_follow, tracking_lead):
|
||||
v_ego, t_follow, tracking_lead, *, early_follow=False):
|
||||
if not tracking_lead or prev_source not in ("lead0", "lead1"):
|
||||
return None
|
||||
|
||||
@@ -795,7 +795,24 @@ class LongitudinalMpc:
|
||||
return None
|
||||
if float(getattr(prev_lead, "modelProb", 0.0)) < VISION_FOLLOW_CRUISE_HOLD_MIN_MODEL_PROB:
|
||||
return None
|
||||
if self.get_stable_follow_cruise_hysteresis(prev_lead, v_ego, t_follow) <= 0.0:
|
||||
if early_follow:
|
||||
# Silverado admits a credible centered vision lead before it reaches the
|
||||
# normal matched-follow window. Hold that lead through the harmless
|
||||
# cruise/lead crossover, but never through a closing or braking lead.
|
||||
relative_speed = float(v_ego) - float(prev_lead.vLead)
|
||||
actual_headway = float(prev_lead.dRel) / max(float(v_ego), 1e-3)
|
||||
if (
|
||||
float(v_ego) < 18.0 or
|
||||
abs(relative_speed) > 2.5 or
|
||||
actual_headway < 0.95 or
|
||||
actual_headway > 2.35 or
|
||||
float(prev_lead.dRel) > 130.0 or
|
||||
abs(float(getattr(prev_lead, "yRel", 0.0))) > 1.2 or
|
||||
max(0.0, -float(getattr(prev_lead, "aLeadK", 0.0))) > 0.35 or
|
||||
float(getattr(prev_lead, "modelProb", 0.0)) < 0.95
|
||||
):
|
||||
return None
|
||||
elif self.get_stable_follow_cruise_hysteresis(prev_lead, v_ego, t_follow) <= 0.0:
|
||||
return None
|
||||
|
||||
prev_lead_obstacle = float(lead_0_obstacle if prev_source == "lead0" else lead_1_obstacle)
|
||||
@@ -845,7 +862,7 @@ class LongitudinalMpc:
|
||||
def update(self, radarstate, v_cruise, x, v, a, j, danger_factor, t_follow,
|
||||
personality=log.LongitudinalPersonality.standard, tracking_lead=True,
|
||||
optional_far_lead_comfort=True, smooth_duplicate_vision=False,
|
||||
stop_x=None):
|
||||
stop_x=None, silverado_early_follow=False):
|
||||
v_ego = self.x0[1]
|
||||
lead_one = radarstate.leadOne
|
||||
lead_two = radarstate.leadTwo
|
||||
@@ -939,6 +956,7 @@ class LongitudinalMpc:
|
||||
v_ego,
|
||||
t_follow,
|
||||
tracking_lead,
|
||||
early_follow=silverado_early_follow,
|
||||
)
|
||||
self.source = sticky_source or candidate_source
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ from openpilot.selfdrive.controls.lib.lead_follow_policy import apply as apply_f
|
||||
from openpilot.selfdrive.controls.lib.lead_follow_policy import is_nonurgent_duplicate_vision_follow
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_vehicle_tunes import (
|
||||
get_far_follow_output_slew_rates,
|
||||
get_follow_prebrake_min_headway,
|
||||
is_gm_silverado_early_follow_lead,
|
||||
get_toyota_sienna_post_departure_restop_cap,
|
||||
get_untracked_slow_lead_decel_scale,
|
||||
@@ -2183,7 +2184,8 @@ class LongitudinalPlanner:
|
||||
personality=personality, tracking_lead=lead_control_active,
|
||||
optional_far_lead_comfort=True,
|
||||
smooth_duplicate_vision=nonurgent_duplicate_vision_follow and not panic_bypass,
|
||||
stop_x=force_stop_x)
|
||||
stop_x=force_stop_x,
|
||||
silverado_early_follow=early_truck_follow)
|
||||
|
||||
self.a_desired_trajectory_full = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.a_solution)
|
||||
self.v_desired_trajectory = np.interp(CONTROL_N_T_IDX, T_IDXS_MPC, self.mpc.v_solution)
|
||||
@@ -2212,7 +2214,7 @@ class LongitudinalPlanner:
|
||||
if lead_one_active:
|
||||
rel_v = max(0.0, v_ego - self.lead_one.vLead)
|
||||
# dynamic time headway adds a small buffer when uncertainty is elevated
|
||||
base_th = max(1.6, effective_t_follow)
|
||||
base_th = get_follow_prebrake_min_headway(self.CP, effective_t_follow)
|
||||
th = base_th + 0.6 * max(0.0, uncertainty - 0.42)
|
||||
desired_gap = th * v_ego
|
||||
if (self.lead_dist_f is not None and self.lead_dist_f < desired_gap and rel_v > 0.5):
|
||||
|
||||
@@ -8,6 +8,7 @@ GM_SILVERADO_EARLY_FOLLOW_MIN_EGO_SPEED = 18.0
|
||||
GM_SILVERADO_EARLY_FOLLOW_MAX_DISTANCE = 130.0
|
||||
GM_SILVERADO_EARLY_FOLLOW_MIN_MODEL_PROB = 0.85
|
||||
GM_SILVERADO_EARLY_FOLLOW_MAX_LATERAL_OFFSET = 1.2
|
||||
GM_SILVERADO_FOLLOW_PREBRAKE_MIN_HEADWAY = 1.25
|
||||
TOYOTA_SIENNA_POST_DEPARTURE_RESTOP_MAX_EGO_SPEED = 2.0
|
||||
TOYOTA_SIENNA_POST_DEPARTURE_RESTOP_MAX_LEAD_SPEED = 0.45
|
||||
TOYOTA_SIENNA_POST_DEPARTURE_RESTOP_MAX_LEAD_DELTA = 0.35
|
||||
@@ -47,6 +48,13 @@ def is_gm_silverado_early_follow_lead(CP, lead, v_ego):
|
||||
return True
|
||||
|
||||
|
||||
def get_follow_prebrake_min_headway(CP, t_follow):
|
||||
"""Return the comfort pre-brake floor without changing lead safety distance."""
|
||||
if CP.brand == "gm" and str(CP.carFingerprint) in ("CHEVROLET_SILVERADO", "CHEVROLET_SILVERADO_CC"):
|
||||
return max(float(t_follow), GM_SILVERADO_FOLLOW_PREBRAKE_MIN_HEADWAY)
|
||||
return max(float(t_follow), 1.6)
|
||||
|
||||
|
||||
def get_toyota_sienna_post_departure_restop_cap(CP, lead, v_ego, accel_min,
|
||||
stop_distance, now_t, departure_latch_until):
|
||||
"""Re-arm a stop if a Sienna's lead twitches forward and stops again."""
|
||||
|
||||
@@ -28,9 +28,11 @@ from openpilot.selfdrive.controls.lib.latcontrol_vehicle_tunes import (
|
||||
get_flm_runtime_overrides,
|
||||
get_hkg_canfd_base_friction_threshold,
|
||||
get_kona_non_scc_center_taper_scale,
|
||||
get_kona_non_scc_friction_threshold,
|
||||
get_kona_non_scc_highway_transition_output_scale,
|
||||
KIA_FORTE_BASE_LAT_ACCEL_FACTOR_MULT,
|
||||
RAM_1500_BASE_LAT_ACCEL_FACTOR_MULT,
|
||||
RAM_1500_MAX_LAT_JERK_UP,
|
||||
get_ram_1500_transition_output_scale,
|
||||
get_ram_1500_ff_scale,
|
||||
get_subaru_impreza_pid_output_scale,
|
||||
@@ -72,6 +74,8 @@ from openpilot.selfdrive.controls.lib.latcontrol_torque import (
|
||||
get_prius_ff_scale,
|
||||
get_prius_friction_scale,
|
||||
get_prius_friction_threshold,
|
||||
get_prius_friction_jerk_deadzone,
|
||||
get_prius_high_speed_output_taper_scale,
|
||||
get_camry_friction_threshold,
|
||||
get_rav4_prime_ff_scale,
|
||||
get_rav4_prime_friction_scale,
|
||||
@@ -97,6 +101,8 @@ from openpilot.selfdrive.controls.lib.latcontrol_torque import (
|
||||
get_ioniq_6_friction_scale,
|
||||
get_ioniq_6_friction_threshold,
|
||||
get_ioniq_6_low_speed_angle_assist_torque,
|
||||
get_ioniq_6_2025_center_output_scale,
|
||||
is_ioniq_6_2025_model,
|
||||
get_kia_forte_center_taper_scale,
|
||||
get_kia_forte_ff_scale,
|
||||
get_kia_carnival_center_taper_scale,
|
||||
@@ -702,6 +708,11 @@ class TestLatControl:
|
||||
assert right_turn_in_scale == left_turn_in_scale > base_scale
|
||||
assert base_scale > left_unwind_scale == right_unwind_scale
|
||||
|
||||
assert get_prius_friction_jerk_deadzone(30.0, 0.0) > get_prius_friction_jerk_deadzone(30.0, 0.8)
|
||||
assert get_prius_friction_jerk_deadzone(8.0, 0.0) < 0.05
|
||||
assert get_prius_high_speed_output_taper_scale(30.0, 0.0) > get_prius_high_speed_output_taper_scale(30.0, 0.8)
|
||||
assert get_prius_high_speed_output_taper_scale(15.0, 0.8) > 0.99
|
||||
|
||||
def test_camry_friction_threshold_only_fades_in_for_calm_high_speed(self):
|
||||
low_speed_center = get_camry_friction_threshold(10.0, 0.0)
|
||||
high_speed_center = get_camry_friction_threshold(32.0, 0.0)
|
||||
@@ -811,7 +822,12 @@ class TestLatControl:
|
||||
base = get_standard_friction_threshold(9.0)
|
||||
center = get_sienna_4th_gen_friction_threshold(9.0, 0.0)
|
||||
turn = get_sienna_4th_gen_friction_threshold(9.0, 0.8)
|
||||
highway_base = get_standard_friction_threshold(28.0)
|
||||
highway_center = get_sienna_4th_gen_friction_threshold(28.0, 0.0)
|
||||
highway_turn = get_sienna_4th_gen_friction_threshold(28.0, 0.8)
|
||||
assert center > turn >= base
|
||||
assert highway_center > highway_base
|
||||
assert highway_turn < highway_center
|
||||
|
||||
calm = get_sienna_4th_gen_center_taper_scale(0.0, 8.0)
|
||||
turn_taper = get_sienna_4th_gen_center_taper_scale(0.8, 8.0)
|
||||
@@ -856,6 +872,18 @@ class TestLatControl:
|
||||
assert get_ram_1500_ff_scale(1.2, -1.1, 17.0) < 1.0
|
||||
assert get_ram_1500_ff_scale(1.2, 1.1, 6.0) < get_ram_1500_ff_scale(1.2, 1.1, 17.0)
|
||||
|
||||
def test_ram_1500_jerk_limit_update_path(self):
|
||||
controller, VM, CS, params, starpilot_toggles = self._build_torque_controller(CHRYSLER.RAM_1500_5TH_GEN)
|
||||
jerk_samples = []
|
||||
for i in range(100):
|
||||
_, _, lac_log = controller.update(
|
||||
True, CS, VM, params, False, 0.0025 * i, False, 0.2, None, None, starpilot_toggles,
|
||||
)
|
||||
jerk_samples.append(abs(lac_log.desiredLateralJerk))
|
||||
|
||||
assert max(jerk_samples) <= RAM_1500_MAX_LAT_JERK_UP + 1e-6
|
||||
assert max(jerk_samples) > RAM_1500_MAX_LAT_JERK_UP - 0.05
|
||||
|
||||
def test_ram_1500_transition_taper_update_path(self, monkeypatch):
|
||||
controller, VM, CS, params, starpilot_toggles = self._build_torque_controller(CHRYSLER.RAM_1500_5TH_GEN)
|
||||
base_output, _, lac_log = controller.update(
|
||||
@@ -910,6 +938,16 @@ class TestLatControl:
|
||||
assert get_kona_non_scc_center_taper_scale(0.28, 25.0) == pytest.approx(1.0)
|
||||
assert get_kona_non_scc_center_taper_scale(0.10, 25.0) < get_kona_non_scc_center_taper_scale(0.10, 15.0)
|
||||
|
||||
def test_kona_non_scc_center_friction_threshold_is_speed_and_center_gated(self):
|
||||
low_speed = get_kona_non_scc_friction_threshold(3.0, 0.0)
|
||||
highway_base = get_standard_friction_threshold(25.0)
|
||||
highway_center = get_kona_non_scc_friction_threshold(25.0, 0.0)
|
||||
highway_curve = get_kona_non_scc_friction_threshold(25.0, 0.8)
|
||||
|
||||
assert low_speed == pytest.approx(get_standard_friction_threshold(3.0), abs=0.002)
|
||||
assert highway_center > highway_base
|
||||
assert highway_curve < highway_center
|
||||
|
||||
def test_kona_non_scc_highway_transition_taper_update_path(self, monkeypatch):
|
||||
controller, VM, CS, params, starpilot_toggles = self._build_torque_controller(HYUNDAI.HYUNDAI_KONA_NON_SCC)
|
||||
CS.vEgo = 30.0
|
||||
@@ -1049,6 +1087,21 @@ class TestLatControl:
|
||||
assert get_ioniq_6_friction_center_fade_scale(-0.5, 30.0) > 0.95
|
||||
assert get_ioniq_6_friction_center_fade_scale(0.0, 8.0) > 0.95
|
||||
|
||||
def test_ioniq_6_2025_variant_is_firmware_gated(self):
|
||||
old_cp = SimpleNamespace(
|
||||
carFingerprint=HYUNDAI.HYUNDAI_IONIQ_6,
|
||||
carFw=[SimpleNamespace(fwVersion=b"99211-KL000 221213"), SimpleNamespace(fwVersion=b"ADR 1.03 221205")],
|
||||
)
|
||||
new_cp = SimpleNamespace(
|
||||
carFingerprint=HYUNDAI.HYUNDAI_IONIQ_6,
|
||||
carFw=[SimpleNamespace(fwVersion=b"99211-KL000 230915"), SimpleNamespace(fwVersion=b"ADR 1.05 240206")],
|
||||
)
|
||||
|
||||
assert not is_ioniq_6_2025_model(old_cp)
|
||||
assert is_ioniq_6_2025_model(new_cp)
|
||||
assert get_ioniq_6_2025_center_output_scale(0.0, 28.0) < get_ioniq_6_2025_center_output_scale(0.5, 28.0)
|
||||
assert get_ioniq_6_2025_center_output_scale(0.0, 15.0) > 0.98
|
||||
|
||||
def test_ioniq_6_center_taper_curve(self):
|
||||
assert get_ioniq_6_center_taper_scale(0.0, 10.0) > get_ioniq_6_center_taper_scale(0.0, 30.0)
|
||||
assert get_ioniq_6_center_taper_scale(0.0, 30.0) < get_ioniq_6_center_taper_scale(0.2, 30.0)
|
||||
@@ -1079,7 +1132,7 @@ class TestLatControl:
|
||||
high_speed_center = get_kia_ev6_friction_threshold(34.0, 0.0, 0.0)
|
||||
high_speed_curve = get_kia_ev6_friction_threshold(34.0, 0.55, 0.0)
|
||||
|
||||
assert low_speed == pytest.approx(get_hkg_canfd_base_friction_threshold(10.0), abs=0.002)
|
||||
assert low_speed == pytest.approx(get_hkg_canfd_base_friction_threshold(10.0), abs=0.004)
|
||||
assert high_speed_center > get_hkg_canfd_base_friction_threshold(34.0)
|
||||
assert high_speed_curve < high_speed_center
|
||||
|
||||
|
||||
@@ -555,6 +555,63 @@ def test_update_releases_stopping_on_small_sustained_positive_target():
|
||||
assert lc.long_control_state == LongCtrlState.starting
|
||||
|
||||
|
||||
def test_corolla_tss2_stop_release_ramps_positive_target():
|
||||
CP = make_longcontrol_cp(
|
||||
brand="toyota",
|
||||
carFingerprint=TOYOTA_CAR.TOYOTA_COROLLA_TSS2,
|
||||
)
|
||||
tuning = vehicle_tunes.LongControlVehicleTuning(CP)
|
||||
tuning.reset()
|
||||
|
||||
first_target = tuning.shape_toyota_corolla_accel_target(1.5, 0.0, False, -0.15)
|
||||
assert first_target < 0.0
|
||||
assert first_target < 1.5
|
||||
|
||||
target = first_target
|
||||
for _ in range(100):
|
||||
target = tuning.shape_toyota_corolla_accel_target(1.5, 0.0, False, target)
|
||||
assert target > 1.4
|
||||
|
||||
for _ in range(100):
|
||||
target = tuning.shape_toyota_corolla_accel_target(1.5, 0.0, False, target)
|
||||
assert target == pytest.approx(1.5, abs=0.01)
|
||||
|
||||
|
||||
def test_corolla_tss2_target_filter_does_not_delay_hard_braking():
|
||||
CP = make_longcontrol_cp(
|
||||
brand="toyota",
|
||||
carFingerprint=TOYOTA_CAR.TOYOTA_COROLLA_TSS2,
|
||||
)
|
||||
tuning = vehicle_tunes.LongControlVehicleTuning(CP)
|
||||
tuning.shape_toyota_corolla_accel_target(1.0, 1.0, False, 0.0)
|
||||
|
||||
assert tuning.shape_toyota_corolla_accel_target(-1.0, 1.0, False, 0.5) == -1.0
|
||||
|
||||
|
||||
def test_corolla_tss2_longcontrol_release_does_not_step_to_full_accel():
|
||||
CP = make_longcontrol_cp(
|
||||
brand="toyota",
|
||||
carFingerprint=TOYOTA_CAR.TOYOTA_COROLLA_TSS2,
|
||||
)
|
||||
lc = LongControl(CP)
|
||||
lc.long_control_state = LongCtrlState.stopping
|
||||
lc.last_output_accel = -0.15
|
||||
CS = car.CarState.new_message(vEgo=0.0, aEgo=0.0, brakePressed=False)
|
||||
CS.cruiseState.standstill = False
|
||||
|
||||
output_accel = lc.update(
|
||||
active=True,
|
||||
CS=CS,
|
||||
a_target=1.5,
|
||||
should_stop=False,
|
||||
accel_limits=(-3.0, 2.0),
|
||||
starpilot_toggles=make_toggles(vEgoStarting=0.1),
|
||||
)
|
||||
|
||||
assert lc.long_control_state == LongCtrlState.pid
|
||||
assert output_accel < 0.0
|
||||
|
||||
|
||||
def test_update_releases_stopping_immediately_after_confirmed_lead_departure():
|
||||
CP = car.CarParams.new_message(startingState=True, vEgoStarting=0.5)
|
||||
CP.longitudinalTuning.kpBP = [0.0]
|
||||
|
||||
@@ -19,6 +19,7 @@ from openpilot.selfdrive.controls.lib.longitudinal_planner import LongitudinalPl
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc, soften_far_radar_lead_accel, should_trigger_planner_fcw
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_vehicle_tunes import (
|
||||
get_follow_prebrake_min_headway,
|
||||
get_toyota_sienna_post_departure_restop_cap,
|
||||
is_gm_silverado_early_follow_lead,
|
||||
)
|
||||
@@ -498,6 +499,31 @@ def test_gm_silverado_early_follow_requires_a_credible_centered_vision_lead(kwar
|
||||
assert not is_gm_silverado_early_follow_lead(CP, lead, 30.0)
|
||||
|
||||
|
||||
def test_silverado_prebrake_floor_is_vehicle_specific():
|
||||
silverado = SimpleNamespace(brand="gm", carFingerprint=GM_CAR.CHEVROLET_SILVERADO)
|
||||
honda = SimpleNamespace(brand="honda", carFingerprint=CAR.HONDA_CIVIC)
|
||||
|
||||
assert get_follow_prebrake_min_headway(silverado, 1.0) == pytest.approx(1.25)
|
||||
assert get_follow_prebrake_min_headway(honda, 1.0) == pytest.approx(1.6)
|
||||
|
||||
|
||||
def test_silverado_vision_follow_hold_survives_nonurgent_far_lead_crossover():
|
||||
v_ego = 32.0
|
||||
t_follow = 1.0
|
||||
CP = CarInterface.get_non_essential_params(CAR.HONDA_CIVIC)
|
||||
planner = LongitudinalPlanner(CP, init_v=v_ego)
|
||||
lead_one = make_lead(status=True, d_rel=70.0, v_lead=31.2, a_lead=-0.02, radar=False, model_prob=1.0, y_rel=0.1)
|
||||
lead_two = make_lead(status=False)
|
||||
|
||||
assert planner.mpc.get_vision_follow_cruise_hold(
|
||||
"lead0", lead_one, lead_two, 101.0, 200.0, 100.0, v_ego, t_follow, True,
|
||||
) is None
|
||||
assert planner.mpc.get_vision_follow_cruise_hold(
|
||||
"lead0", lead_one, lead_two, 101.0, 200.0, 100.0, v_ego, t_follow, True,
|
||||
early_follow=True,
|
||||
) == "lead0"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("model_version", ["v11", "v12", "v13", "v14", "v15"])
|
||||
def test_acc_mode_uses_far_near_stopped_radar_lead_before_tracking(model_version):
|
||||
v_ego = 24.6
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import io
|
||||
from types import SimpleNamespace
|
||||
|
||||
import numpy as np
|
||||
|
||||
@@ -25,31 +24,27 @@ def test_out_of_band_artifact_round_trip():
|
||||
|
||||
|
||||
def test_external_gpu_probe_retries_until_pcie_is_ready(monkeypatch):
|
||||
results = [SimpleNamespace(returncode=1, stdout="", stderr="LTSSM=0x00"),
|
||||
SimpleNamespace(returncode=0, stdout="", stderr="")]
|
||||
calls = []
|
||||
probe_count = 0
|
||||
def probe():
|
||||
nonlocal probe_count
|
||||
probe_count += 1
|
||||
calls.append("probe")
|
||||
return (False, "LTSSM=0x00") if probe_count < 3 else (True, "LTSSM=0x78")
|
||||
monkeypatch.setattr(
|
||||
model_compiler.subprocess,
|
||||
"run",
|
||||
lambda *args, **kwargs: calls.append((args, kwargs)) or results.pop(0),
|
||||
model_compiler,
|
||||
"_probe_external_gpu_link_once",
|
||||
probe,
|
||||
)
|
||||
monkeypatch.setattr(model_compiler.time, "sleep", lambda seconds: calls.append(("sleep", seconds)))
|
||||
|
||||
model_compiler.wait_for_external_gpu({"PYTHONPATH": "/tmp/openpilot"})
|
||||
|
||||
assert len(calls) == 3
|
||||
assert calls[0][1]["env"]["DEV"] == "USB+AMD"
|
||||
assert calls[1] == ("sleep", 1)
|
||||
assert calls == ["probe", ("sleep", 1), "probe", ("sleep", 1), "probe"]
|
||||
|
||||
|
||||
def test_external_gpu_probe_reports_failure(monkeypatch):
|
||||
result = SimpleNamespace(returncode=1, stdout="", stderr="link unavailable")
|
||||
monkeypatch.setattr(model_compiler.subprocess, "run", lambda *args, **kwargs: result)
|
||||
monkeypatch.setattr(model_compiler, "_probe_external_gpu_link_once", lambda: (False, "link unavailable"))
|
||||
monkeypatch.setattr(model_compiler.time, "sleep", lambda _: None)
|
||||
|
||||
try:
|
||||
model_compiler.wait_for_external_gpu({})
|
||||
except RuntimeError as error:
|
||||
assert "link unavailable" in str(error)
|
||||
else:
|
||||
raise AssertionError("external GPU probe unexpectedly succeeded")
|
||||
assert model_compiler.wait_for_external_gpu({}) is False
|
||||
|
||||
@@ -272,7 +272,7 @@ class ConditionalDriveModeView(AdjustorTogglesPanelView):
|
||||
"CESpeed": {"title": tr("Below Speed"), "subtitle": "", "min": 0, "max": max_speed, "step": 1.0, "unit": speed_unit, "presets": [0, 20, 35, 55, 75], "labels": {}, "get": lambda: float(self._controller._params.get_int("CESpeed"))},
|
||||
"CESpeedLead": {"title": tr("Speed w/ Lead"), "subtitle": "", "min": 0, "max": max_speed, "step": 1.0, "unit": speed_unit, "presets": [0, 20, 35, 55, 75], "labels": {}, "get": lambda: float(self._controller._params.get_int("CESpeedLead"))},
|
||||
"CESignalSpeed": {"title": tr("Turn Signal Below"), "subtitle": "", "min": 0, "max": max_speed, "step": 1.0, "unit": speed_unit, "presets": [0, 20, 35, 55, 75], "labels": {0.0: tr("Off")}, "get": lambda: float(self._controller._params.get_int("CESignalSpeed"))},
|
||||
"CEModelStopTime": {"title": tr("Predicted Stop In"), "subtitle": "", "min": 0, "max": 10.0, "step": 1.0, "unit": "s", "presets": [0, 3, 5, 9, 10], "labels": {0.0: tr("Off")}, "get": lambda: float(self._controller._params.get_int("CEModelStopTime"))},
|
||||
"CEModelStopTime": {"title": tr("Predicted Stop In"), "subtitle": "", "min": 0, "max": 10.0, "step": 0.1, "unit": "s", "presets": [0, 3, 5, 7.7, 10], "labels": {0.0: tr("Off")}, "get": lambda: float(self._controller._params.get_float("CEModelStopTime"))},
|
||||
"CCMSpeed": {"title": tr("Above Speed"), "subtitle": "", "min": 0, "max": max_speed, "step": 1.0, "unit": speed_unit, "presets": [0, 35, 55, 65, 80], "labels": {}, "get": lambda: float(self._controller._params.get_int("CCMSpeed"))},
|
||||
"CCMSpeedLead": {"title": tr("Speed w/ Lead"), "subtitle": "", "min": 0, "max": max_speed, "step": 1.0, "unit": speed_unit, "presets": [0, 35, 55, 65, 80], "labels": {}, "get": lambda: float(self._controller._params.get_int("CCMSpeedLead"))},
|
||||
"CCMSetSpeedMargin": {"title": tr("Set Speed Margin"), "subtitle": "", "min": 0, "max": 30.0 if is_metric else 15.0, "step": 1.0, "unit": speed_unit, "presets": [0, 5, 10, 15], "labels": {}, "get": lambda: float(self._controller._params.get_int("CCMSetSpeedMargin"))},
|
||||
@@ -306,22 +306,26 @@ class ConditionalDriveModeView(AdjustorTogglesPanelView):
|
||||
"CESpeed": {"title": tr("Below Speed"), "min": 0, "max": max_speed, "unit": speed_unit, "labels": {}, "presets": [0, 20, 35, 55, 75]},
|
||||
"CESpeedLead": {"title": tr("Speed w/ Lead"), "min": 0, "max": max_speed, "unit": speed_unit, "labels": {}, "presets": [0, 20, 35, 55, 75]},
|
||||
"CESignalSpeed": {"title": tr("Turn Signal Below"), "min": 0, "max": max_speed, "unit": speed_unit, "labels": {0.0: tr("Off")}, "presets": [0, 20, 35, 55, 75]},
|
||||
"CEModelStopTime": {"title": tr("Predicted Stop In"), "min": 0, "max": 10.0, "unit": "s", "labels": {0.0: tr("Off")}, "presets": [0, 3, 5, 9, 10]},
|
||||
"CEModelStopTime": {"title": tr("Predicted Stop In"), "min": 0, "max": 10.0, "unit": "s", "labels": {0.0: tr("Off")}, "presets": [0, 3, 5, 7.7, 10]},
|
||||
"CCMSpeed": {"title": tr("Above Speed"), "min": 0, "max": max_speed, "unit": speed_unit, "labels": {}, "presets": [0, 35, 55, 65, 80]},
|
||||
"CCMSpeedLead": {"title": tr("Speed w/ Lead"), "min": 0, "max": max_speed, "unit": speed_unit, "labels": {}, "presets": [0, 35, 55, 65, 80]},
|
||||
"CCMSetSpeedMargin": {"title": tr("Set Speed Margin"), "min": 0, "max": 30.0 if is_metric else 15.0, "unit": speed_unit, "labels": {}, "presets": [0, 5, 10, 15]},
|
||||
}
|
||||
|
||||
spec = specs[key]
|
||||
original_val = float(self._controller._params.get_int(key))
|
||||
is_float = key == "CEModelStopTime"
|
||||
original_val = float(self._controller._params.get_float(key) if is_float else self._controller._params.get_int(key))
|
||||
|
||||
def on_close(res, val):
|
||||
if res == DialogResult.CONFIRM:
|
||||
self._controller._params.put_int(key, int(val))
|
||||
if is_float:
|
||||
self._controller._params.put_float(key, float(val))
|
||||
else:
|
||||
self._controller._params.put_int(key, int(val))
|
||||
|
||||
gui_app.push_widget(AetherSliderDialog(
|
||||
title=spec["title"],
|
||||
min_val=float(spec["min"]), max_val=float(spec["max"]), step=1.0,
|
||||
min_val=float(spec["min"]), max_val=float(spec["max"]), step=0.1 if is_float else 1.0,
|
||||
current_val=original_val,
|
||||
on_close=on_close, presets=[float(p) for p in spec["presets"]],
|
||||
unit=spec["unit"], labels=spec["labels"], color=PANEL_STYLE.accent
|
||||
|
||||
@@ -291,11 +291,8 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
|
||||
} else if (param == "CCMSetSpeedMargin") {
|
||||
longitudinalToggle = new StarPilotParamValueControl(param, title, desc, icon, 0, 15, tr(" mph"), std::map<float, QString>(), 1, true, 175);
|
||||
} else if (param == "CEModelStopTime") {
|
||||
std::map<float, QString> stopTimeLabels;
|
||||
for (int i = 0; i <= 10; ++i) {
|
||||
stopTimeLabels[i] = i == 0 ? tr("Off") : i == 1 ? QString::number(i) + tr(" second") : QString::number(i) + tr(" seconds");
|
||||
}
|
||||
longitudinalToggle = new StarPilotParamValueControl(param, title, desc, icon, 0, 9, QString(), stopTimeLabels);
|
||||
std::map<float, QString> stopTimeLabels{{0.0f, tr("Off")}};
|
||||
longitudinalToggle = new StarPilotParamValueControl(param, title, desc, icon, 0, 9, tr(" seconds"), stopTimeLabels, 0.1);
|
||||
} else if (param == "CESignalSpeed") {
|
||||
std::vector<QString> ceSignalToggles{"CESignalLaneDetection"};
|
||||
std::vector<QString> ceSignalToggleNames{tr("Not For Detected Lanes")};
|
||||
|
||||
@@ -68,7 +68,7 @@ STARPILOT_PARAM_CANONICALIZATION_MIGRATION_FLAG = Path("/data") / "starpilot_par
|
||||
STARPILOT_PC_ROOT_MIGRATION_FLAG = Path("/data") / "starpilot_pc_root_v1"
|
||||
STARPILOT_PARAMS_CACHE_MIGRATION_FLAG = Path("/data") / "starpilot_params_cache_v1"
|
||||
STARPILOT_DEFAULT_MODEL_MIGRATION_FLAG = Path("/data") / "starpilot_default_model_rdf_v1"
|
||||
STARPILOT_CE_MODEL_STOP_TIME_MIGRATION_FLAG = Path("/data") / "starpilot_ce_model_stop_time_v1"
|
||||
STARPILOT_CE_MODEL_STOP_TIME_MIGRATION_FLAG = Path("/data") / "starpilot_ce_model_stop_time_v2"
|
||||
STARPILOT_LEGACY_CACHE_MARKER_KEYS = ("RemapCancelToDistance",)
|
||||
STARPILOT_REMOVED_PARAM_KEYS = ("CoastUpToLeads", "HumanAcceleration", "HumanFollowing", "PrioritizeSmoothFollowing")
|
||||
LEGACY_CARMODEL_MIGRATIONS = {
|
||||
@@ -561,8 +561,8 @@ def migrate_starpilot_default_parity(params: Params, params_cache: Params) -> No
|
||||
seeded_keys.append(key)
|
||||
|
||||
if not _has_persisted_param_file(params, "CEModelStopTime") and not _has_persisted_param_file(params_cache, "CEModelStopTime"):
|
||||
params.put_float("CEModelStopTime", 9.0)
|
||||
params_cache.put_float("CEModelStopTime", 9.0)
|
||||
params.put_float("CEModelStopTime", 7.7)
|
||||
params_cache.put_float("CEModelStopTime", 7.7)
|
||||
seeded_keys.append("CEModelStopTime")
|
||||
|
||||
# Rebase default regression fix:
|
||||
@@ -628,7 +628,7 @@ def migrate_starpilot_default_model(params: Params, params_cache: Params) -> Non
|
||||
|
||||
|
||||
def migrate_starpilot_ce_model_stop_time(params: Params, params_cache: Params) -> None:
|
||||
"""Move the old persisted 7-second stop prediction default to 9 seconds once."""
|
||||
"""Move persisted users of the old 9-second stop prediction threshold to 7.7 once."""
|
||||
if STARPILOT_CE_MODEL_STOP_TIME_MIGRATION_FLAG.exists():
|
||||
return
|
||||
|
||||
@@ -643,14 +643,14 @@ def migrate_starpilot_ce_model_stop_time(params: Params, params_cache: Params) -
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if abs(parsed_value - 7.0) < 1e-6:
|
||||
if abs(parsed_value - 9.0) < 1e-6:
|
||||
legacy_default_detected = True
|
||||
break
|
||||
|
||||
if legacy_default_detected:
|
||||
params.put_float("CEModelStopTime", 9.0)
|
||||
params_cache.put_float("CEModelStopTime", 9.0)
|
||||
cloudlog.warning("Migrated CEModelStopTime from 7 seconds to 9 seconds")
|
||||
params.put_float("CEModelStopTime", 7.7)
|
||||
params_cache.put_float("CEModelStopTime", 7.7)
|
||||
cloudlog.warning("Migrated CEModelStopTime from 9 seconds to 7.7 seconds")
|
||||
|
||||
try:
|
||||
STARPILOT_CE_MODEL_STOP_TIME_MIGRATION_FLAG.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -240,6 +240,17 @@ class TestManager:
|
||||
assert params.get("CEModelStopTime") == "3.5"
|
||||
assert params_cache.get_bool("NNFF")
|
||||
|
||||
def test_migrate_starpilot_default_parity_seeds_new_model_stop_time_default(self, tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(manager, "STARPILOT_DEFAULTS_PARITY_MIGRATION_FLAG", tmp_path / "starpilot_defaults_parity_v1")
|
||||
|
||||
params = FileBackedFakeParams(tmp_path / "params")
|
||||
params_cache = FileBackedFakeParams(tmp_path / "cache")
|
||||
|
||||
manager.migrate_starpilot_default_parity(params, params_cache)
|
||||
|
||||
assert params.get("CEModelStopTime") == "7.7"
|
||||
assert params_cache.get("CEModelStopTime") == "7.7"
|
||||
|
||||
def test_migrate_starpilot_default_model(self, tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(manager, "STARPILOT_DEFAULT_MODEL_MIGRATION_FLAG", tmp_path / "starpilot_default_model_rdf_v1")
|
||||
|
||||
@@ -262,17 +273,28 @@ class TestManager:
|
||||
assert manager.STARPILOT_DEFAULT_MODEL_MIGRATION_FLAG.exists()
|
||||
|
||||
def test_migrate_starpilot_ce_model_stop_time(self, tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(manager, "STARPILOT_CE_MODEL_STOP_TIME_MIGRATION_FLAG", tmp_path / "starpilot_ce_model_stop_time_v1")
|
||||
monkeypatch.setattr(manager, "STARPILOT_CE_MODEL_STOP_TIME_MIGRATION_FLAG", tmp_path / "starpilot_ce_model_stop_time_v2")
|
||||
|
||||
params = FileBackedFakeParams(tmp_path / "params", {"CEModelStopTime": 7.0})
|
||||
params = FileBackedFakeParams(tmp_path / "params", {"CEModelStopTime": 9.0})
|
||||
params_cache = FileBackedFakeParams(tmp_path / "cache")
|
||||
|
||||
manager.migrate_starpilot_ce_model_stop_time(params, params_cache)
|
||||
|
||||
assert params.get("CEModelStopTime") == "9.0"
|
||||
assert params_cache.get("CEModelStopTime") == "9.0"
|
||||
assert params.get("CEModelStopTime") == "7.7"
|
||||
assert params_cache.get("CEModelStopTime") == "7.7"
|
||||
assert manager.STARPILOT_CE_MODEL_STOP_TIME_MIGRATION_FLAG.exists()
|
||||
|
||||
def test_migrate_starpilot_ce_model_stop_time_preserves_custom_value(self, tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(manager, "STARPILOT_CE_MODEL_STOP_TIME_MIGRATION_FLAG", tmp_path / "starpilot_ce_model_stop_time_v2")
|
||||
|
||||
params = FileBackedFakeParams(tmp_path / "params", {"CEModelStopTime": 8.0})
|
||||
params_cache = FileBackedFakeParams(tmp_path / "cache", {"CEModelStopTime": 8.0})
|
||||
|
||||
manager.migrate_starpilot_ce_model_stop_time(params, params_cache)
|
||||
|
||||
assert params.get("CEModelStopTime") == "8.0"
|
||||
assert params_cache.get("CEModelStopTime") == "8.0"
|
||||
|
||||
def test_migrate_disable_humanlike_defaults(self, tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(manager, "STARPILOT_HUMANLIKE_DISABLE_MIGRATION_FLAG", tmp_path / "starpilot_humanlike_disable_v1")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user