Compare commits

...

1125 Commits

Author SHA1 Message Date
firestar5683 5fad2a9154 Fix manager toggle startup 2026-08-03 14:07:36 -05:00
firestar5683 9b7f1222e8 dec 2026-08-03 13:46:33 -05:00
firestar5683 ff12e1fe8f build 2026-08-03 13:36:19 -05:00
firestar5683 d7498e7a93 Sync Dom non-planner updates 2026-08-03 13:27:23 -05:00
whoisdomi 22f19ad578 Becca 2026-07-24 16:09:26 -05:00
firestar5683 225e98ed58 The Crimson Night 2026-07-24 02:01:57 -05:00
firestar5683 66af0216b9 fix socket 2026-07-24 01:02:05 -05:00
firestar5683 779b42d8ea 11.8 2026-07-24 00:24:13 -05:00
firestar5683 f5f846f5b6 Pause vision inference while parked
Co-Authored-By: Prabhaav Pillai <143428353+prabhaavp@users.noreply.github.com>
2026-07-24 00:08:26 -05:00
firestar5683 d8b6e43a0d Fix vision CPU throttling with offline cores 2026-07-23 15:20:05 -05:00
firestar5683 b72042042f Sip-smiling away 2026-07-23 14:37:54 -05:00
firestar5683 bd6dced538 Update device_settings_layout.json 2026-07-23 14:13:44 -05:00
firestar5683 66245a5a2e flm update 2026-07-23 10:58:17 -05:00
firestar5683 d4a3bc0f5c offroad alert key 2026-07-23 09:15:19 -05:00
firestarsdog fcc5cc359e Big UI : Aethergauge cleanup 2026-07-23 01:20:47 -04:00
firestar5683 aa381d4d97 BUMP 2026-07-23 00:12:31 -05:00
firestar5683 bc3f215764 build 2026-07-23 00:11:05 -05:00
firestar5683 daf0f84bc9 What If You Lived On The Bottom Of A Rubber Duck? 2026-07-23 00:10:19 -05:00
firestar5683 b945d4c021 Add vision adjacent spot monitoring
Integrate V-ASM from PR #75 with Galaxy-only configuration, stale-state safety, conditional SLV coexistence, and OpenCV inference.

Originally contributed by @prabhaavp in #75.

Co-authored-by: Prabhaav Pillai <143428353+prabhaavp@users.noreply.github.com>
2026-07-23 00:05:43 -05:00
jc01rho 9f1066ce83 feat(lateral): add confidence-gated lane centering
Adapt the lane-centering implementation from PR #74 by @jc01rho.

Keep controls in Galaxy developer settings, add confidence and geometry gates, preserve E2E path authority, and reset all related offsets through Safe Mode.
2026-07-23 00:03:23 -05:00
firestarsdog 370654637a Big UI : Map Data update 2026-07-22 21:08:38 -04:00
firestar5683 fb854cecd3 build 2026-07-22 19:36:10 -05:00
firestar5683 713ce294cc revert can ignition 2026-07-22 19:27:37 -05:00
firestarsdog 7450b9de9a Big UI : Speed Racer 2026-07-22 17:12:48 -04:00
firestarsdog 5b2b053afd Big UI Camera Fix - Fix Replay 2026-07-22 16:58:54 -04:00
firestar5683 88be0e6387 beeg 2026-07-22 15:41:34 -05:00
firestar5683 cc5c95705d jwarm 2026-07-22 15:32:02 -05:00
firestar5683 d16d72afc6 mici fallback too 2026-07-22 14:16:16 -05:00
firestar5683 6230d08c0f Stutter in raybig? 2026-07-22 13:55:57 -05:00
firestar5683 48af4d2f7f build 2026-07-22 11:41:19 -05:00
firestar5683 d773ad9025 fixes 2026-07-22 11:38:35 -05:00
whoisdomi 894eae7090 Galaxy radar gate fix
Previously showed radartakeoffs and Human like lane changes to
non-radar cars.
2026-07-22 07:36:41 -05:00
firestarsdog 28fcba8471 Big UI : Quick Vehicle Panel Cleanup Pass 2026-07-21 21:14:32 -04:00
firestarsdog 0cff67bda8 Big UI: Try this Domi 2026-07-21 18:29:12 -04:00
firestar5683 f0eeec955f build 2026-07-21 17:18:00 -05:00
firestar5683 9b28c7bd52 Register vision support params 2026-07-21 17:17:11 -05:00
firestar5683 ef400a9b3f Same Subscriber 2026-07-21 17:15:10 -05:00
firestar5683 d4b3c3c3b0 final polish 2026-07-21 16:51:51 -05:00
firestar5683 c57c05886c panda 2026-07-21 15:21:39 -05:00
firestar5683 80f465616a Tone 2026-07-21 15:20:28 -05:00
firestar5683 4e70755895 tunes 2026-07-21 14:29:34 -05:00
firestar5683 5b41566e4e ev9 2026-07-21 13:39:36 -05:00
firestar5683 2141e5a5b1 cleanup 2026-07-21 13:24:01 -05:00
whoisdomi d51dd02d10 Turn Desire Bug 2 + Force Stop 2026-07-21 13:12:42 -05:00
whoisdomi bb3ed894b1 Lane Change Overshoot Edge Case
Latch entry direction instead of comparing to the command's live sign,
which broke once the command crossed zero during a curve's larger
arrest swing. This will prevent overshoot on curves.
2026-07-21 13:12:41 -05:00
whoisdomi d4c911f58c Turn Desire Bug
Blinker turn desire fed the model a turnLeft/turnRight input below lane-change
speed, inflating model_length so the car rolled past stop lines. Gate it in
desire_helper on prior-frame starpilotPlan.redLight/forcingStop/stopSignConfirmed
until standstill, then release so the model still turns through. "Stop first,
then turn."
2026-07-21 13:12:40 -05:00
firestar5683 fc87af4da1 hotplug 2026-07-21 12:22:47 -05:00
firestarsdog 7cd02e0c40 Big UI: Size up simple download manager 2026-07-21 12:53:42 -04:00
firestar5683 db8d38e85f build 2026-07-21 11:47:36 -05:00
firestar5683 2c7e6e72c5 PID Alerts 2026-07-21 11:45:22 -05:00
firestar5683 85dd1cbe7e Tunes 2026-07-21 11:35:29 -05:00
firestar5683 665f538533 test(hyundai): cover EV9 cluster safety message 2026-07-21 11:35:29 -05:00
LowkeyNEXT 28a4de1c9e safety(hyundai): allow EV9 CCNC angle-long messages 2026-07-21 11:35:28 -05:00
LowkeyNEXT 42eef3f21c feat(hyundai): add EV9 alpha longitudinal support 2026-07-21 11:35:28 -05:00
whoisdomi ce86d9d05a Start Accel bug fix 2026-07-21 11:35:28 -05:00
whoisdomi b70d0941c9 Traffic Mode v2 2026-07-21 11:35:28 -05:00
firestarsdog 8d7ba284d7 Big UI : Favorites + Downloaded 2026-07-21 11:57:51 -04:00
firestarsdog 71b577cbc2 Big UI: Default to expanded while I think 2026-07-21 11:29:18 -04:00
firestar5683 cc40a28562 home cleanup 2026-07-20 23:53:20 -05:00
firestar5683 104ae74901 sped away 2026-07-20 23:22:06 -05:00
firestar5683 2e45e57287 Young Cheddar 2026-07-20 22:49:09 -05:00
firestar5683 10843b2f6e log 2026-07-20 21:59:42 -05:00
firestar5683 eb3eb116eb The Fairlife Milk Out of Stock Ya'll 2026-07-20 21:34:47 -05:00
firestar5683 b34e968f91 But Bigger 2026-07-20 20:51:04 -05:00
firestar5683 3701079265 icon 2026-07-20 20:11:18 -05:00
firestarsdog 1a713fe3e2 Big UI : Enlarge Lead Metrics 2026-07-20 18:00:38 -04:00
firestar5683 6d92a8e5ad no pid 2026-07-20 16:48:50 -05:00
firestarsdog 01df304f88 Big UI: Randomizer Smandomizer 2026-07-20 17:34:17 -04:00
firestarsdog 7a76325e67 Big UI : We can sort models now 2026-07-20 17:19:13 -04:00
firestar5683 c3d1f727c0 yas 2026-07-20 16:02:11 -05:00
firestar5683 94e60c5d70 New Raybig Homescreen 2026-07-20 15:34:21 -05:00
firestar5683 43143e7a1f clarified-moonstone 2026-07-20 15:34:14 -05:00
firestarsdog f2b14c7ac0 Big UI : Model Manager cleanup 2026-07-20 15:25:08 -04:00
firestar5683 d5c0fea948 build 2026-07-20 14:22:32 -05:00
firestar5683 a51b1fd78f Omnioculars V1 2026-07-20 14:07:12 -05:00
firestar5683 8b7c2b5f36 oo buddy boy 2026-07-20 13:18:27 -05:00
firestarsdog 0eab89c8d9 Big UI : A lil Domi proofing 2026-07-20 14:13:17 -04:00
firestar5683 7b124faad2 Anti Burn In 2026-07-20 12:33:41 -05:00
firestar5683 4ac7fcaf5c Refactor 2026-07-20 12:23:38 -05:00
firestar5683 f265aa3f7b Japanese BBQ Sauce 2026-07-20 11:59:49 -05:00
firestar5683 11044975c5 build 2026-07-20 11:26:51 -05:00
firestar5683 27f73a6f08 Kirkland Rotisserie 2026-07-20 11:26:07 -05:00
firestarsdog 3e5bb853cb Big UI: Fix Source Bubble 2026-07-20 10:25:15 -04:00
whoisdomi 2f0864e215 Low Speed Turn Assist update
Slightly higher turn in speeds when possible.

This follows model desires, so if the model doesn't request it or is weak not much can be done.
2026-07-20 07:12:15 -05:00
firestarsdog 8376ba7c97 Big UI : Widget Layout Manager : RIP? 2026-07-19 17:57:33 -04:00
firestar5683 c928e27033 Favorites 2026-07-19 15:45:04 -05:00
firestar5683 5f52120d7a personality 2026-07-19 15:27:16 -05:00
firestar5683 cab8457f47 build 2026-07-19 13:59:44 -05:00
firestar5683 8453f6b4eb 2 2026-07-19 13:59:20 -05:00
firestar5683 03cf613e4c mi mi zu zu pri pri 2026-07-19 13:42:37 -05:00
firestarsdog ce44830b22 Big UI: No flicker 2026-07-19 00:49:23 -04:00
firestar5683 3ae3c5361e Burnt Wasabi 2026-07-18 23:10:00 -05:00
firestarsdog d3dd2545a9 Scale up dm preview in raylib 2026-07-18 23:02:55 -04:00
firestar5683 29cb892e1a Toyota 2026-07-18 19:17:25 -05:00
firestar5683 a106e222ca ez mode 2026-07-18 13:53:48 -05:00
firestar5683 6ccc984dab build 2026-07-18 12:15:43 -05:00
firestar5683 cce803e888 happy saturday 2026-07-18 12:15:09 -05:00
whoisdomi 9427041200 More lane change butter please 2026-07-18 07:07:28 -05:00
whoisdomi 6bae55ac8e Low Speed Turn Assist
When using the blinker coming up to a turn and the car near standstill or stops the model goes blind, but before it does comma will now remember what it was trying to do and continue going that direction. Manually moving the wheel or cancelling turn signal will undo this. Turns will initiate at a lower speed.
2026-07-18 07:07:27 -05:00
firestar5683 d8b9bf5529 build 2026-07-17 22:49:46 -05:00
firestar5683 4c07ea96e7 fixes 2026-07-17 22:49:09 -05:00
firestarsdog fcf1bf2f3c Big UI : Dedicated to Dora and all the Explorers 2026-07-17 22:58:03 -04:00
firestar5683 e3c377df34 ev9 angle 2026-07-17 14:02:38 -05:00
firestar5683 28141e3074 jeep 2026-07-17 13:54:42 -05:00
firestar5683 25c5722372 lat smooth 2026-07-17 13:34:20 -05:00
firestar5683 d699f26ded leedle 2026-07-17 11:59:47 -05:00
firestar5683 9ccd61e8cf Mizuzu 2026-07-17 00:17:41 -05:00
firestar5683 fccd46fef5 build 2026-07-16 23:54:08 -05:00
firestar5683 1863259a58 The Night's Watch 2026-07-16 23:51:45 -05:00
firestarsdog c001d2b184 Big UI: Alerts 2026-07-16 23:11:02 -04:00
firestarsdog 03ebfd2c69 Big UI: Sounds/Alerts Fixes 2026-07-16 23:03:26 -04:00
firestarsdog 94141aebb1 Big UI: Screen brightness 2026-07-16 22:52:39 -04:00
firestarsdog 71ee4ab2a3 Big UI: Clean 2026-07-16 20:08:31 -04:00
firestarsdog dfb5acddf5 Big UI: Cleanup 2026-07-16 19:45:32 -04:00
firestarsdog 33d7e977b4 Big UI : Cleanup 2026-07-16 18:57:57 -04:00
firestar5683 c6708e716f Curves 2026-07-16 14:33:52 -05:00
firestar5683 5a7ec6b154 sleepProb 2026-07-16 12:33:27 -05:00
firestar5683 d935514f78 favs 2026-07-16 11:39:24 -05:00
firestar5683 8f3f9cf6c7 yas 2026-07-16 10:33:59 -05:00
firestarsdog 4013a70e9d Ex Tee Four Cee Cee 2026-07-16 10:29:47 -04:00
firestar5683 3e363cf7a3 build 2026-07-15 23:02:20 -05:00
firestar5683 9f13e71a0a carnivallll 2026-07-15 23:02:20 -05:00
firestar5683 28ea8d0c09 dsu bypass 2026-07-15 22:24:04 -05:00
firestar5683 d0c877f591 update 2026-07-15 22:07:25 -05:00
firestar5683 b5ebc6474e Free Galaxy 2026-07-15 21:35:13 -05:00
firestar5683 cb151bb9aa build 2026-07-15 20:53:21 -05:00
firestar5683 e943d2afd2 Stop It. 2026-07-15 20:43:45 -05:00
firestar5683 8556708cd6 plan stan 2026-07-15 19:32:36 -05:00
firestarsdog 6fa509cc88 Big UI: Nuke 2026-07-15 19:02:57 -04:00
firestar5683 8e7ce87be8 owalawattabotta 2026-07-15 15:57:21 -05:00
firestar5683 5d8137b30a O canada 2026-07-15 14:02:15 -05:00
firestar5683 368cb1a6f6 distilled-moonstone v4 2026-07-15 13:48:19 -05:00
firestar5683 ba460bbb7b patch 2026-07-15 11:32:02 -05:00
firestar5683 a6ffaaa781 build 2026-07-15 11:25:27 -05:00
firestar5683 d4cfd34291 food & stuff 2026-07-15 11:20:09 -05:00
firestar5683 b0334c2ae5 nissan 2026-07-15 08:08:08 -05:00
firestarsdog 6a19e82bb2 Big UI : Biggify 2026-07-15 03:48:07 -04:00
firestarsdog 5693de7d8d Big UI: No balls 2026-07-15 03:28:19 -04:00
firestarsdog 20fa52f5df Big UI: Pagination cleanup 2026-07-15 03:20:44 -04:00
firestarsdog cb540160e4 Big UI: Fix pagination indicator overlap 2026-07-15 01:59:28 -04:00
firestarsdog be1fda1504 Big UI: stats to bottom border 2026-07-15 01:39:16 -04:00
firestarsdog 0c3bd608d9 Big UI: Skinny pill 2026-07-15 01:16:44 -04:00
firestarsdog 258b4c6048 Big UI: Widget show/hide cleanup 2026-07-15 00:55:54 -04:00
firestarsdog 8b23fd8c03 Big UI: Border definition 2026-07-15 00:32:26 -04:00
firestar5683 eb7d4212fd cleanups / BUMP 2026-07-14 22:03:41 -05:00
firestar5683 73485ba76c galaxy 2026-07-14 21:13:47 -05:00
firestarsdog 1ea2143e01 Big UI: Country Roads 2026-07-14 21:35:25 -04:00
firestarsdog 20235f027d Big UI: Distance Button text 2026-07-14 19:57:46 -04:00
firestarsdog 55ad1fd0fd BigUI: Purple Rain 2026-07-14 19:43:43 -04:00
firestar5683 5a2117892c toyboy button 2026-07-14 18:27:08 -05:00
firestar5683 d8e4d75656 build 2026-07-14 18:03:52 -05:00
firestar5683 77db3e506c aol 2026-07-14 17:57:12 -05:00
firestar5683 acd15fcba7 c4 2026-07-14 17:30:59 -05:00
firestar5683 00539e1dc2 writeup 2026-07-14 17:12:55 -05:00
firestar5683 fb98b8cb29 Speed Limit Writeup 2026-07-14 17:01:33 -05:00
firestarsdog fc88f70ebd Big UI: Quick Vehicle Panel Cleanup WIP 2026-07-14 17:47:31 -04:00
firestar5683 6233e7b2c0 camera view 2026-07-14 16:33:42 -05:00
firestar5683 0144a691b9 distilled-moonstone v3 2026-07-14 12:23:32 -05:00
firestar5683 37a6c62e6e Reapply "The Final Kachow" 2026-07-14 11:55:45 -05:00
firestar5683 ca09e50081 Revert "The Final Kachow"
This reverts commit 8098b9fa53.
2026-07-14 11:25:31 -05:00
firestar5683 8098b9fa53 The Final Kachow 2026-07-14 11:16:29 -05:00
firestar5683 5564d133b3 HondaDays 2026-07-14 09:36:22 -05:00
firestarsdog 6e3bf42c97 guess we need these too... cleanup l8er 2026-07-14 03:40:59 -04:00
firestarsdog f94babe509 BigUI WIP: Button Map Cleanup 2026-07-14 02:17:37 -04:00
firestar5683 45eead8dcd nighty night 2026-07-14 01:16:15 -05:00
firestarsdog fcd39be875 BigUI WIP: SLC Bug fixes 2026-07-14 02:08:30 -04:00
firestar5683 a609716520 guess we need these 2026-07-14 00:10:28 -05:00
firestar5683 a0ae06022c cleanup errybody errywhere 2026-07-13 23:59:13 -05:00
firestarsdog c9cf8cfdf6 BigUI WIP: Can we see this? 2026-07-14 00:44:58 -04:00
firestar5683 3d4e1f2d48 raybillywig 2026-07-13 22:39:18 -05:00
firestar5683 ca74743eac Raylib stuff 2026-07-13 22:18:15 -05:00
firestar5683 fb031a3c57 slc raylib fix 2026-07-13 22:12:29 -05:00
firestar5683 4bad6f6f79 yas 2026-07-13 21:58:47 -05:00
whoisdomi 7e1b3769d7 Lane Change Smoothing 2.0
1. Reduced jerk
2. Smoother
3. Improved arrest, reducing chances of overshooting if setting is too low
2026-07-13 15:16:57 -05:00
firestar5683 4a98785aa3 FLM 2026-07-13 14:56:23 -05:00
firestar5683 d305071351 build 2026-07-13 14:01:47 -05:00
firestar5683 653009185e elantra and sped 2026-07-13 14:00:50 -05:00
firestarsdog 57bfc691bf BigUI WIP: Vertical toggletile list? 2026-07-13 13:44:11 -04:00
firestar5683 7e4f8d4154 patch1 2026-07-13 12:41:08 -05:00
firestar5683 361f692d53 lagathy 2026-07-13 10:07:16 -05:00
firestar5683 f81099af79 buttonAOl 2026-07-13 09:55:10 -05:00
firestar5683 1d982da86e distilled-moonstone v2 2026-07-13 09:49:45 -05:00
firestarsdog c306fc7cfd BigUI WIP: 4 Jon: His Eyes Are Saved
Pass 1 of collapsing sidebar, adjustor size increases, onroad bar size increase
2026-07-13 01:44:00 -04:00
firestar5683 b49c21e5aa distilled-moonstone v1 2026-07-13 00:14:02 -05:00
firestar5683 44b2df59da Analytical Techniques 2026-07-13 00:03:37 -05:00
firestar5683 c8c3a814ea build 2026-07-12 23:10:36 -05:00
firestar5683 46c3592563 ftm 2026-07-12 23:09:58 -05:00
firestar5683 6534ce356a build 2026-07-12 21:52:05 -05:00
firestar5683 e4dfbd1a60 Warbler 2026-07-12 21:48:37 -05:00
firestar5683 e9a2c925ed mapd wrap 2026-07-12 20:54:47 -05:00
firestar5683 57292f09bf Robocop 2026-07-12 20:10:01 -05:00
firestar5683 e577502f4b VACATION 2026-07-12 17:53:20 -05:00
firestar5683 7b0c0784ed bump 2026-07-12 01:11:18 -05:00
firestar5683 96dcfa4287 milky time 2026-07-12 01:11:13 -05:00
firestar5683 6046a84e95 rare as trees 2026-07-11 21:38:32 -05:00
firestar5683 1884087590 build 2026-07-11 18:21:07 -05:00
Beartech 637c3c820c gm: route SDGM cam-long friction brake to the correct bus
Send EBCMFrictionBrakeCmd (0x315) where the EBCM receives it: SDGM+SASCM cars
off the SASCM's camera-bus (bus2) leg, bare SDGM on the powertrain bus. Whitelist
0x315 on the camera bus in GM_CAM_LONG_TX_MSGS. Requires a panda rebuild.
2026-07-11 18:20:44 -05:00
firestar5683 4f47f8cb0a twuck2 2026-07-11 16:41:29 -05:00
firestar5683 e38668b3cb Steel Creek 2026-07-11 15:42:44 -05:00
firestar5683 9dbf5db9ec FTMv2 2026-07-11 12:19:35 -05:00
firestar5683 e47a836d2d inference 2026-07-11 11:54:46 -05:00
firestar5683 6c0ee59a3e Dom's Plan 2026-07-11 11:54:34 -05:00
firestar5683 a0f4028aaa sped 2026-07-11 11:36:16 -05:00
firestar5683 beb7e5bf6b build 2026-07-11 10:07:27 -05:00
firestar5683 f88ef7ecc2 FTM 2026-07-11 10:07:27 -05:00
firestar5683 6cc8e9b86a AR0231 2026-07-10 23:21:52 -05:00
firestar5683 a999f28270 build 2026-07-10 22:44:34 -05:00
firestar5683 2a3d2744af Update camerad 2026-07-10 22:22:23 -05:00
firestar5683 804316e40c Eden Falls 2026-07-10 17:41:56 -05:00
firestarsdog bdde8907bf BigUI WIP: Mici Mouseface 2026-07-10 05:04:37 -04:00
firestarsdog 85ab7557e9 BigUI WIP: Pad comma panels 2026-07-10 03:42:38 -04:00
firestarsdog 3d2b959db7 BigUI WIP: Grow up 2026-07-10 03:28:57 -04:00
firestarsdog 889cd3db1a BigUI WIP: Alerts Always on Top 2026-07-10 00:01:39 -04:00
firestarsdog 4916143a5d BigUI WIP: Full screen settings exit + bread margins 2026-07-09 23:50:24 -04:00
firestar5683 1153010f85 Hemmed-In Hollow 2026-07-09 20:13:10 -05:00
firestarsdog 0cbd8013b2 BigUI WIP: Hit me baby one more time 2026-07-09 20:21:55 -04:00
firestarsdog a425a9c11a BIgUI WIP: Fix weird ? trunc on nav card 2026-07-09 19:32:17 -04:00
firestar5683 987de36f54 Float The Buffalo 2026-07-09 17:34:56 -05:00
firestarsdog f2fbd3f97c Bucky the Buick 2026-07-09 09:39:34 -04:00
firestarsdog 30245e7d34 Big Pass 2026-07-09 00:41:32 -04:00
firestarsdog 3aa2801ce7 lead indicator mindblender 2026-07-09 00:18:02 -04:00
firestarsdog bc3c245aa5 BigUI WIP: Kiełbasa Polska 2026-07-08 01:15:02 -04:00
whoisdomi cdb266cba2 Weaving Straights 2026-07-07 07:52:10 -05:00
whoisdomi e4e416bfb3 Notchy Highways 2026-07-07 07:50:46 -05:00
firestarsdog 39414ee2e4 BigUI WIP: Pass B 2026-07-07 04:20:07 -04:00
firestar5683 a08fe79cef fixes 2026-07-06 22:32:54 -05:00
Michael Tawata 33508d42ef 19 buick ascm 26 mph minsteerspeed 2026-07-06 16:06:47 -07:00
firestarsdog 110bd8b295 BigUI WIP: Fix boot screen downloads
BigUI WIP: Fix boot screen downloads
2026-07-06 02:47:58 -04:00
firestarsdog 622720f730 BigUI WIP: Vehicle Panel Pass 2026-07-06 02:04:28 -04:00
firestarsdog 4bdf55f6a0 BigUI WIP: We see? 2026-07-06 00:51:45 -04:00
firestarsdog 9e2448b3d5 BigUI WIP: Shrinky Bread that you can see! 2026-07-06 00:08:40 -04:00
firestar5683 2ccd6e35b7 more smol l8ter 2026-07-05 22:51:46 -05:00
firestar5683 71b5cd8594 twuck 2026-07-05 22:48:58 -05:00
firestarsdog 3bcd062eb7 BigUI WIP: Scaling A 2026-07-05 23:08:38 -04:00
firestarsdog 6a4b508864 BigUI WIP: Chilidog 2026-07-05 22:35:16 -04:00
firestar5683 6e48d7dc12 Panic Nik 2026-07-05 21:19:14 -05:00
firestar5683 d849ac120b something tiny is coming 2026-07-05 19:51:47 -05:00
firestar5683 4243a5b055 SMOOOOLLL 2026-07-05 17:31:32 -05:00
firestar5683 8d9e97fdcd hye 2026-07-05 16:03:37 -05:00
firestar5683 1457b902ac Warn of Agnos 2026-07-05 13:17:18 -05:00
firestar5683 8ab1b723ae The Smallest Yard 2026-07-05 11:33:59 -05:00
firestarsdog 2fb5fbf3ad Raylib Rainbow Road Update (All) 2026-07-05 04:39:52 -04:00
firestarsdog cbe6eb077e BigUI WIP: Fast Update Update...Update 2026-07-05 02:50:57 -04:00
firestarsdog 831a8f27e5 BigUI WIP: Oh lol GM riot prevention 2026-07-05 00:20:55 -04:00
firestar5683 46d19999ce debug 2026-07-04 23:20:12 -05:00
firestar5683 e27badccef Sped 2026-07-04 21:05:32 -05:00
firestarsdog 07cf72d573 BigUI WIP: Cull 2026-07-04 19:24:33 -04:00
firestarsdog 8bda3d5be1 BigUI WIP: This seems nice 2026-07-04 18:42:28 -04:00
firestarsdog cdc2b7a3ed BigUI WIP: Mici the Ticis & Tizis 2026-07-04 18:29:56 -04:00
firestarsdog c7bc46ec8e BigUI WIP: Nav card repel from DM icon 2026-07-04 16:09:57 -04:00
firestarsdog dc1b9fc790 BigUI WIP: Collapse Navigation to right side 2026-07-04 15:54:49 -04:00
firestarsdog 275f8966b2 BigUI WIP: Move nav card to bottom for now 2026-07-04 15:25:15 -04:00
firestar5683 5b1445bb5f SLC 2026-07-04 14:19:45 -05:00
firestarsdog 0b1a94914b BigUI WIP: Simple Download Manager Holdover 2026-07-04 15:08:49 -04:00
firestar5683 3317d545be MOAR 2026-07-04 13:47:48 -05:00
firestar5683 a630533b44 build 2026-07-04 13:46:47 -05:00
firestar5683 cb82059d67 GM 2026-07-04 13:46:21 -05:00
firestar5683 e08745d519 Mango Chutney 2026-07-04 10:40:00 -05:00
firestarsdog 7e76fa9b41 BigUI WIP: + SLC 2026-07-04 08:28:10 -04:00
firestar5683 b72570df40 promotion 2026-07-04 00:53:16 -05:00
firestar5683 95ee3a818b nondefault 2026-07-04 00:14:11 -05:00
firestar5683 72992743a4 that's no moon 2026-07-03 23:50:35 -05:00
firestar5683 8eefbacc48 ./build --params/panda/ui/cereal 2026-07-03 20:53:36 -05:00
firestar5683 4531edad1e build 2026-07-03 20:48:32 -05:00
firestar5683 0af6ca7d37 defaults 2026-07-03 20:43:40 -05:00
firestar5683 ac4ffb4a7e visionpulse 2026-07-03 20:24:09 -05:00
firestarsdog 641f1dc238 BigUI WIP: No place like... StarPilot 2026-07-03 20:55:11 -04:00
firestar5683 650cb03b60 NoDashLeak 2026-07-03 19:39:29 -05:00
firestar5683 cefcc41bca Speed 2026-07-03 19:13:53 -05:00
firestar5683 957fe8af75 pedals in galaxy 2026-07-03 13:43:59 -05:00
firestar5683 d98ae2b94b build 2026-07-03 13:38:57 -05:00
firestar5683 12a984b26d Rats In Alani 2026-07-03 13:34:56 -05:00
firestar5683 9cd81e89f6 Update starpilot_boot_logo.jpg 2026-07-03 12:42:50 -05:00
firestar5683 677545cc23 Reapply "The Power Within"
This reverts commit 2f02c93b3b.
2026-07-03 12:28:00 -05:00
firestar5683 2f02c93b3b Revert "The Power Within"
This reverts commit 7f314d9f28.
2026-07-03 12:24:16 -05:00
firestar5683 7f314d9f28 The Power Within 2026-07-03 12:17:10 -05:00
firestarsdog 6ea41a0329 BigUI WIP: CDM? 2026-07-03 00:57:39 -04:00
firestarsdog c33e8094e8 BigUI WIP: Guess we need more bread... 2026-07-02 23:42:48 -04:00
firestarsdog f0b23a40fe BigUI WIP: Conditional Drive Mode 2026-07-02 23:40:11 -04:00
firestarsdog b65158cd97 BigUI WIP: Bozo's Fight Song 2026-07-02 18:40:41 -04:00
firestar5683 b6794d72d3 sorry ya'll 2026-07-02 17:03:29 -05:00
firestar5683 ea2aa532af I AM SCREAMING 2026-07-02 16:38:13 -05:00
firestar5683 5bbe5f1daf RIP BOZO 2026-07-02 15:50:24 -05:00
firestar5683 1afb6b3978 newnew 2026-07-02 15:27:09 -05:00
firestar5683 9e03465520 blankity blankity blank 2026-07-02 14:42:15 -05:00
firestar5683 06e267cef2 Ultraventure 2026-07-02 14:01:21 -05:00
firestarsdog b79527a217 Fingerprint Catalog more chars 2026-07-02 14:13:52 -04:00
firestarsdog fa85c848f6 BigUI WIP: Moar bread 2026-07-02 13:04:38 -04:00
firestarsdog 0e08829188 BigUI WIP: Visual seperation 2026-07-02 12:57:55 -04:00
firestar5683 1363a5b044 fixes 2026-07-02 11:30:44 -05:00
firestar5683 60406cb982 Memory Hither 2026-07-02 10:44:59 -05:00
firestarsdog 152c39044f BigUI WIP: Didn't like these 2026-07-02 11:32:45 -04:00
firestar5683 6c392185be oopsie 2026-07-02 10:10:45 -05:00
firestarsdog c7a5c880cc BigUI WIP: Try this 2026-07-02 11:07:26 -04:00
firestarsdog 0510e87530 BigUI WIP: Standardize Hubtiles 2026-07-02 03:50:52 -04:00
firestarsdog c9734c9b1a BigUI WIP: Vehicle 2026-07-02 03:37:01 -04:00
firestar5683 66e04d4a45 KA THIS CHOW 2026-07-01 22:59:38 -05:00
firestar5683 c1577d2536 build 2026-07-01 15:04:50 -05:00
firestar5683 23b354d47e Auracast 2026-07-01 15:02:27 -05:00
firestarsdog 5c9888a0d7 BigUI WIP: I can see clearly now (MSAA 4× on PC fix) 2026-07-01 15:35:41 -04:00
firestarsdog 74cf048f94 BigUI WIP: Map Panel Cleanup 2026-07-01 15:32:11 -04:00
firestar5683 0eb8d0cfdc kerchew 2026-07-01 13:45:51 -05:00
firestar5683 9ddf5d31b4 kachow 3 2026-07-01 13:41:33 -05:00
firestar5683 7da4359dd0 Kachow 2 2026-07-01 13:27:44 -05:00
firestarsdog 032b2a1fde BigUI WIP: Cleanup 2026-07-01 13:32:46 -04:00
firestar5683 08df283511 kachow 2026-07-01 11:50:57 -05:00
firestar5683 ae3792c683 build 2026-07-01 11:38:22 -05:00
firestar5683 9d2149d495 queue 2026-07-01 11:32:48 -05:00
firestar5683 5234a121f9 Add HKG EV App Start Climate wake
Add a StarPilot vehicle toggle that selects alternate Panda firmware for Hyundai/Kia/Genesis CAN-FD EVs. The firmware keeps the HKG CAN bus active while Panda is in power save and treats the app climate-active frame, bus 1 address 0x384 with byte 3 nonzero, as a Panda boot wake source without publishing it as CAN ignition.

Wire the toggle through StarPilot vehicle settings, Galaxy device settings, parameter definitions, and pandad firmware selection. Disabling the toggle selects the default Panda firmware again.

Tested on a Kia EV9 and 2023 Kia EV6. EV9 remote climate active used 0x384 byte 3 equal to 0x01; EV6 remote climate active used 0x0a. Both stopped/off states observed byte 3 equal to 0x00. Toggle-off negative testing on EV9 saw the remote climate frame on CAN but pandaStates.ignitionCan stayed false. Toggle-on testing verified the active Panda signature matched panda_h7_hkg_remote.bin.signed. Follow-up testing changed the HKG path to wake-only after remote climate caused partial-car fingerprinting and Dashcam Mode; wake-only firmware was built, flashed, and verified on both devices.
2026-07-01 11:32:29 -05:00
firestarsdog 706c65a70d BigUI WIP: Redudant 2026-07-01 12:26:04 -04:00
firestarsdog 04bee88dd2 BigUI WIP: Size bump 2026-07-01 11:38:55 -04:00
firestar5683 072928ec96 tungsten 2026-07-01 10:08:26 -05:00
firestarsdog 03ec0b2c60 BigUI WIP: Too slow 2026-07-01 10:23:11 -04:00
firestar5683 294e301000 widgety gibbit 2026-07-01 08:50:10 -05:00
firestar5683 74e4dd4c44 All Makes 2026-07-01 08:26:02 -05:00
firestarsdog f40881657c BigUI WIP: Meet The Parents 2026-07-01 01:52:11 -04:00
firestarsdog 4bb15dded4 BigUI WIP: fix breadcrumb 2026-07-01 00:27:17 -04:00
firestarsdog 5eb7e8f02b BigUI WIP: Fixed title 2026-07-01 00:10:58 -04:00
firestarsdog ef5ece17eb BigUI WIP: Star Factory 2026-06-30 23:41:23 -04:00
firestar5683 1339ca02c4 build 2026-06-30 22:11:13 -05:00
firestar5683 d5e40d3bdf Oh What A Night! 2026-06-30 22:03:59 -05:00
firestarsdog 97c20744d3 BigUI WIP: K, we'll start simpler 2026-06-30 18:52:31 -04:00
firestar5683 30786472cb i'm 13 and this is 2026-06-30 16:14:18 -05:00
firestar5683 af185f8491 Mariah 2026-06-30 13:14:37 -05:00
firestarsdog 2a5cb66b9a BigUI WIP: Dedup/remove junk 2026-06-30 02:47:18 -04:00
firestarsdog 82eae95add BigUI WIP: Glow Position 2026-06-30 02:17:24 -04:00
firestarsdog 85b33d8819 BigUI WIP: Onroad Bar alignment 2026-06-30 01:03:44 -04:00
firestarsdog e4fc9b6912 BigUI WIP: Meh 2026-06-30 00:22:27 -04:00
firestarsdog a44cde63a5 BigUI WIP: The Bar Borked 2026-06-30 00:19:48 -04:00
Beartech d93039698c Add BUICK_LACROSSE_ASCM_19US variant with 37 mph minSteerSpeed
US 2019 Buick LaCrosse factory LKA operates only 60-180 km/h. Split it
from BUICK_LACROSSE_ASCM into its own variant so minSteerSpeed can be
raised above the EPS LKA-activation threshold (~12.5 m/s), preventing the
"LKAS Fault: Restart the car to engage" on deceleration. Manual
fingerprint selection only; base LaCrosse platforms unchanged.
2026-06-29 22:18:48 -05:00
firestar5683 3a1ca3fb81 ev6 2026-06-29 20:16:31 -05:00
firestar5683 28e51ebfea build 2026-06-29 20:02:59 -05:00
firestar5683 1c2627e1ae Dead Cow Gully 2026-06-29 19:57:24 -05:00
firestarsdog b4dc28a45e BigUP WIP: Ugly lateral 2026-06-29 19:40:36 -04:00
firestar5683 c8a9eb5464 EV9 the final countdown 2026-06-29 12:55:54 -05:00
firestar5683 11be793c3a Revert "ev9"
This reverts commit ce989294ab.
2026-06-29 12:44:56 -05:00
firestar5683 ce989294ab ev9 2026-06-29 12:03:58 -05:00
firestarsdog a21520fa8f BigUI WIP: Breadcrumb Navigation Cleanup 2026-06-29 12:57:53 -04:00
firestarsdog e5751388d4 BigUI WIP: Boop 2026-06-29 12:28:42 -04:00
firestarsdog 535ae098c6 BigUI WIP: One more 2026-06-29 05:53:57 -04:00
firestarsdog 0b26d1c050 BigUI WIP: Start of Lateral design pass 2026-06-29 05:41:23 -04:00
firestarsdog 7d52c80bf4 BigUI WIP: delete this random blue? 2026-06-29 04:10:55 -04:00
firestarsdog 50630f121c BigUI WIP: System Panel Cleanup 2026-06-29 03:53:12 -04:00
firestarsdog f26c89d6cb SLC: No whammy? 2026-06-29 03:10:59 -04:00
firestar5683 e88854319c PlotWranglerPro 2026-06-28 22:49:08 -05:00
firestar5683 2e53b419d1 sonata hybrid 2026-06-28 22:05:55 -05:00
firestar5683 f4bc8ee6b7 ev9 2026-06-28 20:20:47 -05:00
firestar5683 6daefdc0e1 versioning 2026-06-28 20:04:02 -05:00
firestar5683 96e578fa71 pri pri 2 2026-06-28 16:35:14 -05:00
firestar5683 768a2f324c Mici CSC Icon 2026-06-28 16:22:40 -05:00
firestar5683 f50b8dabbb ev9 2026-06-28 15:52:01 -05:00
firestar5683 d9e0345a2b runtime 2026-06-28 15:51:35 -05:00
firestar5683 8a505e6677 ui 2026-06-28 15:31:42 -05:00
firestar5683 40b5468615 More modeld cleanup 2026-06-28 15:03:09 -05:00
firestar5683 f7418649f8 beeg 2026-06-28 13:30:15 -05:00
firestar5683 5d3b0f4ea9 Update model_compiler.py 2026-06-28 13:17:09 -05:00
firestar5683 7e773e5373 Update model_compiler.py 2026-06-28 13:10:30 -05:00
firestar5683 6d088863a6 no pp 2026-06-28 13:05:58 -05:00
firestar5683 6b515db122 build 2026-06-28 12:50:10 -05:00
firestar5683 bdc1532258 App / Version 2026-06-28 12:44:58 -05:00
firestarsdog afe15a9a80 BigUI WIP: Disablement of more vert scroll 2026-06-28 03:54:02 -04:00
firestarsdog 02060a4b67 BigUI WIP: Hide descriptions 2026-06-28 03:46:39 -04:00
firestarsdog efd25eca90 BigUI WIP: Weird squish fix 2026-06-28 03:01:14 -04:00
firestarsdog b4f17f35f9 BigUI WIP: Toggle tile panel standardization PT55 2026-06-28 02:59:08 -04:00
firestar5683 a0669247e3 ANGEL 2026-06-28 00:56:51 -05:00
firestar5683 be811cbe61 ev9 2026-06-28 00:30:14 -05:00
firestar5683 460b61ebe8 Shenanigans 2026-06-28 00:13:13 -05:00
firestar5683 7411a11f83 pytest 2026-06-27 23:58:18 -05:00
firestar5683 a7ad72489b pri pri 2026-06-27 23:45:56 -05:00
firestar5683 e82a4f034b Konik Tooling 2026-06-27 23:38:32 -05:00
firestar5683 a8ec45ec12 --cem 2026-06-27 22:58:38 -05:00
firestar5683 0df2444e95 mici branch switcher 2026-06-27 22:43:12 -05:00
firestarsdog 32cf065988 BigUI WIP: Nix the Caps 2026-06-27 23:36:11 -04:00
firestarsdog 41c680e60c BigUI WIP: Center Breadcrumb Bar text, was triggering 2026-06-27 23:22:54 -04:00
firestar5683 fac7554cb6 I can be ur angle 2026-06-27 22:17:04 -05:00
firestarsdog 92bc8ee934 BigUI WIP: The Starry Night 2026-06-27 23:12:51 -04:00
firestar5683 9c30fc2387 Plexy 2026-06-27 21:55:44 -05:00
firestar5683 3f5dc27170 FERG 2026-06-27 20:47:54 -05:00
firestarsdog a5fb9a2cff BigUI WIP: Prettier Bread 2026-06-27 21:37:10 -04:00
firestarsdog 201d0c0476 BigUI WIP: Standardize Breadcrumbs 2026-06-27 18:31:33 -04:00
firestar5683 54e722ff00 build 2026-06-27 16:02:53 -05:00
firestar5683 fb1c2ea1c4 spicy 2026-06-27 15:57:38 -05:00
firestar5683 0f43f042fb nope 2026-06-27 15:37:25 -05:00
firestar5683 ee1f0bbe83 nah
pan
2026-06-27 15:23:35 -05:00
firestar5683 b811825b38 slither 2026-06-27 14:36:52 -05:00
firestar5683 ee71b70f24 build 2026-06-27 13:58:30 -05:00
firestar5683 b75b21681d Madlad stuff 2026-06-27 13:51:16 -05:00
firestar5683 562c5eb58d long boi 2026-06-27 13:30:18 -05:00
firestar5683 2798c12c90 build 2026-06-27 13:19:46 -05:00
firestar5683 19d545b22e Operation Bigfoot 2026-06-27 13:06:03 -05:00
firestar5683 36e935c9dc nah 2026-06-27 00:18:18 -05:00
firestar5683 cf89678178 driver monitoring 2026-06-26 21:40:10 -05:00
firestar5683 88e4004c9a Stop The Pain 2026-06-26 16:52:28 -05:00
firestar5683 9f0ae1a495 2019 ascm esv 2026-06-26 16:49:02 -05:00
firestar5683 f5a5b9e141 lat control refactor 2026-06-26 16:32:15 -05:00
firestar5683 057ca874ce Dom's Plan 2026-06-26 16:02:47 -05:00
firestar5683 497eb3f771 build 2026-06-26 15:35:10 -05:00
firestar5683 284bb45c0c that's alot 2026-06-26 15:29:52 -05:00
firestar5683 836b0278eb stuff 2026-06-26 12:53:23 -05:00
whoisdomi 4ce9be2752 Bug Fix: Blinker disregards force stop
Prior commit inteneded for blinker to veto force stop from activating during a turn/curves.
If blinker was on, it was vetoing actual force stops. This tweaks is so the veto only works
on actual turns, or if force stop was already on. So force stop will stop, then allow turn without reactivating force stop.
2026-06-26 06:10:13 -05:00
firestarsdog 24fc6fe4e5 BigUI WIP: More Standarization 2026-06-26 04:16:26 -04:00
firestar5683 297ff1973d Don't Brake Check 2026-06-26 02:18:55 -05:00
firestarsdog 727985697f BigUI WIP: Adaptive Nested Panel 2026-06-26 03:14:11 -04:00
firestar5683 59d1581c0a pedal away from the metal 2026-06-26 01:50:06 -05:00
firestarsdog 3a86dffa17 BigUI WIP: Guess this needs a back button 2026-06-26 01:53:15 -04:00
firestarsdog 9f7dcb68f9 BigUI WIP: Add yeast 2026-06-26 01:27:14 -04:00
firestar5683 6793c1a4f5 build 2026-06-25 23:31:56 -05:00
firestar5683 f351dbac09 Lists A Plenty 2026-06-25 23:26:03 -05:00
firestarsdog 44255d67c2 BigUI WIP: Standarize Breadcrumbs 2026-06-25 22:48:37 -04:00
firestarsdog 1ce49be89b BigUI WIP: Standardize single pane toggle tiles 2026-06-25 18:36:17 -04:00
firestar5683 bdf7bca569 Lite Brite 2026-06-25 10:54:58 -05:00
firestar5683 d8e292dc94 build 2026-06-25 00:00:42 -05:00
firestar5683 f0601e27ec The Plum 2026-06-24 23:54:45 -05:00
firestar5683 cec9f090c4 Bolt Pedal Friction Tune 2026-06-24 22:51:42 -05:00
firestar5683 d08da1ff22 volt opd adjust 2026-06-24 22:31:44 -05:00
firestar5683 58b028cfc8 wumbo 2026-06-24 19:37:49 -05:00
firestar5683 d7f3037c88 build 2026-06-24 14:35:53 -05:00
firestar5683 028ee7b3f5 UpstreamStructs 2026-06-24 14:06:16 -05:00
firestar5683 94aff6faed i6 2026-06-24 13:24:28 -05:00
firestar5683 b63039ce84 i6 2026-06-24 12:55:11 -05:00
firestarsdog aec5590d57 BigUI WIP: New Appearance Icon 2026-06-24 03:07:42 -04:00
firestarsdog abd19df5f4 BigUI WIP: Scale up speaker 2026-06-24 02:33:01 -04:00
firestarsdog b1dae43ea8 BigUI WIP: Bell -> Speaker 2026-06-24 02:25:18 -04:00
firestarsdog 8c32f6d99d BigUI WIP: Add some graphics 2026-06-24 02:13:48 -04:00
firestarsdog f6b51e6742 BigUI WIP: More purples 2026-06-24 01:25:34 -04:00
firestarsdog d3881e6a77 BigUI WIP: Sound Panel Polish 2026-06-24 00:47:06 -04:00
firestarsdog d83b065c53 BigUI WIP: Container Store 2026-06-23 23:50:52 -04:00
firestar5683 16c3d5f48a Tom Bombadil 2026-06-23 21:45:36 -05:00
firestar5683 d6dc906ff8 mica 2026-06-23 20:00:29 -05:00
firestar5683 ea0ef444de The Domi Effect 2026-06-23 18:36:47 -05:00
firestar5683 ea1da70b22 lacrosse test 2026-06-23 18:18:14 -05:00
firestar5683 ad9aa72979 slc 2026-06-23 18:16:06 -05:00
firestar5683 1382200cda plexy and noah 2026-06-23 18:00:13 -05:00
firestar5683 7e8832d672 Pacifica mod support 2026-06-23 13:12:32 -05:00
firestar5683 9cd9a6201c build 2026-06-23 12:09:37 -05:00
firestar5683 6ee00d3f60 Support multipart model artifacts 2026-06-23 12:01:45 -05:00
firestar5683 d97100bd14 tiny my BUTT 2026-06-23 12:01:44 -05:00
firestar5683 bb36fe4287 fartlek 2026-06-23 11:28:17 -05:00
firestar5683 066a0f2520 Tibetan Singing Bowl 2026-06-22 23:37:15 -05:00
firestar5683 c5a6e1da9d Blaze It and Praise It 2026-06-22 19:45:11 -05:00
firestar5683 f8cec6f270 Long Blong 2026-06-22 19:35:51 -05:00
firestar5683 544979d652 EV6 GT 2026-06-22 19:27:43 -05:00
firestar5683 353672fb6a Domi's Steer Max Fix 2026-06-22 17:19:21 -05:00
firestar5683 4101ab9b28 Doms Plan 2026-06-22 17:18:48 -05:00
firestar5683 7fb1d854c6 Revert "Dom(i)'s Steer Max"
This reverts commit ad3bad8b85.
2026-06-22 16:55:53 -05:00
firestar5683 d8587bba31 longy long long 2026-06-22 16:55:49 -05:00
firestar5683 ad3bad8b85 Dom(i)'s Steer Max 2026-06-22 16:42:11 -05:00
firestar5683 c91ac533ef is it hi-yun-dae? 2026-06-21 22:19:04 -05:00
firestar5683 32a6af9ac8 Truckothy 2026-06-21 22:10:37 -05:00
firestar5683 e84c0e44ab The Triple Dipper 2026-06-21 21:19:56 -05:00
firestar5683 d28cd4df8b lil rope a dope 2026-06-21 20:48:27 -05:00
firestarsdog cfd762f0a2 BigUI WIP: Bread 2026-06-21 20:47:11 -04:00
firestarsdog 16d6af490a BigUI WIP: Title Standards 2026-06-21 20:39:13 -04:00
firestar5683 0b37a23c75 new stuf 2026-06-21 17:00:32 -05:00
firestarsdog bf8204e9a2 BigUI WIP: Hänsel und Gretel
BigUI WIP: Hänsel und Gretel
2026-06-21 05:57:30 -04:00
firestar5683 34813dee41 cap'n crunch 2026-06-20 23:04:18 -05:00
firestar5683 d84518b97f AYYYEE TOYOTA 2026-06-20 21:26:46 -05:00
firestar5683 2356823b62 build 2026-06-20 20:52:51 -05:00
firestar5683 ce98b31cbf Tyger Tyger Burning Bright 2026-06-20 20:49:05 -05:00
firestar5683 97881b5c66 The fields speak to me 2026-06-20 18:04:39 -05:00
firestarsdog fc90fcb879 BigUI WIP: Gas/Brake Pass 1 2026-06-20 16:47:05 -04:00
firestar5683 762c54bb2f build 2026-06-20 14:41:37 -05:00
firestar5683 9910651a9d Carl The Witch 2026-06-20 14:38:56 -05:00
firestar5683 42a23508b7 RECOVER 2026-06-20 13:08:23 -05:00
firestar5683 fbb6eb651c twuck 2026-06-20 12:33:29 -05:00
firestar5683 e4809535dc build 2026-06-20 01:26:51 -05:00
firestar5683 63490fe5e6 one pedal update 2026-06-20 01:26:51 -05:00
firestar5683 a7b7148c25 2019 hold 2026-06-20 00:05:25 -05:00
firestar5683 e50874baca dash 2026-06-20 00:00:35 -05:00
firestar5683 ef4f174c8d AHHHH 2026-06-19 23:44:41 -05:00
firestar5683 9c726d99de Revert "THE SMOKING GUN"
This reverts commit 25a50a2ec3.
2026-06-19 23:38:09 -05:00
firestar5683 25a50a2ec3 THE SMOKING GUN 2026-06-19 23:31:38 -05:00
firestar5683 5d3d5a884b a;oiwht 2026-06-19 23:05:28 -05:00
firestar5683 7a3c1ede9a The tone is in the tune 2026-06-19 22:39:05 -05:00
firestar5683 d931d3007b build 2026-06-19 21:13:24 -05:00
firestar5683 05c2a90e16 lacrosse 2026-06-19 21:10:41 -05:00
firestar5683 dc581f6300 Revert "Now Mary's In"
This reverts commit 0bc009f800.
2026-06-19 21:01:51 -05:00
firestar5683 a6c5b43caf Revert "maybe"
This reverts commit d8b715799c.
2026-06-19 21:01:18 -05:00
firestar5683 3ec82de5fc Revert "again"
This reverts commit cd08c87a80.
2026-06-19 21:01:18 -05:00
firestar5683 cd08c87a80 again 2026-06-19 17:33:49 -05:00
firestar5683 d8b715799c maybe 2026-06-19 17:20:32 -05:00
firestar5683 0bc009f800 Now Mary's In 2026-06-19 16:53:59 -05:00
firestarsdog ff49f332b0 BigUI WIP: Shes glowing 2026-06-19 17:25:30 -04:00
firestarsdog f04b561f88 BigUI WIP: Russian Nesting Tiles 2026-06-19 17:16:36 -04:00
firestar5683 1f237019e7 Byte You In The 2026-06-19 14:16:01 -05:00
firestar5683 b47c18426d Steam Your Water 2026-06-19 14:14:07 -05:00
firestar5683 0e5d40fb1b Angler Wish 2026-06-19 13:48:30 -05:00
firestarsdog 496d36f805 BigUI WIP: Font_scale fix 2026-06-19 11:12:39 -04:00
firestar5683 9217bf289c build 2026-06-19 00:44:56 -05:00
firestar5683 2c2d8b86ab Drain The Swamp 2026-06-19 00:39:48 -05:00
firestar5683 c8128d2cde Annie Are You Okay 2026-06-18 23:48:23 -05:00
firestar5683 9c85ebc365 The Triple Dipper 2026-06-18 16:55:42 -05:00
firestar5683 8c510f964c Offroad 2026-06-18 14:04:36 -05:00
firestar5683 35e623c392 Dang Imperials 2026-06-18 13:51:58 -05:00
firestar5683 5eb6fe2dd9 Kachow 2026-06-18 13:36:40 -05:00
firestar5683 64bb95e3cf Applebees 2026-06-18 12:20:17 -05:00
firestar5683 96818d8efc The Time Turner 2026-06-18 10:58:09 -05:00
firestar5683 c23434b947 Is This A Date? 2026-06-18 10:54:25 -05:00
firestar5683 2a0053c046 build 2026-06-18 10:27:12 -05:00
firestar5683 f1a256dac0 Don't Kill Suave 2026-06-18 10:19:06 -05:00
firestar5683 967fb96167 build 2026-06-18 10:09:53 -05:00
firestar5683 bb4f3b74d9 There's Pou in this Tine 2026-06-18 10:07:26 -05:00
firestar5683 7dab3a0ceb build 2026-06-17 23:32:03 -05:00
firestar5683 e6b12d612a Agent Cody Banks 2026-06-17 23:29:00 -05:00
firestarsdog d17a4bd6cb BigUI WIP: Appear 2026-06-17 22:05:45 -04:00
firestar5683 540becea52 Mica's cable shipped 2026-06-17 11:49:14 -05:00
firestar5683 a71be7c47b long plan 2026-06-17 11:24:45 -05:00
firestar5683 7305822e67 leedle leedle leedle lee 2026-06-17 11:16:00 -05:00
firestar5683 6b0e5aed24 I did the backstroke in college 2026-06-16 21:19:57 -05:00
firestar5683 6f907e2060 final plan 2026-06-16 18:58:49 -05:00
firestar5683 29b777f12c fremulon 2026-06-16 18:40:22 -05:00
firestar5683 335d6934fb plimothy 2026-06-16 18:31:36 -05:00
firestar5683 60305edeae niro phev 2026-06-16 10:34:30 -05:00
firestarsdog da305d9da3 BigUI WIP: Lil scrolling cleanup 2026-06-16 03:42:22 -04:00
firestarsdog 624f51aef4 BigUI WIP: Pagination out of bounds dragging fix 2026-06-16 03:10:39 -04:00
firestarsdog ba76832979 BigUI WIP: Pagination/Page Turning UX 2026-06-16 02:54:55 -04:00
firestarsdog 49126f29ae BigUI WIP: Apperance -> Aethergrid start 2026-06-16 02:47:30 -04:00
firestar5683 2ed92c88ae build 2026-06-16 00:00:25 -05:00
firestar5683 a9771a0e85 Supernova 2026-06-15 23:58:00 -05:00
firestar5683 1dcac8cfef Tiny Dancer 2 2026-06-15 22:25:18 -05:00
firestarsdog 18ea1dd170 BigUI WIP : AetherMultiSelect Tile + Dialog 2026-06-15 22:28:44 -04:00
firestarsdog 59336096e7 BigUI WIP: Out with the old 2026-06-15 21:27:06 -04:00
firestarsdog 57d7796edb BigUI WIP: Panel standardization 2026-06-15 21:15:52 -04:00
firestar5683 2dc441d621 build 2026-06-15 16:35:06 -05:00
firestar5683 93ec2a94e6 NudgeMe 2026-06-15 16:32:44 -05:00
firestar5683 56564d55c8 REEEEEE 2026-06-15 16:27:29 -05:00
firestar5683 322364c1ca plan stan 2026-06-15 14:47:21 -05:00
firestar5683 838c7fdc9b fixes 2026-06-15 11:30:41 -05:00
firestar5683 e02d67c153 gaslight2 2026-06-15 01:14:20 -05:00
firestar5683 407e2ea90a refreshing 2026-06-15 01:03:31 -05:00
firestar5683 712256eac4 build 2026-06-15 00:47:13 -05:00
firestar5683 1c2aedcc9a gaslight 2026-06-15 00:45:06 -05:00
firestar5683 9af2969540 My Eyes Are Up Here 2026-06-15 00:40:07 -05:00
firestar5683 8a7946b26c pond 2026-06-15 00:17:25 -05:00
firestar5683 53e0aded4c build 2026-06-15 00:06:07 -05:00
firestar5683 3ecd8be1f1 Raindrops on Roses & Whiskers on Kittens 2026-06-15 00:03:44 -05:00
firestar5683 0262b934c4 dumb 2026-06-14 21:18:13 -05:00
firestar5683 9aeaf593c3 son day I'll get this 2026-06-14 21:02:31 -05:00
firestar5683 00c64ba805 Zikeji Tales 2026-06-14 19:26:56 -05:00
firestar5683 7d939e1c76 planner work 2026-06-14 17:10:32 -05:00
firestar5683 8a4d2b558b radar vs voacc 2026-06-14 17:06:52 -05:00
Jason Jackrel 0508653a29 Volt tune from Thinkpad
Squash merge PR #63.
2026-06-14 16:42:36 -05:00
firestar5683 2e75486d16 planner work 2026-06-14 16:38:10 -05:00
firestar5683 7bd73401cd oopsie 2026-06-13 21:48:35 -05:00
firestar5683 4a107868cf build 2026-06-13 20:50:04 -05:00
firestar5683 53766ff6b7 The Forked Man 2026-06-13 20:47:15 -05:00
firestar5683 4ee6758b9f XCeeding expectations 2026-06-13 20:46:30 -05:00
firestar5683 4c1317e30d Mom's Spaghetti 2026-06-13 20:45:52 -05:00
firestar5683 8a68dec71f Swell Tune 2026-06-13 20:43:51 -05:00
firestar5683 c7efa7fa20 Two is not better than one 2026-06-13 20:42:50 -05:00
firestarsdog bd7394ea33 BigUI WIP: Tile updates 2026-06-13 11:56:21 -04:00
firestar5683 fa7fa6afaf Remove Slow Logic atm 2026-06-12 23:09:31 -05:00
firestar5683 491ec0c0b8 the slow mo guys 2026-06-12 10:50:14 -05:00
firestar5683 87f1334ce9 yes 2026-06-12 10:22:03 -05:00
firestar5683 140b047e7f better raylib 2026-06-12 01:34:58 -05:00
firestar5683 21b1bfd600 THIS DESERVES A BUMP 2026-06-11 23:04:34 -05:00
firestar5683 5da99bc977 build 2026-06-11 22:32:31 -05:00
firestar5683 a30dc40b8a wumbology 2026-06-11 22:30:21 -05:00
firestar5683 96893d9c36 Dingle's got dragonclaw?! 2026-06-11 19:36:18 -05:00
firestarsdog 9be0defc29 The speed of cyan 2026-06-11 18:07:30 -04:00
firestar5683 afc8c6fb4b Mr. Freeze 2026-06-11 11:34:12 -05:00
firestar5683 b559b0f827 Fridge Cigarette 2026-06-11 10:51:05 -05:00
firestar5683 79e31ff241 TRY AGAIN, SPIDERMAN 2026-06-10 22:30:48 -05:00
firestar5683 1e604fd80e loopback 2026-06-10 19:11:02 -05:00
firestar5683 56989a164e update 2026-06-10 19:01:20 -05:00
firestar5683 eaf5d44037 forte he 2026-06-10 15:54:35 -05:00
firestarsdog 93cb562321 BigUI WIP: Larger for the Dads 2026-06-10 15:49:25 -04:00
firestar5683 31d3df673a Kia Xceed 2026-06-10 11:55:20 -05:00
firestar5683 c0aa7a7460 oops 2026-06-10 10:54:28 -05:00
firestar5683 498b7f14a9 build 2026-06-10 10:50:40 -05:00
firestar5683 95b6ecec86 Hello Poppet 2026-06-10 10:48:32 -05:00
firestarsdog 8e6fc9bed3 BigUI WIP: Page flipping is tough... 2026-06-10 02:20:14 -04:00
firestarsdog cf7822180b BigUI WIP: Aethergrid Update 2026-06-10 00:07:00 -04:00
firestar5683 f93c536f7e deeprl3 2026-06-09 22:58:07 -05:00
firestarsdog d555d1f588 BigUP WIP: Style 2026-06-09 23:50:01 -04:00
firestar5683 88e297b183 offsets 2026-06-09 22:21:48 -05:00
firestar5683 37f5c8ca58 Navigation: Breaking Dawn 2026-06-09 21:19:08 -05:00
firestarsdog 7d53bd5af7 BigUI WIP: LED 2026-06-09 21:30:52 -04:00
firestar5683 455a8ec11d XT4 Sigmoid 2026-06-09 17:02:27 -05:00
firestar5683 dac0610a19 build 2026-06-09 16:47:33 -05:00
firestar5683 da5b3f829f black pink in your area2 2026-06-09 16:47:28 -05:00
firestarsdog 02960fc8c2 SLC allow override to persist if within obtained speed 2026-06-09 17:26:25 -04:00
firestar5683 4585938753 build 2026-06-09 15:42:23 -05:00
firestar5683 f777e71c56 Black / Pink in your area 2026-06-09 15:39:56 -05:00
firestar5683 0a698d202b build 2026-06-09 14:13:36 -05:00
firestar5683 63db39082b Mount Wannahockaloogie 2026-06-09 14:11:13 -05:00
firestarsdog 4f48c2ec27 BigUI WIP: Lateral Spateral 2026-06-09 13:13:55 -04:00
firestarsdog 6faf9bd88a BigUI WIP: Weird scrolling 2026-06-09 01:52:23 -04:00
firestarsdog a624cf89bb BigUI WIP: Remove pagenation from system settings 2026-06-09 01:41:27 -04:00
firestarsdog e836ed09c8 BigUI WIP: Optional Pagenation 2026-06-09 01:37:08 -04:00
firestarsdog 8cc9c59330 BigUI WIP: Some panel standarization 2026-06-09 00:00:33 -04:00
firestar5683 a11d064aeb buttan 2026-06-08 22:38:57 -05:00
firestar5683 77c82edb44 sonata hybrid 2026-06-08 20:55:23 -05:00
firestar5683 9a9ac3af77 navstate 2026-06-08 20:30:44 -05:00
firestar5683 ac8511b211 bsm 2026-06-08 20:10:33 -05:00
firestar5683 c3ff2e86db build 2026-06-08 19:57:20 -05:00
firestar5683 98d6a4eac0 chill takeoff 2026-06-08 19:57:20 -05:00
firestar5683 5f413b967e odyss 2026-06-08 19:57:20 -05:00
firestar5683 bdb0da4fa0 suburu sng 2026-06-08 19:57:20 -05:00
firestarsdog cabacda0ad BigUI WIP: mono 2026-06-08 20:48:20 -04:00
firestar5683 d8c79a9712 build 2026-06-08 19:19:19 -05:00
firestar5683 88c259a666 Prioritize Smooth Follow 2026-06-08 19:15:50 -05:00
firestarsdog 796d081fce BigUI WIP: More prints of the finger stuff 2026-06-08 19:16:53 -04:00
firestar5683 6d61feff11 rlonlylat 2026-06-07 21:59:32 -05:00
firestar5683 5d0ab0cfb0 First time in San Juan mi hijo 2026-06-07 21:51:36 -05:00
firestar5683 6c687a9f5c build 2026-06-07 21:16:08 -05:00
firestar5683 7a17c21fab Truck V2 2026-06-07 21:13:52 -05:00
firestar5683 1994a0bd16 build 2026-06-07 20:53:37 -05:00
firestar5683 8a1bfb925c odyss 2026-06-07 20:51:27 -05:00
firestar5683 914411fe06 build 2026-06-07 20:43:19 -05:00
firestar5683 c88bebbc3e Zik is my boss 2026-06-07 20:37:47 -05:00
firestar5683 aba65bf755 build 2026-06-07 20:18:52 -05:00
firestar5683 cf1c99cf78 Haberdashery 2026-06-07 20:16:35 -05:00
firestar5683 9c51a6024e build 2026-06-07 15:21:10 -05:00
firestar5683 bec246c6ef Clear Nav 2026-06-07 15:18:56 -05:00
firestar5683 eeab4b8c85 Build 2026-06-07 15:04:23 -05:00
firestar5683 a6758eb9e6 New stoofs 2026-06-07 15:01:59 -05:00
firestar5683 cdcc8da555 sm 2026-06-07 14:26:14 -05:00
firestar5683 1f9aa83440 buttons 2026-06-07 14:26:14 -05:00
firestar5683 15d218677e build 2026-06-07 14:26:14 -05:00
firestar5683 f8934840da Conditional Chill 2026-06-07 14:26:14 -05:00
firestarsdog a888c5602a BigUI WIP: Prob don't need 2026-06-07 05:04:30 -04:00
firestar5683 4134da76ca volt probz 2026-06-06 20:49:28 -05:00
firestar5683 24b0f37ae7 hda1 2026-06-06 19:31:04 -05:00
firestar5683 559a738fe7 build 2026-06-06 17:52:05 -05:00
firestar5683 f20b1f2a4f mochi mochi mochi 2026-06-06 17:49:41 -05:00
firestar5683 c76b770807 plan takeoff 2026-06-06 14:47:33 -05:00
firestarsdog 3c0dea5747 Raylib UI : Global fingerprint_catalog 2026-06-06 14:53:43 -04:00
firestar5683 e47fbd1cb9 build 2026-06-06 12:08:50 -05:00
firestar5683 efdc48980d defaults 2026-06-06 12:03:35 -05:00
firestarsdog f84f7d4f17 Replay Controls 2026-06-05 23:29:34 -04:00
firestar5683 aa82ae0bd0 build 2026-06-05 22:10:00 -05:00
Michael Tawata 743ff67927 no fun allowed here 2026-06-05 22:06:48 -05:00
firestarsdog 2880189713 BigUI WIP: Pushpop Wires 2026-06-05 18:31:50 -04:00
firestarsdog 2847d0fd8a BigUI WIP: oplong push_widget 2026-06-05 18:20:19 -04:00
firestarsdog c23aeb9fcd BigUI WIP: Remove puke 2026-06-05 15:02:52 -04:00
firestarsdog 980c85cfb1 BigUI WIP: Vehicle Panel state update 2026-06-05 14:58:28 -04:00
firestar5683 826775bb1f Project Hateno 2026-06-05 11:13:24 -05:00
firestarsdog e01d61feb9 BigUI WIP: Good chunk of vehicle settings 2026-06-05 03:17:23 -04:00
firestar5683 fee42e4d7b so that was a lie 2026-06-05 02:00:55 -05:00
firestar5683 038b83ac4a this outta be good 2026-06-04 23:52:55 -05:00
firestar5683 4c27f3cd5e Zikeji's Dilemma 2026-06-04 23:32:57 -05:00
firestar5683 2aaad84ab6 livin off energy drinks and Marlboro Reds 2026-06-04 23:32:16 -05:00
firestar5683 a1d338f35c Been workin all day just to keep my family fed 2026-06-04 23:09:43 -05:00
firestar5683 50bd4f121e Requiem For Rancid Remmy Rental Roadster 2026-06-04 15:16:33 -05:00
firestar5683 3d3f6ea888 build 2026-06-04 13:49:02 -05:00
firestar5683 e5cc74603a defaults 2026-06-04 13:46:40 -05:00
firestar5683 7da3d84053 build 2026-06-04 13:43:16 -05:00
firestar5683 47c2cc9990 stuff and things 2026-06-04 13:40:53 -05:00
whoisdomi 85e3e11c10 Radar for Leads Button 2026-06-04 13:40:53 -05:00
firestarsdog 840e4814d0 No-uh 2026-06-04 14:25:38 -04:00
firestar5683 42bcb717a4 ninininini 2026-06-03 23:31:27 -05:00
firestarsdog b515b285db slc diag script : dirty update to make runnable anywhere 2026-06-04 00:21:58 -04:00
firestar5683 7fb15f97ab v16 2026-06-03 22:14:00 -05:00
firestar5683 b202886c33 tiny dancer 2026-06-03 16:57:44 -05:00
firestar5683 e3e4542ef2 My Collar's Blue & My Neck's Red 2026-06-03 16:04:14 -05:00
firestar5683 3027988a4d Purple Monkey Balls 2026-06-03 15:03:40 -05:00
firestar5683 119fcb15a1 leady speedy 2026-06-03 13:39:40 -05:00
firestar5683 1b4e609b33 loopdy loop 2026-06-03 12:48:57 -05:00
firestar5683 c80365de78 mid day stuffs 2026-06-03 11:01:28 -05:00
firestar5683 3e591f311c i6 2026-06-03 07:50:13 -05:00
Michael Tawata 3118ff5c52 remove fp references and fix readme tagline 2026-06-02 23:55:39 -07:00
firestar5683 d0598334e4 Microslop 2026-06-02 21:47:09 -05:00
firestar5683 2f13d3846c i6 2026-06-02 21:44:56 -05:00
firestar5683 7558054914 build 2026-06-02 20:30:02 -05:00
firestar5683 71260b52d1 angle cleanup 2026-06-02 20:27:34 -05:00
firestarsdog f55046f6e9 BigUI WIP: Aethergauge 2026-06-02 19:16:34 -04:00
firestarsdog 3cf48ae3c8 BigUI WIP: Some CEM Stuff 2026-06-02 17:49:10 -04:00
firestar5683 e44e612465 build 2026-06-02 14:26:19 -05:00
whoisdomi 78e9b5139c Faster Leads for $300 Trebek, and say hi to your motha
Faster takeoffs after leads and green lights.
2026-06-02 14:12:21 -05:00
whoisdomi d2a8163f32 Human Lane Change ui fix
Toggled on, would show adjecent radar leads, even if that toggle was off.
Now gated to its toggle in developer ui.
2026-06-02 14:12:20 -05:00
firestar5683 9f30661f6d long planner / i5 / sonata 2026-06-02 11:18:34 -05:00
firestar5683 5632559e5a fcw 2026-06-02 10:31:16 -05:00
firestar5683 ae2f502767 g90 long 2026-06-02 00:29:10 -05:00
firestarsdog 669143a178 BUICK_LACROSSE_ASCM 2026-06-02 00:07:16 -04:00
firestar5683 54cb76ddfd build 2026-06-01 20:52:31 -05:00
whoisdomi fabf122627 Wheel controls qt fix 2026-06-01 20:50:11 -05:00
whoisdomi 3486c695b8 QT StarPilot Logo 2026-06-01 20:50:11 -05:00
whoisdomi 6eb513501d Fire Firehose 2026-06-01 20:50:11 -05:00
whoisdomi 45060a07b7 Add CC Main and LKAS buttons to Wheel Controls
Clean up so all buttons are handled from wheel controls
2026-06-01 20:50:11 -05:00
firestarsdog 7f5e78fd8f BigUI WIP: Delete Stuff 2026-06-01 02:51:51 -04:00
firestarsdog b178e67ae5 BigUI WIP: Scale up dialogs 2026-06-01 02:31:32 -04:00
firestarsdog 026c83fb1b BigUI WIP: Align System Settings, again... 2026-06-01 02:13:23 -04:00
firestarsdog c7b3251918 BigUI WIP: System Settings Bump 2026-06-01 01:46:36 -04:00
firestarsdog 14f94151a5 BigUP WIP: System Settings Pass 2026-06-01 01:19:50 -04:00
firestar5683 6dc473713c i5 2026-06-01 00:10:14 -05:00
firestarsdog 594f525c0c BigUI WIP: System Settings Cleanup Pass 2026-06-01 00:39:18 -04:00
firestar5683 2132a5ceb0 build 2026-05-31 21:06:39 -05:00
firestar5683 5d86b7ac5b IsRHD 2026-05-31 21:03:42 -05:00
firestarsdog 0e7123d632 BigUI WIP: Huh need this afterall 2026-05-31 16:56:39 -04:00
firestarsdog b96c9290f7 BigUI WIP: Settings Cleanup 2026-05-31 16:48:12 -04:00
firestarsdog 416b5e3cd2 BigUI WIP: System Settings update 2026-05-31 15:57:01 -04:00
firestar5683 8a3a872a93 build 2026-05-31 13:45:41 -05:00
firestar5683 6f5690618f param 2026-05-31 13:42:11 -05:00
firestarsdog fad4434104 Expose Python UI Screen Timeout Variables 2026-05-31 14:40:08 -04:00
firestarsdog 86359bacab BigUI WIP: Sounds Default=Auto 2026-05-31 14:00:03 -04:00
firestarsdog a7d8d7a544 BigUP WIP: Sound Polish 2026-05-31 13:53:06 -04:00
firestar5683 86d059bdb4 long 2026-05-31 12:37:09 -05:00
firestar5683 caa5f41b1e radars 2026-05-31 12:26:54 -05:00
firestar5683 fcda700625 nav fixes 2026-05-31 12:14:04 -05:00
firestarsdog cdca40f018 BigUI WIP: Sound Panel Alignment 2026-05-31 04:27:57 -04:00
firestarsdog 736c344cdd BigUI WIP: Sheep > Goat 2026-05-31 02:27:54 -04:00
firestarsdog a28250c81b BigUI WIP: Icons and removal of magic math 2026-05-31 02:14:32 -04:00
firestar5683 b406a1a9d8 nightly roundup 2026-05-31 00:55:43 -05:00
firestarsdog a44e306343 Hm.. XT5? lol 2026-05-30 23:00:45 -04:00
firestarsdog ecbed0f4f8 BigUI WIP: Remove dock lol 2026-05-30 21:31:43 -04:00
firestar5683 04273eefad above 2026-05-30 14:41:03 -05:00
firestar5683 bd5436c55f nav / planner / sonata buttons 2026-05-30 14:26:09 -05:00
firestarsdog 6ca397b840 BigUI WIP: Optimizations 2026-05-30 03:24:04 -04:00
firestarsdog cc2b53a6e9 BigUI WIP: Drop starpilot_icon 2026-05-29 18:10:59 -04:00
firestar5683 6c4717cc39 g90test 2026-05-29 16:07:34 -05:00
firestar5683 6afdc99dd5 redneck 2026-05-29 15:57:20 -05:00
firestarsdog 07fcbbdab8 BigUI WIP: Poof 2026-05-29 16:38:59 -04:00
firestar5683 d55d1bff69 fort hey 2026-05-29 14:42:42 -05:00
firestarsdog a80d3680d0 BigUI WIP: Remove icon code 2026-05-29 15:36:11 -04:00
firestar5683 9673c72d44 bleehhhhh 2026-05-29 14:29:49 -05:00
firestar5683 7051b79674 nav 2026-05-29 14:15:46 -05:00
elkoled e7fa0f51a6 comment
(cherry picked from commit 81fceadb7817b831e47e679a07f515b02950e6e8)
2026-05-29 13:56:21 -05:00
elkoled e9dc540f64 adjust fan setpoint
(cherry picked from commit 269d2189b2383fa5b7c0d5e7cab4fb527f29a636)
2026-05-29 13:56:18 -05:00
firestar5683 e26a91147d build 2026-05-29 13:50:51 -05:00
firestar5683 3de95a341a bokoblin loves mutton; I fix the button 2026-05-29 13:48:07 -05:00
firestar5683 dff6f898a8 done goofed 2026-05-29 12:07:46 -05:00
firestar5683 dfd614c31f build 2026-05-29 12:00:14 -05:00
whoisdomi 5020d33748 ui+selfdrived: pin UI after init, move selfdrived to core 5
Move the UI core-affinity pin to after MainWindow init so startup and
restart recovery can use all cores (pinning before init starved the
restarting UI on the contended little cores, stretching recovery from
~30s to minutes). Move selfdrived off the saturated core 4 onto core 5
so its 100 Hz loop is no longer starved, eliminating selfdrivedLagging.

Verified over a full drive: selfdrivedLagging=0, core4/core5 sustained
>=95% only 0.3%/1.2% of the time, UI restart recovery ~15s with the
device staying engaged, radar tracking unaffected.
2026-05-29 11:56:33 -05:00
firestarsdog bd687f353f BigUI WIP: Sine Bonis P1 2026-05-29 03:40:04 -04:00
firestar5683 ce19d2c5f0 Bat bat come under my hat 2026-05-29 01:18:27 -05:00
firestar5683 29ade037d3 Offer applies with enrollment and triple advantage 2026-05-29 00:55:19 -05:00
firestarsdog 75b1deaf60 BigUI WIP: Try dock 2026-05-28 21:48:23 -04:00
firestar5683 a9930207ba v16 2026-05-28 17:38:14 -05:00
firestar5683 742c104964 on 2026-05-28 15:42:42 -05:00
firestarsdog 4183698fc6 BigUI: Widget Scale 2026-05-28 16:05:59 -04:00
firestar5683 f06c82b2b8 ev6 2026-05-28 14:19:03 -05:00
firestarsdog b23b4384f1 BigUI WIP: Aethergauge offset location 2026-05-28 15:11:44 -04:00
firestar5683 93bad13469 patches 2026-05-28 13:31:59 -05:00
firestar5683 31e0a5b8cc volt bsm 2026-05-28 13:29:45 -05:00
firestar5683 732830b095 g90 radar 2026-05-28 13:18:20 -05:00
firestarsdog 43d42594ef BigUI WIP: Aethergauge Helpers 2026-05-28 13:58:40 -04:00
firestar5683 e61039bb67 DM ruh roh 2026-05-28 12:27:45 -05:00
firestar5683 8e8225b6ae Nav Long 2026-05-28 11:41:05 -05:00
firestar5683 01bd291b78 you used to drive me onto sidewalks 2026-05-28 10:41:46 -05:00
firestar5683 61e28a0ac9 build 2026-05-28 10:23:35 -05:00
firestar5683 c744f66b2a Optimus Prime 2026-05-28 10:21:01 -05:00
firestarsdog 9b177b25b5 Revert "test cycle"
This reverts commit b9d89a3e85.
2026-05-28 11:05:47 -04:00
firestarsdog b9d89a3e85 test cycle 2026-05-28 11:04:09 -04:00
firestar5683 903fd2264e build 2026-05-28 00:37:45 -05:00
firestar5683 0f8142a15c default on 2026-05-28 00:35:16 -05:00
firestar5683 b95b5b1d53 build 2026-05-28 00:12:16 -05:00
firestar5683 3d0c3a8a45 Powers You Never Knew You Had and What To Do With Them Now You've Wised Up 2026-05-28 00:09:41 -05:00
firestar5683 9af23999d1 navgal 2026-05-28 00:09:34 -05:00
firestar5683 74a9bb5a4e build 2026-05-28 00:09:34 -05:00
firestar5683 cf506e59b0 nav 2026-05-28 00:09:20 -05:00
firestar5683 68d7fd09e2 Legion 2026-05-27 23:26:52 -05:00
firestarsdog b70680aa86 Silverado CC 2026-05-27 23:47:46 -04:00
Dom 823ff696ab Merge pull request #59 from Thinkpad4by3/Dom
Dom
2026-05-27 21:55:13 -05:00
firestar5683 9b530d520c XT5 2026-05-27 21:37:23 -05:00
firestar5683 3d35284a49 build 2026-05-27 19:53:14 -05:00
Jason Jackrel f425d86457 update tire stiffness 2026-05-27 16:48:27 -07:00
Jason Jackrel 98a9373346 finally the volt tune 2026-05-27 16:47:18 -07:00
firestar5683 35a7e43045 blocky block 2026-05-27 17:40:56 -05:00
firestar5683 b535c0845e ioniq 5 radar 2026-05-27 17:40:56 -05:00
whoisdomi 0ed821d32d 25hz 2026-05-27 17:35:19 -05:00
whoisdomi 2317057411 50hz poll 2026-05-27 17:35:19 -05:00
whoisdomi dc3b39a198 are we there? 2026-05-27 17:35:19 -05:00
whoisdomi ce5611f24c is this radar data? 2026-05-27 17:35:19 -05:00
firestar5683 f819386399 happy wife happy life 2026-05-26 22:20:19 -05:00
firestar5683 e1812ec3d7 build 2026-05-26 21:59:47 -05:00
firestar5683 e9935624f7 smoosh smoosh 2026-05-26 21:59:46 -05:00
firestar5683 0fec51a5d9 volt 2026-05-26 18:58:11 -05:00
firestar5683 3fa2d370bf i6 2026-05-26 18:19:51 -05:00
firestar5683 0750072ef0 build 2026-05-26 16:05:46 -05:00
firestar5683 fb93198a92 logg 2026-05-26 16:02:58 -05:00
firestar5683 a4789c9f61 i6 2026-05-26 15:53:05 -05:00
firestar5683 7386073c71 build 2026-05-26 11:36:09 -05:00
firestar5683 7d8be7079c I h8 u nudgeless 2026-05-26 11:33:49 -05:00
firestar5683 148929d2f1 i5 2026-05-26 11:09:12 -05:00
firestar5683 13e4f301b9 oopsie 2026-05-26 10:42:59 -05:00
firestarsdog dc91ac13b1 BigUI WIP: Clip lanes 2026-05-26 02:15:52 -04:00
firestar5683 a129d591e7 hkg radar 2026-05-26 00:17:24 -05:00
firestar5683 8aa0cf327a build 2026-05-26 00:00:25 -05:00
firestar5683 b78e44303d CCNC 2026-05-25 23:57:56 -05:00
firestarsdog feba46db30 BigUI WIP: Onroad Path Cleanup 2026-05-26 00:56:31 -04:00
firestarsdog a8d501fcd9 BigUI WIP: Scissor Borders 2026-05-26 00:40:47 -04:00
firestarsdog fb17126f68 BigUI WIP: Consolidated Border Effects 2026-05-26 00:32:31 -04:00
firestar5683 693b1f08a3 color calib 2026-05-25 02:12:44 -05:00
firestar5683 6e81630e49 build 2026-05-25 01:42:33 -05:00
firestar5683 76dbf9412a cameradisableFullDisable 2026-05-25 01:40:01 -05:00
firestar5683 68123093c3 stop UI log 2026-05-25 00:48:26 -05:00
firestar5683 73cbee1b85 tune 2026-05-25 00:48:20 -05:00
firestar5683 0cb613b6ce volt aeb 2026-05-25 00:48:13 -05:00
firestarsdog 7834d15127 BigUI WIP: Curves again 2026-05-25 01:02:08 -04:00
firestarsdog 71ce49a301 BigUI WIP: Useless banner 2026-05-24 23:17:21 -04:00
firestarsdog fd7f75578d BigUI WIP: Remove white border on sign + less steppy movement 2026-05-24 03:59:11 -04:00
firestarsdog 4c8452de78 BigUI WIP: Update Curves Again 2026-05-24 01:48:08 -04:00
firestarsdog 7bebf0ef3c BigUI WIP: Force Stop -> Aethergauge 2026-05-24 01:01:31 -04:00
firestarsdog 56a0c4e0d9 BigUI WIP: Center Bar 2026-05-23 13:24:40 -04:00
firestarsdog 666b9d35d6 BigUI WIP: Curvey 2026-05-23 12:49:27 -04:00
firestarsdog 2ef8f8ebef BigUI WIP: Aethergauge Curvey 2026-05-23 05:41:52 -04:00
firestarsdog b88c886592 BigUI WIP: Aethergauge 2026-05-23 02:19:23 -04:00
firestarsdog e742482175 BigUI WIP: Wow, simpler glow 2026-05-23 01:06:58 -04:00
firestarsdog 8c63451137 BigUI WIP: Glow up
BigUI WIP: Glow up
2026-05-22 23:21:28 -04:00
firestar5683 a30a59331d toyota 2026-05-22 01:30:56 -05:00
firestar5683 95d074eb92 slow lead depart 2026-05-21 23:15:48 -05:00
firestar5683 103c44bfd8 Tůne 2026-05-21 22:35:02 -05:00
firestar5683 bfcd43452e deep 2026-05-21 14:41:38 -05:00
firestar5683 0c5cf54d57 elantra 2026-05-21 13:23:20 -05:00
firestarsdog 3f4f2a1813 BigUI WIP: Onroad Cleaner-er 2026-05-21 13:47:56 -04:00
firestar5683 a94c3b72d3 honda 2026-05-21 11:03:10 -05:00
firestar5683 c848b5f1b4 toyota 2026-05-21 10:03:12 -05:00
firestar5683 55f110351e elantra hybrid 2026-05-21 10:00:09 -05:00
firestar5683 58e7f84627 i6 2026-05-21 09:56:27 -05:00
firestarsdog db769226b8 BigUI WIP: The Trail We Blaze 2026-05-21 04:37:41 -04:00
firestar5683 bfcab984e2 toyota 2026-05-20 23:35:50 -05:00
firestar5683 b33a8dea15 Elantra Hybrid 2026-05-20 22:19:05 -05:00
firestar5683 5e00550c6a avalon surge 2026-05-20 22:00:25 -05:00
firestar5683 329b41a84b op16 2026-05-20 21:58:17 -05:00
firestar5683 5e74861311 genesis 2026-05-20 21:04:59 -05:00
firestar5683 70229486bb toyota 2026-05-20 20:56:39 -05:00
firestar5683 813507267c i6 brake adjust 2026-05-20 16:49:52 -05:00
firestar5683 f55402e033 OP16Deep 2026-05-20 15:22:08 -05:00
firestar5683 f3cf4d6969 build 2026-05-20 11:03:16 -05:00
firestar5683 da88d20b1e Toyota 2026-05-20 11:00:08 -05:00
firestar5683 b17bba7e93 Ioniq 6 2026-05-20 10:59:38 -05:00
firestar5683 c99a999f1a Add lateral resume delay settings surfaces and tests 2026-05-20 10:56:59 -05:00
prabhaavp c5c5253de5 Lateral Resume Delay Feature W/O Testing 2026-05-20 10:49:51 -05:00
firestar5683 1f8652d809 Fix wide camera disable runtime gating 2026-05-20 10:44:10 -05:00
prabhaavp 8846b907d7 Disable Widecam Feature
Disable Widecam Feature

Disable Widecam Feature

Disable Widecam Feature

Disable Widecam Feature
2026-05-20 10:39:06 -05:00
firestar5683 3d6c55962b genesis 2026-05-19 21:26:54 -05:00
firestarsdog 0b0f18399c We represent the Lollipop Guild 2026-05-19 19:23:34 -04:00
firestar5683 5856e77f3b i6 turn in 2026-05-19 16:54:16 -05:00
firestar5683 c80d9ffb99 non hda ioniq 2026-05-19 16:43:55 -05:00
firestar5683 1f84395539 toyota pedal 2026-05-19 12:42:41 -05:00
firestarsdog f3a7620188 StarPilot Tools Auth Cleanup 2026-05-19 10:57:20 -04:00
firestar5683 180b0c6768 g90 revert 2026-05-19 09:10:57 -05:00
firestarsdog 55a93013c7 BigUI WIP: Delete tuning gate 2026-05-19 03:21:58 -04:00
firestarsdog 982e742322 BigUI WIP: Always show developer, hide firehose 2026-05-19 03:19:19 -04:00
firestarsdog 3676191fc8 BigUI WIP: The Grinch 2026-05-19 03:11:43 -04:00
firestarsdog 5b19d38d88 BigUI WIP: Bah Hambug 2026-05-19 02:58:09 -04:00
firestarsdog 32c088ac00 BigUI WIP: Refinement/More Extraction 2026-05-19 01:16:53 -04:00
firestar5683 123adc7edc redneck and g90 attempt lkas 2026-05-18 20:21:22 -05:00
firestarsdog dbecce602c Follow The Yellow Brick Road 2026-05-18 19:16:31 -04:00
firestar5683 2b10dc21b0 2021 2026-05-18 15:22:35 -05:00
firestar5683 51701ecffc build 2026-05-18 13:05:07 -05:00
firestar5683 601b8855f6 redneck Hyundai 2026-05-18 12:58:14 -05:00
firestar5683 f56bfb7d4b build and kia forte 2026-05-18 11:49:28 -05:00
whoisdomi 3f8d368b87 Pending Speed Limit Cleanup
Fixed the speed limit display so it no longer flashes an empty speeds, and now flashes over the current speed for a cleaner look.
2026-05-18 11:19:06 -05:00
whoisdomi 70ccc64831 SLC abbreviated icons
Gives the options to display SLC sources as abbreviated and the option to only show sources with data in them to give a cleaner UI look.
2026-05-18 11:19:06 -05:00
whoisdomi 2f5aef1fb8 Remove Taco Tune Hacks
No longer needed toggle. Values.py do the same now
2026-05-18 11:19:06 -05:00
firestar5683 3581a9ecf0 final piece 2026-05-18 11:10:24 -05:00
firestarsdog ed06aa8920 Yellow Brick Road, Emerald City, Oz 2026-05-18 03:35:51 -04:00
firestar5683 5bb401772a Other edge case 2026-05-16 21:53:04 -05:00
firestar5683 5c30a69e10 final stop 2026-05-16 09:50:21 -05:00
firestar5683 be585f72a3 gen2 bolt 2026-05-15 21:39:32 -05:00
StarPilot Build Bot 309665f63e build 2026-05-16 00:20:57 +00:00
firestar5683 9d8a055a04 build change 2026-05-15 18:40:41 -05:00
firestar5683 45a1d3fa8e volt and old ioniq and new ioniq and honda 2026-05-15 18:34:50 -05:00
firestar5683 473e3efae9 túne 2026-05-15 12:42:50 -05:00
StarPilot Build Bot e2607ea6e8 build 2026-05-15 17:20:46 +00:00
firestarsdog 75dcc0772e Club Penguin 2.0 2026-05-15 12:19:08 -04:00
firestar5683 38ad334e12 Create compile_bluescreens.yaml 2026-05-15 10:22:30 -05:00
firestar5683 5fcc1bc196 delete old actions 2026-05-15 10:00:41 -05:00
firestar5683 5bd1977c89 A440 2026-05-15 01:14:06 -05:00
firestarsdog 3eb5db5b31 Speed Limit Controller : Deletion. Bye Bye. 2026-05-14 22:19:19 -04:00
StarPilot Build Bot aa84176c7d build 2026-05-14 23:54:40 +00:00
firestar5683 f30e540690 buildy build 2026-05-14 18:18:44 -05:00
firestar5683 1729d3cda3 i6 2026-05-14 10:08:41 -05:00
firestar5683 c7c10822fb woahhhhh buddy 2026-05-13 23:24:39 -05:00
firestar5683 6b39e4103e Sonata hybrid 2026-05-13 22:57:57 -05:00
firestar5683 5a90937c52 fixy 2026-05-13 20:48:29 -05:00
firestarsdog 69e7ed3eae SLC Wrong Speed Rejection 2026-05-13 20:40:14 -04:00
firestar5683 01bcb40c50 Longfixes 2026-05-13 13:51:25 -05:00
firestar5683 3ecb73dc8a i6 highway 2026-05-13 11:29:40 -05:00
firestar5683 06c00b0895 long bugs 2026-05-13 10:51:19 -05:00
firestar5683 3f8b47aa91 planner hesitations 2026-05-12 22:17:21 -05:00
firestar5683 dc82e51ef6 peter 2026-05-12 22:17:13 -05:00
firestar5683 2516d13bc5 sonata 2026-05-12 21:59:24 -05:00
firestar5683 2ffb286569 Build 2026-05-12 21:47:15 -05:00
firestar5683 af84c8802b HonDeez 2026-05-12 21:47:14 -05:00
firestar5683 d7e43b7ecc otter 2026-05-12 21:32:20 -05:00
firestar5683 471a33d64d build 2026-05-12 16:21:58 -05:00
firestar5683 334481c78d make banner optional 2026-05-12 16:19:10 -05:00
firestar5683 c2bb8f9c56 tune 2026-05-11 22:51:16 -05:00
firestarsdog c650edd193 speed limit filler test? 2026-05-11 22:56:08 -04:00
firestar5683 3e03917edc test 2026-05-11 21:50:07 -05:00
firestar5683 4d0f65a6d1 F 2026-05-11 21:17:43 -05:00
firestar5683 02717ebe73 build 2026-05-11 19:11:53 -05:00
firestar5683 a67c8f98b7 RIP iPedal 2026-05-11 19:09:47 -05:00
firestar5683 21589861fd huge if work 2026-05-11 17:50:09 -05:00
firestar5683 0ce8161cbf i6 2026-05-11 17:04:43 -05:00
firestar5683 013ecbed97 i6 2026-05-11 15:34:33 -05:00
firestarsdog 4370e9c7a3 BigUI WIP: + newer options 2026-05-11 02:43:06 -04:00
firestarsdog a5dedeb164 BigUI WIP: Accents 2026-05-11 02:17:28 -04:00
Fufs 7b557144b3 Fix catastrophic mistake 2026-05-11 00:55:17 -05:00
firestar5683 4747d26cf6 palisade and gen2 bolt 2026-05-11 00:53:27 -05:00
firestar5683 3c3969b09d exp c4 ui 2026-05-11 00:36:41 -05:00
firestar5683 8bd080b3e0 fcw 2026-05-11 00:36:08 -05:00
firestarsdog 5a044781fc BigUI WIP: Accents 2026-05-11 01:33:31 -04:00
firestarsdog 98480a3018 BigUI WIP: Chips 2026-05-11 01:16:18 -04:00
firestarsdog 5c412cea96 BigUI WIP: Standardize Sliders 2026-05-11 01:09:15 -04:00
firestar5683 ee3d33526b honda 2026-05-10 21:25:30 -05:00
firestar5683 25633be976 log grabber 2026-05-10 20:17:17 -05:00
Fufs cd20d94c7c Add legal stuff after adding mdi icons 2026-05-10 17:16:04 -05:00
Fufs 90fbb74f93 C4 UI Vehicle Panel 2026-05-10 17:16:04 -05:00
firestar5683 867159198a túnē 2026-05-10 16:53:33 -05:00
firestar5683 6c4ae9749d build 2026-05-10 13:02:33 -05:00
firestar5683 4254090cf4 button 2026-05-10 13:00:25 -05:00
firestar5683 006319deff build 2026-05-10 11:36:21 -05:00
firestar5683 9872c5fb4b button 2026-05-10 11:25:58 -05:00
firestar5683 2bc5247dc0 i6 wiggle 2026-05-10 10:48:58 -05:00
firestar5683 2ca5f36590 build 2026-05-10 01:18:49 -05:00
firestar5683 c1e3525929 I cannot stop planning long 2026-05-10 01:18:49 -05:00
firestar5683 ef44741760 build 2026-05-09 21:37:54 -05:00
firestar5683 eebfd509d7 LongyLongNeck 2026-05-09 19:28:03 -05:00
firestar5683 61ca62df5f konik 2026-05-09 19:24:05 -05:00
firestar5683 ba18142718 i6 2026-05-09 16:12:44 -05:00
firestar5683 1714c516ab all the small things 2026-05-09 08:54:04 -05:00
firestar5683 1b2b13881c Lead 2026-05-08 11:37:20 -05:00
firestar5683 7dc26d1a68 angle 2026-05-08 11:01:30 -05:00
firestar5683 fbba97f9a6 build 2026-05-08 10:41:15 -05:00
firestar5683 e969a96c17 Update params_keys.h 2026-05-08 10:35:43 -05:00
firestar5683 930ef6e646 honda 2026-05-08 10:10:16 -05:00
firestar5683 b0bba1917f pedal surge 2026-05-08 01:11:41 -05:00
firestar5683 1fbd6ecdfa pedal long brake bias 2026-05-07 23:59:22 -05:00
firestar5683 888a674675 i5 2026-05-07 23:51:33 -05:00
firestar5683 510e2c2225 build 2026-05-07 23:13:33 -05:00
firestar5683 ffd8f6404b teslurrrr 2026-05-07 23:11:06 -05:00
firestar5683 e0259e191c HERCULES 2026-05-07 21:33:21 -05:00
firestar5683 245a5eaaeb who put the glad in gladiator 2026-05-07 21:30:52 -05:00
firestarsdog 1fb31b2e12 BigUI WIP: Cleanup/uniformity 2026-05-07 19:57:18 -04:00
firestar5683 ea64cc4de3 tune 2026-05-07 17:10:31 -05:00
firestar5683 b038b102d8 teslurr 2026-05-07 17:07:25 -05:00
firestar5683 5e0a1bbec3 cacao nibs 2026-05-07 15:27:39 -05:00
firestar5683 5f3d71798d The Well-Tempered Clavier 2026-05-07 14:07:24 -05:00
firestar5683 c1804b1fd8 kia 2026-05-07 11:03:37 -05:00
firestar5683 86ce0b03ee i6 2026-05-07 10:48:44 -05:00
firestar5683 e5ac0c511d tunes 2026-05-06 22:47:07 -05:00
firestar5683 8c0e8375f4 build 2026-05-06 22:17:17 -05:00
whoisdomi 357d7e545f Force Stop Icon replaces banner 2026-05-06 22:14:10 -05:00
whoisdomi d2bd12e9a1 Honda and Mazda Dashboard signals
Mazda CX-5 2017-21
Mazda CX-5 2022-25
Mazda CX-9 2016-20
Mazda CX-9 2021-23
Mazda 3 2017-18
Mazda 6 2017-20

The Mazda caveat worth noting: unlike Honda (where HAS_CAMERA_MESSAGES was already confirmed per-car), Mazda has no such gate — all six models will attempt to read CAM_TRAFFIC_SIGNS since it's registered with freq=0

Honda: limited to HONDA_CAMERA_MESSAGE_CARS, all radarless Bosch:
Honda Accord 2018-22 (+ Accord Hybrid 2018-22, Inspire 2018)
Honda Civic 2019-21 (+ Civic Hatchback 2017-21)
Honda Civic 2022-24 (+ Civic Hatchback 2022-24, Civic Hybrid 2025-26, Civic Hatchback Hybrid 2023/2025-26)
Honda CR-V 2017-22
Honda CR-V Hybrid 2017-22
Honda HR-V 2023-25
Honda Insight 2019-22

Not included (not in HONDA_CAMERA_MESSAGE_CARS): Accord 2023-25, CR-V 2023-26, Odyssey, Pilot, Passport, Acura RDX 3G, Acura TLX — those are either CANFD or use a different DBC and haven't been confirmed to publish CAMERA_MESSAGES
2026-05-06 22:14:10 -05:00
whoisdomi 300ad3d49c Hide the bodies
User can now hide:
DM Icon
Lane Change Banner
Turning Banner
Distance Profile Banner
2026-05-06 22:14:09 -05:00
whoisdomi be9ab0a7e6 Force Stop bugfix: gap behind leads 2 2026-05-06 22:14:09 -05:00
whoisdomi c71a9aed6e Force Stop bugfix: gap behind leads
Force Stop (cem_path) was missing a tracking_lead guard, causing it to activate behind stopped leads at red lights and stop signs — stopping the car far short of the lead instead of letting ACC handle following distance. Added and not self.starpilot_planner.tracking_lead to cem_path, matching the guard already present on dash_path.
2026-05-06 22:14:09 -05:00
whoisdomi ecf6161f9c Efficiency batch 3: UI
F1 — Toggle cache (starpilot_annotated_camera.h + .cc): Added 25 typed cached members; all 32 starpilot_toggles.value() calls in paint code replaced with the cached versions. All reads happen once at the top of updateState() per frame. The only surviving raw call is in mousePressEvent (intentional — touch is rare, not paint-path).

F2 — HUD gradient hoist (selfdrive/ui/qt/onroad/hud.cc): Header gradient is now a static const built once via lambda, no allocation per frame.

Build, flash, and verify that toggling compass, simple_mode, radar_tracks etc. from settings still take effect live without a restart.
2026-05-06 22:14:09 -05:00
whoisdomi 78d5f71fed Efficiency batch 2
D2 — update() in starpilot_onroad.cc now only fires when at least one overlay (showBlindspot, showSignal, showSteering, showFPS) is active. ~30–60 wasted repaints/sec eliminated when all overlays are off.

E4 — Holiday theme check reordered so current_holiday_theme != "stock" (cheapest) is first. Default is stock, so the rest of the chain never evaluates on a normal non-holiday drive.

E7 — paintSteeringTorqueBorder no longer rebuilds the QLinearGradient and computes lighter(120)/setAlpha/5 setColorAt calls every frame. The gradient is now built once in resizeEvent and reused. The per-frame work is now just the two geometry calculations and fillRect.

E5/E6/E8 — Audited clean: all remaining params_memory.put calls are event-driven (button presses, random events), no hot-path logging exists in the UI code, and all QTimers are event-driven or single-shot offroad dialogs.
2026-05-06 22:14:09 -05:00
whoisdomi c1d3e4540b Efficiency batch 1
Wave A (pure refactors):

A2: nnff toggle moved to front of NNFF check — kills ~100 IPC reads/sec when NNFF disabled
A4: 3 filters now use update_alpha() instead of being recreated — ~60 allocs/sec eliminated
Wave B (write reduction):

B1: CEStatus only writes on state transitions (+ E3 folded in: extracted ce_write_value local at both sites). Reset path added in the manual-override branch. ~19 writes/sec saved during cruise
B2: GPS position only persists when compass is enabled AND bearing shifts >0.5° (+ E1 folded in: json.dumps inside the gate). ~95% of writes eliminated on highway
Wave C (polling throttles):

C1: Onscreen distance button reads at 10 Hz instead of 100 Hz — ~90 IPC reads/sec eliminated. Wheel button unaffected
C2: SpeedLimitAccepted IPC read throttled to 5 Hz via existing _slc_adopt_counter. Wheel accel still instant
C3: Lane width numpy calls at 5 Hz instead of 20 Hz — ~300 allocs/sec eliminated. Counter resets when speed drops below threshold so values are fresh on re-entry
2026-05-06 22:14:09 -05:00
firestar5683 2e7036ab07 cem 2026-05-06 16:18:18 -05:00
firestar5683 cfff7d7cb7 honda 2026-05-06 15:02:41 -05:00
firestar5683 1f68e0deaf plan stan man ban 2026-05-06 14:06:47 -05:00
firestar5683 c79e2b3ad7 i6 2026-05-06 13:54:16 -05:00
firestar5683 49aad9cce3 tůne 2026-05-06 10:38:47 -05:00
firestar5683 8ec27d25c5 up 2026-05-05 21:03:40 -05:00
firestar5683 cd9115b0b2 tesla 2026-05-05 20:50:28 -05:00
firestar5683 7918dab915 build 2026-05-05 20:41:25 -05:00
firestar5683 0913a22dfe poodle 2026-05-05 20:41:24 -05:00
firestar5683 e36a9c6c61 ye 2026-05-05 19:53:18 -05:00
firestar5683 a98bf277c8 oops 2026-05-05 17:57:48 -05:00
firestar5683 c5b12e0a16 dbc 2026-05-05 17:24:55 -05:00
firestar5683 e421eb271e neeneeneeneeneenee 2026-05-05 16:20:53 -05:00
whoisdomi 9b97124f80 Finally, a girl is no one 2026-05-05 15:39:44 -05:00
firestar5683 1a39c51617 build 2026-05-05 12:45:15 -05:00
firestar5683 2f74f93308 peedle 2026-05-05 12:41:05 -05:00
firestar5683 4747792c37 p 2026-05-05 11:59:29 -05:00
firestar5683 5e0447df1e ipedal 2026-05-05 11:11:10 -05:00
firestar5683 d9676ca194 models 2026-05-05 10:48:08 -05:00
firestar5683 026a2eb528 op11 2026-05-05 10:39:52 -05:00
firestar5683 e49cfe44b9 honda/ipedal 2026-05-05 10:29:18 -05:00
firestar5683 2e113835a7 build 2026-05-04 23:17:54 -05:00
firestar5683 5f51e6704d ipedal2 2026-05-04 23:15:38 -05:00
firestar5683 806a210467 build 2026-05-04 20:32:12 -05:00
firestar5683 1ddbc24a14 always I-pedal 2026-05-04 20:30:03 -05:00
firestar5683 aed0b7fdb9 f 2026-05-04 19:30:51 -05:00
firestar5683 7837a3c1aa Tesla 2026-05-04 19:12:20 -05:00
firestar5683 7e4818916b Freshly Caught 2026-05-04 17:48:07 -05:00
firestar5683 32185c0c2e honda 2026-05-04 15:40:38 -05:00
firestar5683 90b05a1d18 i6 2026-05-04 15:29:54 -05:00
whoisdomi 37882e86d5 Don't buy the dip
A slight acceleration dip was felt/seen as PID integrator takes over. Now it will be seeded with a_target, for a smoother transiiton and less dip.
2026-05-04 14:52:10 -05:00
firestar5683 1fd3f2cb9d i6 2026-05-04 13:36:11 -05:00
firestar5683 3f3a63a14b i6 2026-05-04 12:49:37 -05:00
firestar5683 4abda00404 i6 2026-05-04 12:15:57 -05:00
firestar5683 b2ded79155 Revert "STOCK LONG I6 wobble fix?"
This reverts commit 7ea096686d.
2026-05-04 12:05:30 -05:00
whoisdomi 7ea096686d STOCK LONG I6 wobble fix? 2026-05-04 11:44:04 -05:00
firestar5683 847333d536 i6 2026-05-04 11:19:28 -05:00
firestar5683 f132bd7b82 i6 2026-05-04 11:19:24 -05:00
firestar5683 d7ec15bddb planner 2026-05-04 11:19:23 -05:00
firestar5683 41fef69a57 honda 2026-05-04 11:19:23 -05:00
firestar5683 14cde4a64c You could be drivin a honda 2026-05-04 11:19:23 -05:00
firestar5683 abd2721a15 This car b steery 2026-05-04 11:19:23 -05:00
firestar5683 3deb8fbb84 Update the_pond.py 2026-05-04 11:19:23 -05:00
firestar5683 c49b4ec228 hurdy gurdy 2026-05-04 11:19:23 -05:00
firestarsdog 8125fd789a BigUI WIP: Size Queen II 2026-05-04 11:19:22 -05:00
firestar5683 6764db8b3b ain't no test shoooo 2026-05-04 11:19:22 -05:00
firestar5683 24af3405f2 big if true 2026-05-04 11:19:22 -05:00
firestarsdog 6626202ff1 BigUI WIP: Size Queen 2026-05-04 11:19:22 -05:00
firestar5683 261b139bcc honda 2026-05-04 11:19:22 -05:00
firestar5683 da5a028057 honda 2026-05-04 11:19:22 -05:00
firestar5683 b9ab07d7cd leedle 2026-05-04 11:19:22 -05:00
firestar5683 a9d57b521e honda 2026-05-04 11:19:21 -05:00
firestar5683 7f03e2880c yeet 2026-05-04 11:19:21 -05:00
firestar5683 6923c35e7d Update latcontrol_pid.py 2026-05-04 11:19:21 -05:00
firestar5683 48ea42c026 honda 2026-05-04 11:19:21 -05:00
firestar5683 5bc24ff148 Honda Long Tune 2026-05-04 11:19:21 -05:00
firestar5683 8ddf2b4757 longplan 2026-05-04 11:19:21 -05:00
firestar5683 863273edbc build 2026-05-04 11:19:20 -05:00
firestar5683 b8a84d6196 honda 2026-05-04 11:19:20 -05:00
whoisdomi 997c1be7b6 Could this be the last accel chain?
Issue: limit_accel_in_turns breakpoint table started at 20 m/s, causing np.interp to clamp a_total_max to 1.7 m/s² for all speeds below 20 m/s (~45 mph), overriding acceleration profiles during the entire low-speed pull.
Fix: Extended _A_TOTAL_MAX_BP down to 0 m/s with a 3.5 m/s² ceiling, matching the maximum ACCEL_MAX.
Turn protection still works correctly since a_y grows with v² and naturally consumes the budget in actual turns.
2026-05-04 10:28:29 -05:00
whoisdomi 471981f732 Hyundai Unchained 2: Let my people go
PID limits clampping max accel from 3.5 to 2.0m/s2
Sport+ should now work.
2026-05-03 09:08:23 -05:00
firestarsdog 989b69ee92 BigUI WIP: Apperance + Cleanup 2026-05-03 02:50:46 -04:00
firestar5683 650b79941f palisade 2026-05-03 00:19:28 -05:00
firestar5683 f7d79c613e honda 2026-05-03 00:15:15 -05:00
firestarsdog 37c82cc2d4 BigUI WIP: Start of lateral 2026-05-03 00:14:43 -04:00
firestar5683 1c38b731bf Omnifarious Panoply 2026-05-02 20:39:08 -05:00
firestarsdog 5312ce3082 SLC Gods, pls 2026-05-02 21:06:31 -04:00
whoisdomi 3c27a6a273 Fix Domi's rant 2026-05-02 19:44:26 -05:00
firestar5683 d4f73f56c4 honda 2026-05-02 15:54:34 -05:00
firestar5683 5584535842 honda 2026-05-02 15:33:29 -05:00
firestar5683 5607d3d01a i6 2026-05-02 15:29:05 -05:00
firestar5683 5ace618860 Update latcontrol_pid.py 2026-05-02 15:02:44 -05:00
firestar5683 fc4a53c02e update 2026-05-02 13:29:21 -05:00
firestar5683 1a016da5fa i6 2026-05-02 12:20:57 -05:00
firestar5683 0f5ab2f6f6 cem light latch 2026-05-02 09:57:49 -05:00
firestar5683 be88d86b21 patch 2026-05-02 09:19:39 -05:00
firestarsdog d98d1c3432 BigUI WIP: Long + Clean...er..ish 2026-05-02 02:49:47 -04:00
firestar5683 873275374d build 2026-05-01 23:26:21 -05:00
firestar5683 712aa081bc HKG Blended CAN/CAN-FD 2026-05-01 23:20:45 -05:00
firestarsdog 0c39558afb BigUI WIP: Lil cleanup 2026-05-01 21:36:30 -04:00
firestar5683 762146babc tǔne 2026-05-01 18:57:37 -05:00
firestar5683 708af332de build 2026-05-01 18:35:08 -05:00
firestar5683 c612f7a102 tüne 2026-05-01 17:32:30 -05:00
whoisdomi 943a060db2 Developer sidebar fix
Auto-tune off would still display auto-tune values.
Correct chosen values were being used but not displayed.
2026-05-01 15:00:42 -05:00
firestar5683 b77341c804 honda lpf 2026-05-01 14:54:13 -05:00
firestar5683 f69599fabb honda wobble 2026-05-01 14:34:17 -05:00
firestar5683 617aa0a5db honda I6 2026-05-01 14:19:28 -05:00
firestar5683 86f5102158 multiplier 2026-05-01 13:09:43 -05:00
firestar5683 900bb97459 red light stop 2026-05-01 12:40:29 -05:00
firestar5683 86f99b9e1b auto hold 2026-05-01 12:20:42 -05:00
firestar5683 e57d75a3d7 honda 2026-05-01 11:24:47 -05:00
firestarsdog 375a73891c BigUI WIP: Start on Vehicle Panel 2026-05-01 03:43:12 -04:00
firestarsdog ae4c155c6e BigUI WIP: Cleanerish 2026-05-01 02:39:46 -04:00
firestar5683 eedcfe3c56 bumpity 2026-05-01 00:12:31 -05:00
firestar5683 345747a042 more stuff 2026-04-30 23:31:59 -05:00
firestar5683 26e25bf9a8 Errybody wants tuning 2026-04-30 23:11:16 -05:00
firestar5683 8b12ed459f i6 cem 2026-04-30 17:52:50 -05:00
firestar5683 0041a79823 Genesis 2026-04-30 15:29:11 -05:00
firestarsdog b820a3214f BigUI WIP: In-line sliders 2026-04-30 14:28:09 -04:00
firestar5683 f93a4f5adb build 2026-04-30 11:07:47 -05:00
firestar5683 4503811202 DM and volt auto hold 2026-04-30 11:01:46 -05:00
firestar5683 8ec92d12fd toyboi 2026-04-30 10:31:59 -05:00
firestar5683 edc9a9ce60 I6 and CEM 2026-04-30 10:18:17 -05:00
firestarsdog f58b6fc6c7 BigUI WIP: System Settings Parity 2026-04-30 09:43:34 -04:00
firestar5683 d5b8ab3262 build 2026-04-30 08:34:16 -05:00
whoisdomi 609ba6cf63 Slow takeoff possible fix 2026-04-30 07:22:44 -05:00
whoisdomi b9c5a78d16 Prebuilt flag bug fix 2026-04-30 05:42:43 -05:00
whoisdomi a919998872 Unchain me - HKG
Raises max_accel to match sport+ mode of 3.5m/s2
2026-04-30 05:12:03 -05:00
whoisdomi f7fdd7634e CCmain for SLC
CC main button now accepts the current best speed limit source, even if new speed limit source is not flashing.
It snaps cruise speed to match (+ your offset), in either direction.
It works even before engaging longitudinal, so you can pre-set speed limit.
Won't interfere with cars using CC main for Always-On Lateral.
2026-04-30 05:12:02 -05:00
whoisdomi feb9d49c93 SLC Cleanup
Fix three SLC bugs:
1. Auto-accept limits when not engaged to keep previous_target current.
2. Gate Vision out of the limits dict when not a configured priority slot.
3. Replace mapdOut fallback with 0 when filler has no data to prevent stale OSM speed limits from leaking in.
2026-04-30 05:10:48 -05:00
firestarsdog d0c19745c3 BigUI WIP: Extraction 2026-04-30 01:49:24 -04:00
whoisdomi 3adc8592da Acceleration Profile Changes 2026-04-29 23:58:35 -05:00
firestar5683 dcaec4f160 build 2026-04-29 23:44:59 -05:00
firestar5683 b5340a3f3d blinky 2026-04-29 23:44:59 -05:00
firestar5683 b3a2f141d6 updatz 2026-04-29 23:44:59 -05:00
firestar5683 86db8e39c6 patch 2026-04-29 16:41:42 -05:00
firestar5683 749b0d6d79 build 2026-04-29 15:52:46 -05:00
firestar5683 0c7d259e7f sng 2026-04-29 15:50:30 -05:00
firestar5683 f9d6c0d648 Doms plan small update 2026-04-29 15:38:45 -05:00
firestar5683 3e82e773a9 build 2026-04-29 14:25:51 -05:00
firestar5683 04dbd8d0fd HKG 2026-04-29 14:22:52 -05:00
firestar5683 60d6cc4476 i6 2026-04-29 14:22:46 -05:00
firestar5683 91a6df08b0 Plexy 2026-04-29 14:02:42 -05:00
firestar5683 40aff87f88 HKG Long Tune 2026-04-29 11:34:07 -05:00
firestar5683 e19f7d29b4 i6 2026-04-29 11:33:57 -05:00
firestar5683 f27069f2d2 SLC fix 2026-04-29 11:22:58 -05:00
firestarsdog aac395ccd2 BigUI WIP: Mapsssssss 2026-04-29 11:47:46 -04:00
firestar5683 422d92f0ea RL code 2026-04-28 21:14:00 -05:00
firestar5683 d547e3632d rl 2026-04-28 21:06:03 -05:00
firestar5683 ef57854b81 Doms Plan v5 2026-04-28 20:45:13 -05:00
firestar5683 d7a29e6d81 cry more 2026-04-28 20:43:01 -05:00
firestar5683 a68bc7be2e volt 2026-04-28 18:52:55 -05:00
firestar5683 2ed89e4bb7 i6 2026-04-28 18:16:01 -05:00
firestarsdog 145f9d2b19 BigUI WIP: maps are dumb 2026-04-28 19:09:37 -04:00
firestar5683 94c71b8b20 i6 2026-04-28 18:08:41 -05:00
firestar5683 52071db172 i6 2026-04-28 15:13:22 -05:00
firestar5683 66d2a63bcf Patch 2026-04-28 11:33:20 -05:00
firestar5683 53116c29c8 toyota sng 2026-04-28 11:33:12 -05:00
firestar5683 d8fccdb01c build 2026-04-28 10:46:03 -05:00
firestar5683 be77164d8d Bribe Mayhem 2026-04-28 10:42:47 -05:00
firestar5683 0889b3b0c2 Dom's Plan 4 2026-04-28 10:03:38 -05:00
firestarsdog 67c88675da BigUI WIP: Fix callbacks 2026-04-28 03:00:07 -04:00
firestarsdog 65a9fcf3ec BigUI WIP: More map cleanup 2026-04-28 02:14:16 -04:00
firestar5683 cb56102da7 volt 2026-04-27 23:55:25 -05:00
firestarsdog 2e28374fc9 BigUI WIP: Map Panel WIP 2026-04-28 00:35:31 -04:00
firestar5683 9598e47162 build 2026-04-27 21:26:20 -05:00
whoisdomi 40372c63ee Force Stop 2.0
Force Stop 2.0 — Smoother deceleration curve. On cars with the ADAS stop-sign signal, stops are even more confident; cars without dashboard stop sign signal will also benefit from a new deceleration curve and MPC handoff.

Toggle off = stock behavior.
2026-04-27 21:26:20 -05:00
firestar5683 e24520254b Ioniq 6 Long Tune 2026-04-27 21:26:19 -05:00
firestar5683 43a5c09412 Dom's Plan V3 2026-04-27 11:49:39 -05:00
firestar5683 426dbd1718 Dom's plan 2026-04-27 00:35:13 -05:00
firestar5683 8bae6a1063 Dom's Plan 2026-04-26 23:50:48 -05:00
firestar5683 8f7b28deed genesis 2026-04-26 23:20:43 -05:00
firestar5683 4026b6af9b volt 2026-04-26 23:16:42 -05:00
firestar5683 a5dae4669c i6 2026-04-26 23:01:47 -05:00
firestar5683 6b1e11c314 ioniq 2026-04-26 19:28:17 -05:00
firestar5683 e2681b17a4 lane change? 2026-04-26 17:36:12 -05:00
firestar5683 da61e79f2e hud bsm? 2026-04-26 17:14:39 -05:00
firestar5683 31fefd8eb8 bSM 2026-04-26 15:51:16 -05:00
firestar5683 bcf78fec02 i6 2026-04-26 15:40:15 -05:00
firestar5683 71528fd547 ioniq tests 2026-04-26 14:38:27 -05:00
firestar5683 962e0d740a test 2026-04-26 12:37:51 -05:00
firestar5683 1262a2d8f3 Lane change? 2026-04-26 11:03:42 -05:00
firestar5683 a8ba10aac6 ioniq 6 2026-04-26 00:18:31 -05:00
firestarsdog ff67d2eedd BigUI WIP: Finish nuking nav from ui 2026-04-25 23:40:39 -04:00
firestarsdog a2c39aa2ed BigUI WIP: Remove nav junk 2026-04-25 22:10:29 -04:00
firestarsdog a1a781bcf6 BigUI WIP: Tile title and description cleanup 2026-04-25 22:08:38 -04:00
firestar5683 6d0559c6d9 Dom's Plan 2026-04-25 20:51:58 -05:00
firestar5683 330a811114 ioniq tune | blindspot | paddle 2026-04-25 20:51:58 -05:00
firestarsdog ed695fab1b BigUI WIP: Simpleton 2026-04-25 17:17:13 -04:00
firestar5683 a2d51807c7 ioniq 6 2026-04-25 15:58:10 -05:00
firestar5683 df0b6c3e2b YOU WERE THE CHOSEN ONE 2026-04-25 15:39:43 -05:00
firestar5683 636e0d0585 Suppress Dash Faults? 2026-04-25 14:54:33 -05:00
firestar5683 124daf1f51 ioniq 6 2026-04-25 14:26:42 -05:00
whoisdomi e8d0d7bc3a ECU disable fallback stock HDA2 fix
When car is started in "ready" mode now stock acc will work as intended
2026-04-25 10:37:31 -05:00
firestar5683 f074dcc3b5 Revert "Fallback mode HDA2"
This reverts commit 2e4c3f43ee.
2026-04-25 10:37:19 -05:00
whoisdomi 2eb4dfbdc9 Lane Smoothing Tune
Tune to prevent overshoot
2026-04-25 01:15:57 -05:00
firestar5683 2e4c3f43ee Fallback mode HDA2
Revert "Fallback mode HDA2"

This reverts commit 81b2b3584227bd1aa62089770245e50e131e0a3b.

Fallback mode hda2
2026-04-25 01:15:57 -05:00
firestar5683 be87ecec3e ioniq 6 2026-04-24 22:22:34 -05:00
firestar5683 317be3b383 nostalgia 2026-04-24 20:44:12 -05:00
firestar5683 ca5b641b96 Voacc refinement and non-scc cruise check 2026-04-24 18:19:18 -05:00
firestar5683 031ad89851 kia forte 2026-04-24 16:16:25 -05:00
1938 changed files with 312005 additions and 236544 deletions
+9
View File
@@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(python3 -c \"import json; json.load\\(open\\(r'c:\\\\Users\\\\user\\\\Documents\\\\GitHub\\\\openpilot\\\\starpilot\\\\system\\\\the_pond\\\\assets\\\\components\\\\tools\\\\device_settings_layout.json'\\)\\)\")",
"Bash(python3 -m py_compile \"c:\\\\Users\\\\user\\\\Documents\\\\GitHub\\\\openpilot\\\\starpilot\\\\controls\\\\lib\\\\starpilot_vcruise.py\")",
"Bash(python3 -m py_compile \"c:\\\\Users\\\\user\\\\Documents\\\\GitHub\\\\openpilot\\\\selfdrive\\\\ui\\\\layouts\\\\settings\\\\starpilot\\\\longitudinal.py\")"
]
}
}
-52
View File
@@ -1,52 +0,0 @@
name: "PR review"
on:
pull_request_target:
types: [opened, reopened, synchronize, edited]
jobs:
labeler:
name: review
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: false
# Label PRs
- uses: actions/labeler@v5.0.0
with:
dot: true
configuration-path: .github/labeler.yaml
# Check PR target branch
- name: check branch
uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5
if: github.repository == 'commaai/openpilot'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
target: /^(?!master$).*/
exclude: /commaai:.*/
change-to: ${{ github.base_ref }}
already-exists-action: close_this
already-exists-comment: "Your PR should be made against the `master` branch"
# Welcome comment
- name: "First timers PR"
uses: actions/first-interaction@v1
if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot'
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
pr-message: |
<!-- _(run_id **${{ github.run_id }}**)_ -->
Thanks for contributing to openpilot! In order for us to review your PR as quickly as possible, check the following:
* Convert your PR to a draft unless it's ready to review
* Read the [contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md)
* Before marking as "ready for review", ensure:
* the goal is clearly stated in the description
* all the tests are passing
* the change is [something we merge](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md#what-gets-merged)
* include a route or your device' dongle ID if relevant
-37
View File
@@ -1,37 +0,0 @@
name: badges
on:
schedule:
- cron: '0 * * * *'
workflow_dispatch:
env:
BASE_IMAGE: openpilot-base
DOCKER_REGISTRY: ghcr.io/commaai
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c
jobs:
badges:
name: create badges
runs-on: ubuntu-latest
if: github.repository == 'commaai/openpilot'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
- name: Push badges
run: |
${{ env.RUN }} "python3 selfdrive/ui/translations/create_badges.py"
rm .gitattributes
git checkout --orphan badges
git rm -rf --cached .
git config user.email "badge-researcher@comma.ai"
git config user.name "Badge Researcher"
git add translation_badge.svg
git commit -m "Add/Update badges"
git push -f origin HEAD
-101
View File
@@ -1,101 +0,0 @@
name: weekly CI test report
on:
schedule:
- cron: '37 9 * * 1' # 9:37AM UTC -> 2:37AM PST every monday
workflow_dispatch:
inputs:
ci_runs:
description: 'The amount of runs to trigger in CI test report'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CI_RUNS: ${{ github.event.inputs.ci_runs || '50' }}
jobs:
setup:
if: github.repository == 'commaai/openpilot'
runs-on: ubuntu-latest
outputs:
ci_runs: ${{ steps.ci_runs_setup.outputs.matrix }}
steps:
- id: ci_runs_setup
name: CI_RUNS=${{ env.CI_RUNS }}
run: |
matrix=$(python3 -c "import json; print(json.dumps({ 'run_number' : list(range(${{ env.CI_RUNS }})) }))")
echo "matrix=$matrix" >> $GITHUB_OUTPUT
ci_matrix_run:
needs: [ setup ]
strategy:
fail-fast: false
matrix: ${{fromJSON(needs.setup.outputs.ci_runs)}}
uses: commaai/openpilot/.github/workflows/ci_weekly_run.yaml@master
with:
run_number: ${{ matrix.run_number }}
report:
needs: [ci_matrix_run]
runs-on: ubuntu-latest
if: always() && github.repository == 'commaai/openpilot'
steps:
- name: Get job results
uses: actions/github-script@v7
id: get-job-results
with:
script: |
const jobs = await github
.paginate("GET /repos/{owner}/{repo}/actions/runs/{run_id}/attempts/{attempt}/jobs", {
owner: "commaai",
repo: "${{ github.event.repository.name }}",
run_id: "${{ github.run_id }}",
attempt: "${{ github.run_attempt }}",
})
var report = {}
jobs.slice(1, jobs.length-1).forEach(job => {
if (job.conclusion === "skipped") return;
const jobName = job.name.split(" / ")[2];
const runRegex = /\((.*?)\)/;
const run = job.name.match(runRegex)[1];
report[jobName] = report[jobName] || { successes: [], failures: [], canceled: [] };
switch (job.conclusion) {
case "success":
report[jobName].successes.push({ "run_number": run, "link": job.html_url}); break;
case "failure":
report[jobName].failures.push({ "run_number": run, "link": job.html_url }); break;
case "canceled":
report[jobName].canceled.push({ "run_number": run, "link": job.html_url }); break;
}
});
return JSON.stringify({"jobs": report});
- name: Add job results to summary
env:
JOB_RESULTS: ${{ fromJSON(steps.get-job-results.outputs.result) }}
run: |
cat <<EOF >> template.html
<table>
<thead>
<tr>
<th></th>
<th>Job</th>
<th>✅ Passing</th>
<th>❌ Failure Details</th>
</tr>
</thead>
<tbody>
{% for key in jobs.keys() %}<tr>
<td>{% for i in range(5) %}{% if i+1 <= (5 * jobs[key]["successes"]|length // ${{ env.CI_RUNS }}) %}🟩{% else %}🟥{% endif %}{% endfor%}</td>
<td>{{ key }}</td>
<td>{{ 100 * jobs[key]["successes"]|length // ${{ env.CI_RUNS }} }}%</td>
<td>{% if jobs[key]["failures"]|length > 0 %}<details>{% for failure in jobs[key]["failures"] %}<a href="{{ failure['link'] }}">Log for run #{{ failure['run_number'] }}</a><br>{% endfor %}</details>{% else %}{% endif %}</td>
</td>
</tr>{% endfor %}
</table>
EOF
pip install jinja2-cli
echo $JOB_RESULTS | jinja2 template.html > report.html
echo "# CI Test Report - ${{ env.CI_RUNS }} Runs" >> $GITHUB_STEP_SUMMARY
cat report.html >> $GITHUB_STEP_SUMMARY
-17
View File
@@ -1,17 +0,0 @@
name: weekly CI test run
on:
workflow_call:
inputs:
run_number:
required: true
type: string
concurrency:
group: ci-run-${{ inputs.run_number }}-${{ github.ref }}
cancel-in-progress: true
jobs:
tests:
uses: commaai/openpilot/.github/workflows/tests.yaml@master
with:
run_number: ${{ inputs.run_number }}
+215
View File
@@ -0,0 +1,215 @@
name: Compile Bluescreens
on:
workflow_dispatch:
inputs:
target_ref:
description: "Branch to build and publish back to"
type: string
default: "bluescreensonly2"
required: true
jobs:
description: "Optional parallel job count passed to ./build"
type: string
default: "12"
required: false
enable_scons_cache:
description: "Enable SCons cache for faster incremental builds"
type: boolean
default: true
required: false
build_all:
description: "Build everything"
type: boolean
default: true
required: false
build_ui:
description: "Build UI (selfdrive/ui)"
type: boolean
default: true
required: false
build_params:
description: "Build params Python extension"
type: boolean
default: false
required: false
build_cereal:
description: "Build cereal messaging bridge"
type: boolean
default: false
required: false
build_panda:
description: "Build panda firmware outputs"
type: boolean
default: true
required: false
build_modeld:
description: "Build modeld Python extension"
type: boolean
default: false
required: false
build_controls:
description: "Build controls solvers + locationd generated models"
type: boolean
default: false
required: false
concurrency:
group: compile-bluescreens-${{ inputs.target_ref }}
cancel-in-progress: false
permissions:
contents: write
env:
GIT_EMAIL: "168790843+firestar5683@users.noreply.github.com"
GIT_NAME: "StarPilot Build Bot"
TARGET_REF: ${{ inputs.target_ref }}
jobs:
build_and_push:
runs-on: [self-hosted, truenas, starpilot-build]
timeout-minutes: 720
steps:
- name: Validate target branch
shell: bash
run: |
set -euo pipefail
if [[ -z "${TARGET_REF}" ]]; then
echo "target_ref is required." >&2
exit 1
fi
if [[ "${TARGET_REF}" == refs/heads/* ]]; then
echo "BUILD_BRANCH=${TARGET_REF#refs/heads/}" >> "$GITHUB_ENV"
else
echo "BUILD_BRANCH=${TARGET_REF}" >> "$GITHUB_ENV"
fi
- name: Checkout target branch
uses: actions/checkout@v4
with:
ref: ${{ env.BUILD_BRANCH }}
fetch-depth: 0
submodules: recursive
- name: Configure git identity
shell: bash
run: |
set -euo pipefail
git config user.name "$GIT_NAME"
git config user.email "$GIT_EMAIL"
git config http.postBuffer 104857600
- name: Ensure branch exists on origin
shell: bash
run: |
set -euo pipefail
git ls-remote --exit-code --heads origin "refs/heads/${BUILD_BRANCH}" >/dev/null
- name: Link persistent sysroot
shell: bash
run: |
set -euo pipefail
ls -ld /runner /runner/sysroots /runner/sysroots/default || true
ls -ld /runner/sysroots/default/usr /runner/sysroots/default/usr/local /runner/sysroots/default/usr/local/lib || true
rm -rf .comma_sysroot
ln -s /runner/sysroots/default .comma_sysroot
ls -ld .comma_sysroot .comma_sysroot/usr .comma_sysroot/usr/local .comma_sysroot/usr/local/lib
- name: Run Bluescreens build
shell: bash
env:
SP_ENABLE_SCONS_CACHE: ${{ inputs.enable_scons_cache && '1' || '0' }}
run: |
set -euo pipefail
RUNNER_HOST_ROOT="/mnt/Apparition/My_App_Data/starpilot-runner"
if [[ "${GITHUB_WORKSPACE}" != /runner/_work/* ]]; then
echo "Unexpected GITHUB_WORKSPACE: ${GITHUB_WORKSPACE}" >&2
exit 1
fi
WORKSPACE_REL="${GITHUB_WORKSPACE#/runner}"
export COMMA_HOST_ROOT_DIR="${RUNNER_HOST_ROOT}${WORKSPACE_REL}"
export COMMA_HOST_SYSROOT_DIR="${RUNNER_HOST_ROOT}/sysroots/default"
export COMMA_HOST_CACHE_DIR="${RUNNER_HOST_ROOT}/cache/work"
export COMMA_HOST_VENV_DIR="${RUNNER_HOST_ROOT}/cache/venv-linux-arm64"
export COMMA_SYSROOT_DIR="/runner/sysroots/default"
echo "GITHUB_WORKSPACE=${GITHUB_WORKSPACE}"
echo "COMMA_HOST_ROOT_DIR=${COMMA_HOST_ROOT_DIR}"
echo "COMMA_HOST_SYSROOT_DIR=${COMMA_HOST_SYSROOT_DIR}"
echo "COMMA_HOST_CACHE_DIR=${COMMA_HOST_CACHE_DIR}"
echo "COMMA_HOST_VENV_DIR=${COMMA_HOST_VENV_DIR}"
JOBS="${{ inputs.jobs }}"
if [[ "${{ inputs.build_all }}" == "true" ]]; then
if [[ -n "${JOBS}" ]]; then
./build "${JOBS}"
else
./build
fi
exit 0
fi
TARGETS=()
[[ "${{ inputs.build_ui }}" == "true" ]] && TARGETS+=("selfdrive/ui/ui")
[[ "${{ inputs.build_params }}" == "true" ]] && TARGETS+=("common/params_pyx.so")
[[ "${{ inputs.build_cereal }}" == "true" ]] && TARGETS+=("cereal/messaging/bridge")
if [[ "${{ inputs.build_panda }}" == "true" ]]; then
TARGETS+=(
"panda/board/obj/panda.bin.signed"
"panda/board/obj/panda_h7.bin.signed"
"panda/board/obj/panda_remote.bin.signed"
"panda/board/obj/panda_h7_remote.bin.signed"
"panda/board/obj/panda_can_ignition_only.bin.signed"
"panda/board/obj/panda_h7_can_ignition_only.bin.signed"
"panda/board/obj/panda_remote_can_ignition_only.bin.signed"
"panda/board/obj/panda_h7_remote_can_ignition_only.bin.signed"
"panda/board/obj/panda_jungle_h7.bin.signed"
"panda/board/obj/body_h7.bin.signed"
)
fi
[[ "${{ inputs.build_modeld }}" == "true" ]] && TARGETS+=("selfdrive/modeld/models/commonmodel_pyx.so")
if [[ "${{ inputs.build_controls }}" == "true" ]]; then
TARGETS+=(
"selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/libacados_ocp_solver_lat.so"
"selfdrive/controls/lib/longitudinal_mpc_lib/c_generated_code/libacados_ocp_solver_long.so"
"selfdrive/locationd/models/generated/car.cpp"
"selfdrive/locationd/models/generated/pose.cpp"
)
fi
if [[ ${#TARGETS[@]} -eq 0 ]]; then
echo "No partial targets selected; defaulting to UI + panda"
TARGETS=("selfdrive/ui/ui" "panda/board/obj/panda.bin.signed")
fi
echo "Running partial build for targets: ${TARGETS[*]}"
if [[ -n "${JOBS}" ]]; then
./build "${JOBS}" "${TARGETS[@]}"
else
./build "$(nproc)" "${TARGETS[@]}"
fi
- name: Commit build output
shell: bash
run: |
set -euo pipefail
if [[ -z "$(git status --porcelain --untracked-files=no)" ]]; then
echo "No build output changes detected."
exit 0
fi
git add -u
git commit -m "build"
- name: Push build commit
shell: bash
run: |
set -euo pipefail
git push origin "HEAD:refs/heads/${BUILD_BRANCH}"
+81 -205
View File
@@ -3,237 +3,113 @@ name: Compile StarPilot
on:
workflow_dispatch:
inputs:
not_vetted:
description: "This branch is not vetted"
type: boolean
default: false
required: false
publish_custom_branch:
description: "Push to custom branch:"
target_ref:
description: "Branch to build and publish back to"
type: string
default: ""
required: false
publish_starpilot:
description: "Push to StarPilot"
type: boolean
default: false
required: false
publish_staging:
description: "Push to StarPilot-Staging"
type: boolean
default: false
required: false
publish_testing:
description: "Push to StarPilot-Testing"
type: boolean
default: false
required: false
runner:
description: "Select runner"
type: choice
options:
- c3
- c3x
default: "c3"
default: "master"
required: true
update_translations:
description: "Update missing/outdated translations"
type: boolean
default: false
required: false
vet_existing_translations:
description: "Vet existing translations"
type: boolean
default: false
jobs:
description: "Optional parallel job count passed to ./build"
type: string
default: "12"
required: false
concurrency:
group: compile-starpilot-${{ inputs.target_ref }}
cancel-in-progress: false
permissions:
contents: write
env:
BASE_DIR: ${{ github.workspace }}
BUILD_DIR: "/data/openpilot"
CUSTOM_BRANCH: ${{ inputs.publish_custom_branch }}
GIT_EMAIL: "91348155+FrogAi@users.noreply.github.com"
GIT_NAME: "James"
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GIT_EMAIL: "168790843+firestar5683@users.noreply.github.com"
GIT_NAME: "StarPilot Build Bot"
TARGET_REF: ${{ inputs.target_ref }}
jobs:
get_branch:
runs-on: [self-hosted, "${{ inputs.runner }}"]
outputs:
branch: ${{ steps.get_branch.outputs.branch }}
python_version: ${{ steps.get_python_version.outputs.python_version }}
build_and_push:
runs-on: [self-hosted, truenas, starpilot-build]
timeout-minutes: 720
steps:
- name: Get Current Branch
id: get_branch
- name: Validate target branch
shell: bash
run: |
cd "$BUILD_DIR"
echo "branch=$(git rev-parse --abbrev-ref HEAD)" >> "$GITHUB_OUTPUT"
set -euo pipefail
- name: Get Python Version
id: get_python_version
run: |
echo "python_version=$(tr -d '[:space:]' < "$BUILD_DIR/.python-version")" >> $GITHUB_OUTPUT
if [[ -z "${TARGET_REF}" ]]; then
echo "target_ref is required." >&2
exit 1
fi
translate:
needs: get_branch
if: inputs.update_translations
runs-on: ubuntu-latest
steps:
- name: Configure Git Identity
run: |
git config --global user.name "$GIT_NAME"
git config --global user.email "$GIT_EMAIL"
if [[ "${TARGET_REF}" == refs/heads/* ]]; then
echo "BUILD_BRANCH=${TARGET_REF#refs/heads/}" >> "$GITHUB_ENV"
else
echo "BUILD_BRANCH=${TARGET_REF}" >> "$GITHUB_ENV"
fi
- name: Checkout Required Files
- name: Checkout target branch
uses: actions/checkout@v4
with:
ref: ${{ needs.get_branch.outputs.branch }}
sparse-checkout: |
starpilot/ui/
selfdrive/controls/lib/alerts_offroad.json
selfdrive/ui/
selfdrive/ui/translations/
selfdrive/ui/translations/auto_translate.py
selfdrive/ui/update_translations.py
ref: ${{ env.BUILD_BRANCH }}
fetch-depth: 0
submodules: recursive
- name: Set Up Python
uses: actions/setup-python@v4
with:
cache: "pip"
python-version: ${{ needs.get_branch.outputs.python_version }}
- name: Install Dependencies
- name: Configure git identity
shell: bash
run: |
pip install requests
sudo apt-get update && sudo apt-get install -y --no-install-recommends qttools5-dev-tools
set -euo pipefail
git config user.name "$GIT_NAME"
git config user.email "$GIT_EMAIL"
git config http.postBuffer 104857600
- name: Update Translations
- name: Ensure branch exists on origin
shell: bash
run: |
python selfdrive/ui/update_translations.py --vanish
set -euo pipefail
git ls-remote --exit-code --heads origin "refs/heads/${BUILD_BRANCH}" >/dev/null
- name: Update Missing Translations
continue-on-error: true
timeout-minutes: 300
- name: Link persistent sysroot
shell: bash
run: |
python selfdrive/ui/translations/auto_translate.py --all-files
set -euo pipefail
ls -ld /runner /runner/sysroots /runner/sysroots/default || true
ls -ld /runner/sysroots/default/usr /runner/sysroots/default/usr/local /runner/sysroots/default/usr/local/lib || true
rm -rf .comma_sysroot
ln -s /runner/sysroots/default .comma_sysroot
ls -ld .comma_sysroot .comma_sysroot/usr .comma_sysroot/usr/local .comma_sysroot/usr/local/lib
- name: Vet Existing Translations
if: inputs.vet_existing_translations
continue-on-error: true
timeout-minutes: 300
- name: Run StarPilot device build
shell: bash
run: |
python selfdrive/ui/translations/auto_translate.py --all-files --vet-translations
set -euo pipefail
- name: Commit and Push Translations
export COMMA_HOST_ROOT_DIR="/mnt/Apparition/My_App_Data/starpilot-runner/_work/${GITHUB_REPOSITORY#*/}/${GITHUB_REPOSITORY#*/}"
export COMMA_HOST_SYSROOT_DIR="/mnt/Apparition/My_App_Data/starpilot-runner/sysroots/default"
export COMMA_HOST_CACHE_DIR="/mnt/Apparition/My_App_Data/starpilot-runner/cache/work"
export COMMA_HOST_VENV_DIR="/mnt/Apparition/My_App_Data/starpilot-runner/cache/venv-linux-arm64"
export COMMA_SYSROOT_DIR="/runner/sysroots/default"
if [[ -n "${{ inputs.jobs }}" ]]; then
./build "${{ inputs.jobs }}"
else
./build
fi
- name: Commit build output
shell: bash
run: |
if git diff --quiet selfdrive/ui/translations/*.ts; then
echo "No translation updates detected."
set -euo pipefail
if [[ -z "$(git status --porcelain --untracked-files=no)" ]]; then
echo "No build output changes detected."
exit 0
fi
git fetch --unshallow origin "${{ needs.get_branch.outputs.branch }}"
git checkout "${{ needs.get_branch.outputs.branch }}"
git add selfdrive/ui/translations/*.ts
git commit --amend --no-edit
git push --force origin "${{ needs.get_branch.outputs.branch }}"
git add -u
git commit -m "build"
build_and_push:
needs: [get_branch, translate]
if: ${{ !failure() && !cancelled() && needs.get_branch.result == 'success' }}
runs-on: [self-hosted, "${{ inputs.runner }}"]
permissions:
contents: write
defaults:
run:
working-directory: ${{ env.BUILD_DIR }}
steps:
- name: Configure Git
- name: Push build commit
shell: bash
run: |
git config http.postBuffer 104857600
git config user.name "$GIT_NAME"
git config user.email "$GIT_EMAIL"
git remote set-url origin "https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/FrogAi/StarPilot.git"
- name: Sync Translation Updates
if: inputs.update_translations
run: |
git fetch origin "${{ needs.get_branch.outputs.branch }}"
git reset --hard FETCH_HEAD
- name: Take Ownership of Build Directory
run: |
sudo chown -R $(whoami):$(whoami) .
- name: Clean Build Artifacts
run: |
find . -name "matlab.*.md" -delete
find . -type d \( -iname "debug" -o -iname "test" -o -iname "tests" -o -name '__pycache__' \) -exec rm -rf {} +
find . -type f \( \
-name '*.a' -o \
-name '*.o' -o \
-name '*.onnx' -o \
-name '*.os' -o \
-name '*.pyc' -o \
-name 'moc_*' \
\) -delete
find .github -mindepth 1 -maxdepth 1 ! -name 'workflows' -exec rm -rf {} +
find .github/workflows -mindepth 1 ! \( \
-type f \( \
-name 'compile_starpilot.yaml' -o \
-name 'review_pull_request.yaml' -o \
-name 'schedule_update.yaml' -o \
-name 'update_pr_branch.yaml' -o \
-name 'update_release_branch.yaml' -o \
-name 'update_tinygrad.yaml' \
\) \
\) -exec rm -rf {} +
find panda/board -type f \
! -name '__init__.py' \
! -name 'bootstub.panda.bin' \
! -name 'bootstub.panda_h7.bin' \
! -name 'panda.bin.signed' \
! -name 'panda_h7.bin.signed' \
-delete
find third_party/ -name '*Darwin*' -exec rm -rf {} +
find third_party/ -name '*x86*' -exec rm -rf {} +
rm -f .gitignore .gitmodules .gitattributes .lfsconfig .overlay_init
rm -rf .sconsign.dblite .vscode/ Jenkinsfile release/ scripts/ site_scons/ teleoprtc_repo/
find . -type d -empty ! -path "./.git*" -delete
touch prebuilt
[ "${{ inputs.not_vetted }}" = "true" ] && touch not_vetted || true
- name: Add Update Date File
if: inputs.publish_staging
continue-on-error: true
run: |
curl -fLsS https://raw.githubusercontent.com/FrogAi/StarPilot/StarPilot-Staging/.github/update_date -o .github/update_date || echo "No update_date found, skipping..."
- name: Commit and Push Build
run: |
git add -f .
git commit -m "Compile StarPilot"
git push --force origin HEAD
if [ "${{ inputs.publish_starpilot }}" = "true" ]; then
git push --force origin HEAD:StarPilot
fi
if [ "${{ inputs.publish_staging }}" = "true" ]; then
git push --force origin HEAD:StarPilot-Staging
fi
if [ "${{ inputs.publish_testing }}" = "true" ]; then
git push --force origin HEAD:StarPilot-Testing
fi
if [ -n "$CUSTOM_BRANCH" ]; then
git push --force origin HEAD:"$CUSTOM_BRANCH"
fi
set -euo pipefail
git push origin "HEAD:refs/heads/${BUILD_BRANCH}"
-65
View File
@@ -1,65 +0,0 @@
name: docs
on:
push:
branches:
- master
pull_request:
workflow_call:
inputs:
run_number:
default: '1'
required: true
type: string
concurrency:
group: docs-tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
cancel-in-progress: true
jobs:
docs:
name: build docs
runs-on: ubuntu-24.04
steps:
- uses: commaai/timeout@v1
- uses: actions/checkout@v4
with:
submodules: true
# Build
- name: Build docs
run: |
# TODO: can we install just the "docs" dependency group without the normal deps?
pip install mkdocs
mkdocs build
# Push to docs.comma.ai
- uses: actions/checkout@v4
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
with:
path: openpilot-docs
ssh-key: ${{ secrets.OPENPILOT_DOCS_KEY }}
repository: commaai/openpilot-docs
- name: Push
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
run: |
set -x
source release/identity.sh
cd openpilot-docs
git checkout --orphan tmp
git rm -rf .
# copy over docs
cp -r ../docs_site/ docs/
# GitHub pages config
touch docs/.nojekyll
echo -n docs.comma.ai > docs/CNAME
git add -f .
git commit -m "build docs"
# docs live in different repo to not bloat openpilot's full clone size
git push -f origin tmp:gh-pages
-59
View File
@@ -1,59 +0,0 @@
name: jenkins scan
on:
issue_comment:
types: [created, edited]
jobs:
# TODO: gc old branches in a separate job in this workflow
scan-comments:
runs-on: ubuntu-latest
if: ${{ github.event.issue.pull_request }}
permissions:
contents: write
issues: write
steps:
- name: Check for trigger phrase
id: check_comment
uses: actions/github-script@v7
with:
script: |
const triggerPhrase = "trigger-jenkins";
const comment = context.payload.comment.body;
const commenter = context.payload.comment.user.login;
const { data: permissions } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: commenter
});
const hasWriteAccess = permissions.permission === 'write' || permissions.permission === 'admin';
return (hasWriteAccess && comment.includes(triggerPhrase));
result-encoding: json
- name: Checkout repository
if: steps.check_comment.outputs.result == 'true'
uses: actions/checkout@v4
with:
ref: refs/pull/${{ github.event.issue.number }}/head
- name: Push to tmp-jenkins branch
if: steps.check_comment.outputs.result == 'true'
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b tmp-jenkins-${{ github.event.issue.number }}
GIT_LFS_SKIP_PUSH=1 git push -f origin tmp-jenkins-${{ github.event.issue.number }}
- name: Delete trigger comment
if: steps.check_comment.outputs.result == 'true' && always()
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
});
@@ -1,151 +0,0 @@
name: "mici raylib ui preview"
on:
push:
branches:
- master
pull_request_target:
types: [assigned, opened, synchronize, reopened, edited]
branches:
- 'master'
paths:
- 'selfdrive/assets/**'
- 'selfdrive/ui/**'
- 'system/ui/**'
workflow_dispatch:
env:
UI_JOB_NAME: "Create mici raylib UI Report"
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.sha || github.event.pull_request.head.sha }}
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}-mici-raylib-ui"
MASTER_BRANCH_NAME: "openpilot_master_ui_mici_raylib"
# All report files are pushed here
REPORT_FILES_BRANCH_NAME: "mici-raylib-ui-reports"
jobs:
preview:
if: github.repository == 'commaai/openpilot'
name: preview
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
pull-requests: write
actions: read
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Waiting for ui generation to end
uses: lewagon/wait-on-check-action@v1.3.4
with:
ref: ${{ env.SHA }}
check-name: ${{ env.UI_JOB_NAME }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
allowed-conclusions: success
wait-interval: 20
- name: Getting workflow run ID
id: get_run_id
run: |
echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ env.SHA }}/check-runs | jq -r '.check_runs[] | select(.name == "${{ env.UI_JOB_NAME }}") | .html_url | capture("(?<number>[0-9]+)") | .number')" >> $GITHUB_OUTPUT
- name: Getting proposed ui # filename: pr_ui/mici_ui_replay.mp4
id: download-artifact
uses: dawidd6/action-download-artifact@v6
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
run_id: ${{ steps.get_run_id.outputs.run_id }}
search_artifacts: true
name: mici-raylib-report-1-${{ env.REPORT_NAME }}
path: ${{ github.workspace }}/pr_ui
- name: Getting master ui # filename: master_ui_raylib/mici_ui_replay.mp4
uses: actions/checkout@v4
with:
repository: commaai/ci-artifacts
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
path: ${{ github.workspace }}/master_ui_raylib
ref: ${{ env.MASTER_BRANCH_NAME }}
- name: Saving new master ui
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
working-directory: ${{ github.workspace }}/master_ui_raylib
run: |
git checkout --orphan=new_master_ui_mici_raylib
git rm -rf *
git branch -D ${{ env.MASTER_BRANCH_NAME }}
git branch -m ${{ env.MASTER_BRANCH_NAME }}
git config user.name "GitHub Actions Bot"
git config user.email "<>"
mv ${{ github.workspace }}/pr_ui/* .
git add .
git commit -m "mici raylib video for commit ${{ env.SHA }}"
git push origin ${{ env.MASTER_BRANCH_NAME }} --force
- name: Setup FFmpeg
uses: AnimMouse/setup-ffmpeg@ae28d57dabbb148eff63170b6bf7f2b60062cbae
- name: Finding diff
if: github.event_name == 'pull_request_target'
id: find_diff
run: |
# Find the video file from PR
pr_video="${{ github.workspace }}/pr_ui/mici_ui_replay_proposed.mp4"
mv "${{ github.workspace }}/pr_ui/mici_ui_replay.mp4" "$pr_video"
master_video="${{ github.workspace }}/pr_ui/mici_ui_replay_master.mp4"
mv "${{ github.workspace }}/master_ui_raylib/mici_ui_replay.mp4" "$master_video"
# Run report
export PYTHONPATH=${{ github.workspace }}
baseurl="https://github.com/commaai/ci-artifacts/raw/refs/heads/${{ env.BRANCH_NAME }}"
diff_exit_code=0
python3 ${{ github.workspace }}/selfdrive/ui/tests/diff/diff.py "${{ github.workspace }}/pr_ui/mici_ui_replay_master.mp4" "${{ github.workspace }}/pr_ui/mici_ui_replay_proposed.mp4" "diff.html" --basedir "$baseurl" --no-open || diff_exit_code=$?
# Copy diff report files
cp ${{ github.workspace }}/selfdrive/ui/tests/diff/report/diff.html ${{ github.workspace }}/pr_ui/
cp ${{ github.workspace }}/selfdrive/ui/tests/diff/report/diff.mp4 ${{ github.workspace }}/pr_ui/
REPORT_URL="https://commaai.github.io/ci-artifacts/diff_pr_${{ github.event.number }}.html"
if [ $diff_exit_code -eq 0 ]; then
DIFF="✅ Videos are identical! [View Diff Report]($REPORT_URL)"
else
DIFF="❌ <strong>Videos differ!</strong> [View Diff Report]($REPORT_URL)"
fi
echo "DIFF=$DIFF" >> "$GITHUB_OUTPUT"
- name: Saving proposed ui
if: github.event_name == 'pull_request_target'
working-directory: ${{ github.workspace }}/master_ui_raylib
run: |
# Overwrite PR branch w/ proposed ui, and master ui at this point in time for future reference
git config user.name "GitHub Actions Bot"
git config user.email "<>"
git checkout --orphan=${{ env.BRANCH_NAME }}
git rm -rf *
mv ${{ github.workspace }}/pr_ui/* .
git add .
git commit -m "mici raylib video for PR #${{ github.event.number }}"
git push origin ${{ env.BRANCH_NAME }} --force
# Append diff report to report files branch
git fetch origin ${{ env.REPORT_FILES_BRANCH_NAME }}
git checkout ${{ env.REPORT_FILES_BRANCH_NAME }}
cp ${{ github.workspace }}/selfdrive/ui/tests/diff/report/diff.html diff_pr_${{ github.event.number }}.html
git add diff_pr_${{ github.event.number }}.html
git commit -m "mici raylib ui diff report for PR #${{ github.event.number }}" || echo "No changes to commit"
git push origin ${{ env.REPORT_FILES_BRANCH_NAME }}
- name: Comment Video on PR
if: github.event_name == 'pull_request_target'
uses: thollander/actions-comment-pull-request@v2
with:
message: |
<!-- _(run_id_video_mici_raylib **${{ github.run_id }}**)_ -->
## mici raylib UI Preview
${{ steps.find_diff.outputs.DIFF }}
comment_tag: run_id_video_mici_raylib
pr_number: ${{ github.event.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-42
View File
@@ -1,42 +0,0 @@
name: "model review"
on:
pull_request:
types: [opened, reopened, synchronize]
paths:
- 'selfdrive/modeld/models/*.onnx'
workflow_dispatch:
jobs:
comment:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
if: github.repository == 'commaai/openpilot'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Checkout master
uses: actions/checkout@v4
with:
ref: master
path: base
- run: git lfs pull
- run: cd base && git lfs pull
- run: pip install onnx
- name: scripts/reporter.py
id: report
run: |
echo "content<<EOF" >> $GITHUB_OUTPUT
echo "## Model Review" >> $GITHUB_OUTPUT
MASTER_PATH=${{ github.workspace }}/base python scripts/reporter.py >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Post model report comment
uses: marocchino/sticky-pull-request-comment@baa7203ed60924babbe5dcd0ac8eae3b66ec5e16
with:
header: model-review
message: ${{ steps.report.outputs.content }}
-39
View File
@@ -1,39 +0,0 @@
name: prebuilt
on:
schedule:
- cron: '0 * * * *'
workflow_dispatch:
env:
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
BUILD: selfdrive/test/docker_build.sh prebuilt
jobs:
build_prebuilt:
name: build prebuilt
runs-on: ubuntu-latest
if: github.repository == 'commaai/openpilot'
env:
PUSH_IMAGE: true
permissions:
checks: read
contents: read
packages: write
steps:
- name: Wait for green check mark
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
with:
ref: master
wait-interval: 30
running-workflow-name: 'build prebuilt'
repo-token: ${{ secrets.GITHUB_TOKEN }}
check-regexp: ^((?!.*(build master-ci).*).)*$
- uses: actions/checkout@v4
with:
submodules: true
- run: git lfs pull
- name: Build and Push docker image
run: |
$DOCKER_LOGIN
eval "$BUILD"
@@ -0,0 +1,35 @@
name: Publish TrueNAS Runner Image
on:
workflow_dispatch:
inputs:
image_tag:
description: "Container tag to publish to GHCR"
type: string
default: "latest"
required: true
permissions:
contents: read
packages: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push runner image
uses: docker/build-push-action@v6
with:
context: .
file: tools/truenas_github_runner/Dockerfile
push: true
tags: ghcr.io/${{ github.repository_owner }}/starpilot-truenas-runner:${{ inputs.image_tag }}
-175
View File
@@ -1,175 +0,0 @@
name: "raylib ui preview"
on:
push:
branches:
- master
pull_request_target:
types: [assigned, opened, synchronize, reopened, edited]
branches:
- 'master'
paths:
- 'selfdrive/assets/**'
- 'selfdrive/ui/**'
- 'system/ui/**'
workflow_dispatch:
env:
UI_JOB_NAME: "Create raylib UI Report"
REPORT_NAME: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
SHA: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.sha || github.event.pull_request.head.sha }}
BRANCH_NAME: "openpilot/pr-${{ github.event.number }}-raylib-ui"
jobs:
preview:
if: github.repository == 'commaai/openpilot'
name: preview
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
pull-requests: write
actions: read
steps:
- name: Waiting for ui generation to start
run: sleep 30
- name: Waiting for ui generation to end
uses: lewagon/wait-on-check-action@v1.3.4
with:
ref: ${{ env.SHA }}
check-name: ${{ env.UI_JOB_NAME }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
allowed-conclusions: success
wait-interval: 20
- name: Getting workflow run ID
id: get_run_id
run: |
echo "run_id=$(curl https://api.github.com/repos/${{ github.repository }}/commits/${{ env.SHA }}/check-runs | jq -r '.check_runs[] | select(.name == "${{ env.UI_JOB_NAME }}") | .html_url | capture("(?<number>[0-9]+)") | .number')" >> $GITHUB_OUTPUT
- name: Getting proposed ui
id: download-artifact
uses: dawidd6/action-download-artifact@v6
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
run_id: ${{ steps.get_run_id.outputs.run_id }}
search_artifacts: true
name: raylib-report-1-${{ env.REPORT_NAME }}
path: ${{ github.workspace }}/pr_ui
- name: Getting master ui
uses: actions/checkout@v4
with:
repository: commaai/ci-artifacts
ssh-key: ${{ secrets.CI_ARTIFACTS_DEPLOY_KEY }}
path: ${{ github.workspace }}/master_ui_raylib
ref: openpilot_master_ui_raylib
- name: Saving new master ui
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
working-directory: ${{ github.workspace }}/master_ui_raylib
run: |
git checkout --orphan=new_master_ui_raylib
git rm -rf *
git branch -D openpilot_master_ui_raylib
git branch -m openpilot_master_ui_raylib
git config user.name "GitHub Actions Bot"
git config user.email "<>"
mv ${{ github.workspace }}/pr_ui/*.png .
git add .
git commit -m "raylib screenshots for commit ${{ env.SHA }}"
git push origin openpilot_master_ui_raylib --force
- name: Finding diff
if: github.event_name == 'pull_request_target'
id: find_diff
run: >-
sudo apt-get update && sudo apt-get install -y imagemagick
scenes=$(find ${{ github.workspace }}/pr_ui/*.png -type f -printf "%f\n" | cut -d '.' -f 1 | grep -v 'pair_device')
A=($scenes)
DIFF=""
TABLE="<details><summary>All Screenshots</summary>"
TABLE="${TABLE}<table>"
for ((i=0; i<${#A[*]}; i=i+1));
do
# Check if the master file exists
if [ ! -f "${{ github.workspace }}/master_ui_raylib/${A[$i]}.png" ]; then
# This is a new file in PR UI that doesn't exist in master
DIFF="${DIFF}<details open>"
DIFF="${DIFF}<summary>${A[$i]} : \$\${\\color{cyan}\\text{NEW}}\$\$</summary>"
DIFF="${DIFF}<table>"
DIFF="${DIFF}<tr>"
DIFF="${DIFF} <td> <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
DIFF="${DIFF}</tr>"
DIFF="${DIFF}</table>"
DIFF="${DIFF}</details>"
elif ! compare -fuzz 2% -highlight-color DeepSkyBlue1 -lowlight-color Black -compose Src ${{ github.workspace }}/master_ui_raylib/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png; then
convert ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png -transparent black mask.png
composite mask.png ${{ github.workspace }}/master_ui_raylib/${A[$i]}.png composite_diff.png
convert -delay 100 ${{ github.workspace }}/master_ui_raylib/${A[$i]}.png composite_diff.png -loop 0 ${{ github.workspace }}/pr_ui/${A[$i]}_diff.gif
mv ${{ github.workspace }}/master_ui_raylib/${A[$i]}.png ${{ github.workspace }}/pr_ui/${A[$i]}_master_ref.png
DIFF="${DIFF}<details open>"
DIFF="${DIFF}<summary>${A[$i]} : \$\${\\color{red}\\text{DIFFERENT}}\$\$</summary>"
DIFF="${DIFF}<table>"
DIFF="${DIFF}<tr>"
DIFF="${DIFF} <td> master <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_master_ref.png\"> </td>"
DIFF="${DIFF} <td> proposed <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
DIFF="${DIFF}</tr>"
DIFF="${DIFF}<tr>"
DIFF="${DIFF} <td> diff <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.png\"> </td>"
DIFF="${DIFF} <td> composite diff <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}_diff.gif\"> </td>"
DIFF="${DIFF}</tr>"
DIFF="${DIFF}</table>"
DIFF="${DIFF}</details>"
else
rm -f ${{ github.workspace }}/pr_ui/${A[$i]}_diff.png
fi
INDEX=$(($i % 2))
if [[ $INDEX -eq 0 ]]; then
TABLE="${TABLE}<tr>"
fi
TABLE="${TABLE} <td> <img src=\"https://raw.githubusercontent.com/commaai/ci-artifacts/${{ env.BRANCH_NAME }}/${A[$i]}.png\"> </td>"
if [[ $INDEX -eq 1 || $(($i + 1)) -eq ${#A[*]} ]]; then
TABLE="${TABLE}</tr>"
fi
done
TABLE="${TABLE}</table></details>"
echo "DIFF=$DIFF$TABLE" >> "$GITHUB_OUTPUT"
- name: Saving proposed ui
if: github.event_name == 'pull_request_target'
working-directory: ${{ github.workspace }}/master_ui_raylib
run: |
git config user.name "GitHub Actions Bot"
git config user.email "<>"
git checkout --orphan=${{ env.BRANCH_NAME }}
git rm -rf *
mv ${{ github.workspace }}/pr_ui/* .
git add .
git commit -m "raylib screenshots for PR #${{ github.event.number }}"
git push origin ${{ env.BRANCH_NAME }} --force
- name: Comment Screenshots on PR
if: github.event_name == 'pull_request_target'
uses: thollander/actions-comment-pull-request@v2
with:
message: |
<!-- _(run_id_screenshots_raylib **${{ github.run_id }}**)_ -->
## raylib UI Preview
${{ steps.find_diff.outputs.DIFF }}
comment_tag: run_id_screenshots_raylib
pr_number: ${{ github.event.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-42
View File
@@ -1,42 +0,0 @@
name: release
on:
schedule:
- cron: '0 9 * * *'
workflow_dispatch:
jobs:
build_masterci:
name: build master-ci
env:
ImageOS: ubuntu24
container:
image: ghcr.io/commaai/openpilot-base:latest
runs-on: ubuntu-latest
if: github.repository == 'commaai/openpilot'
permissions:
checks: read
contents: write
steps:
- name: Install wait-on-check-action dependencies
run: |
sudo apt-get update
sudo apt-get install -y libyaml-dev
- name: Wait for green check mark
if: ${{ github.event_name == 'schedule' }}
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc
with:
ref: master
wait-interval: 30
running-workflow-name: 'build master-ci'
repo-token: ${{ secrets.GITHUB_TOKEN }}
check-regexp: ^((?!.*(build prebuilt).*).)*$
- uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Pull LFS
run: |
git config --global --add safe.directory '*'
git lfs pull
- name: Push master-ci
run: BRANCH=__nightly release/build_stripped.sh
-72
View File
@@ -1,72 +0,0 @@
name: repo maintenance
on:
schedule:
- cron: "0 14 * * 1" # every Monday at 2am UTC (6am PST)
workflow_dispatch:
env:
BASE_IMAGE: openpilot-base
BUILD: selfdrive/test/docker_build.sh base
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
jobs:
update_translations:
runs-on: ubuntu-latest
if: github.repository == 'commaai/openpilot'
steps:
- uses: actions/checkout@v4
- uses: ./.github/workflows/setup-with-retry
- name: Update translations
run: |
${{ env.RUN }} "python3 selfdrive/ui/update_translations.py --vanish"
- name: Create Pull Request
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
with:
author: Vehicle Researcher <user@comma.ai>
commit-message: "Update translations"
title: "[bot] Update translations"
body: "Automatic PR from repo-maintenance -> update_translations"
branch: "update-translations"
base: "master"
delete-branch: true
labels: bot
package_updates:
name: package_updates
runs-on: ubuntu-latest
container:
image: ghcr.io/commaai/openpilot-base:latest
if: github.repository == 'commaai/openpilot'
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: uv lock
run: |
python3 -m ensurepip --upgrade
pip3 install uv
uv lock --upgrade
- name: bump submodules
run: |
git config --global --add safe.directory '*'
git submodule update --remote
git add .
- name: update car docs
run: |
export PYTHONPATH="$PWD"
scons -j$(nproc) --minimal opendbc_repo
python selfdrive/car/docs.py
git add docs/CARS.md
- name: Create Pull Request
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
with:
author: Vehicle Researcher <user@comma.ai>
token: ${{ secrets.ACTIONS_CREATE_PR_PAT }}
commit-message: Update Python packages
title: '[bot] Update Python packages'
branch: auto-package-updates
base: master
delete-branch: true
body: 'Automatic PR from repo-maintenance -> package_updates'
labels: bot
-71
View File
@@ -1,71 +0,0 @@
name: Schedule StarPilot Update
on:
workflow_dispatch:
inputs:
scheduled_date:
description: "Enter the date to update the \"StarPilot\" branch (YYYY-MM-DD)"
required: true
env:
GIT_EMAIL: "91348155+FrogAi@users.noreply.github.com"
GIT_NAME: "James"
TARGET_BRANCH: "StarPilot-Staging"
UPDATE_FILE_PATH: ".github/update_date"
jobs:
schedule_update:
runs-on: ubuntu-latest
steps:
- name: Checkout Target Branch
uses: actions/checkout@v4
with:
ref: ${{ env.TARGET_BRANCH }}
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
fetch-depth: 3
- name: Configure Git Identity
run: |
git config --global user.name "$GIT_NAME"
git config --global user.email "$GIT_EMAIL"
- name: Write Schedule Date
env:
SCHEDULED_DATE: ${{ github.event.inputs.scheduled_date }}
run: |
echo "$SCHEDULED_DATE" > "$UPDATE_FILE_PATH"
git add "$UPDATE_FILE_PATH"
- name: Get Target Commit Data
id: get_target
run: |
TARGET_COMMIT=$(git rev-parse HEAD~1)
AUTHOR_DATE=$(git show -s --format=%aD "$TARGET_COMMIT")
COMMITTER_DATE=$(git show -s --format=%cD "$TARGET_COMMIT")
echo "AUTHOR_DATE=$AUTHOR_DATE" >> "$GITHUB_ENV"
echo "COMMITTER_DATE=$COMMITTER_DATE" >> "$GITHUB_ENV"
echo "TARGET_COMMIT=$TARGET_COMMIT" >> "$GITHUB_ENV"
- name: Create Fixup Commit
id: fixup_commit
run: |
if git diff --cached --quiet; then
echo "No changes detected."
echo "has_changes=false" >> "$GITHUB_OUTPUT"
else
echo "Changes detected. Creating fixup commit."
git commit --fixup="$TARGET_COMMIT"
echo "has_changes=true" >> "$GITHUB_OUTPUT"
fi
- name: Autosquash and Restore Timestamps
if: steps.fixup_commit.outputs.has_changes == 'true'
run: |
GIT_SEQUENCE_EDITOR=: git rebase --autosquash -i HEAD~3
git rebase --exec "GIT_COMMITTER_DATE='$COMMITTER_DATE' git commit --amend --no-edit --date='$AUTHOR_DATE'" HEAD~2
- name: Push Changes
if: steps.fixup_commit.outputs.has_changes == 'true'
run: |
git push origin "$TARGET_BRANCH" --force-with-lease
-52
View File
@@ -1,52 +0,0 @@
name: stale
on:
schedule:
- cron: '30 1 * * *'
workflow_dispatch:
env:
DAYS_BEFORE_PR_CLOSE: 7
DAYS_BEFORE_PR_STALE: 24
DAYS_BEFORE_PR_STALE_DRAFT: 30
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
exempt-all-milestones: true
# pull request config
stale-pr-message: 'This PR has had no activity for ${{ env.DAYS_BEFORE_PR_STALE }} days. It will be automatically closed in ${{ env.DAYS_BEFORE_PR_CLOSE }} days if there is no activity.'
close-pr-message: 'This PR has been automatically closed due to inactivity. Feel free to re-open once activity resumes.'
stale-pr-label: stale
delete-branch: ${{ github.event.pull_request.head.repo.full_name == 'commaai/openpilot' }} # only delete branches on the main repo
exempt-pr-labels: "ignore stale,needs testing" # if wip or it needs testing from the community, don't mark as stale
days-before-pr-stale: ${{ env.DAYS_BEFORE_PR_STALE }}
days-before-pr-close: ${{ env.DAYS_BEFORE_PR_CLOSE }}
exempt-draft-pr: false
# issue config
days-before-issue-stale: -1 # ignore issues for now
# same as above, but give draft PRs more time
stale_drafts:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
exempt-all-milestones: true
# pull request config
stale-pr-message: 'This PR has had no activity for ${{ env.DAYS_BEFORE_PR_STALE_DRAFT }} days. It will be automatically closed in ${{ env.DAYS_BEFORE_PR_CLOSE }} days if there is no activity.'
close-pr-message: 'This PR has been automatically closed due to inactivity. Feel free to re-open once activity resumes.'
stale-pr-label: stale
delete-branch: ${{ github.event.pull_request.head.repo.full_name == 'commaai/openpilot' }} # only delete branches on the main repo
exempt-pr-labels: "ignore stale,needs testing" # if wip or it needs testing from the community, don't mark as stale
days-before-pr-stale: ${{ env.DAYS_BEFORE_PR_STALE_DRAFT }}
days-before-pr-close: ${{ env.DAYS_BEFORE_PR_CLOSE }}
exempt-draft-pr: true
# issue config
days-before-issue-stale: -1 # ignore issues for now
-294
View File
@@ -1,294 +0,0 @@
name: tests
on:
push:
branches:
- master
pull_request:
workflow_dispatch:
workflow_call:
inputs:
run_number:
default: '1'
required: true
type: string
concurrency:
group: tests-ci-run-${{ inputs.run_number }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
cancel-in-progress: true
env:
PYTHONWARNINGS: error
BASE_IMAGE: openpilot-base
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
BUILD: selfdrive/test/docker_build.sh base
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
PYTEST: pytest --continue-on-collection-errors --durations=0 -n logical
jobs:
build_release:
name: build release
runs-on: ${{
(github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|| fromJSON('["ubuntu-24.04"]') }}
env:
STRIPPED_DIR: /tmp/releasepilot
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Getting LFS files
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e
with:
timeout_minutes: 2
max_attempts: 3
command: git lfs pull
- name: Build devel
timeout-minutes: 1
run: TARGET_DIR=$STRIPPED_DIR release/build_stripped.sh
- uses: ./.github/workflows/setup-with-retry
- name: Build openpilot and run checks
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
run: |
cd $STRIPPED_DIR
${{ env.RUN }} "python3 system/manager/build.py"
- name: Run tests
timeout-minutes: 1
run: |
cd $STRIPPED_DIR
${{ env.RUN }} "release/check-dirty.sh"
- name: Check submodules
if: github.repository == 'commaai/openpilot'
timeout-minutes: 3
run: release/check-submodules.sh
build:
runs-on: ${{
(github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|| fromJSON('["ubuntu-24.04"]') }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Setup docker push
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
run: |
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
$DOCKER_LOGIN
- uses: ./.github/workflows/setup-with-retry
- uses: ./.github/workflows/compile-openpilot
timeout-minutes: 30
build_mac:
name: build macOS
if: false # tmp disable due to brew install not working
runs-on: ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-macos-8x14' || 'macos-latest' }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
- name: Homebrew cache
uses: ./.github/workflows/auto-cache
with:
path: ~/Library/Caches/Homebrew
key: brew-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
restore-keys: |
brew-macos-${{ env.CACHE_COMMIT_DATE }}
brew-macos
- name: Install dependencies
run: ./tools/mac_setup.sh
env:
PYTHONWARNINGS: default # package install has DeprecationWarnings
HOMEBREW_DISPLAY_INSTALL_TIMES: 1
- run: git lfs pull
- name: Getting scons cache
uses: ./.github/workflows/auto-cache
with:
path: /tmp/scons_cache
key: scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
restore-keys: |
scons-${{ runner.arch }}-macos-${{ env.CACHE_COMMIT_DATE }}
scons-${{ runner.arch }}-macos
- name: Building openpilot
run: . .venv/bin/activate && scons -j$(nproc)
static_analysis:
name: static analysis
runs-on: ${{
(github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|| fromJSON('["ubuntu-24.04"]') }}
env:
PYTHONWARNINGS: default
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
- name: Static analysis
timeout-minutes: 1
run: ${{ env.RUN }} "scripts/lint/lint.sh"
unit_tests:
name: unit tests
runs-on: ${{
(github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|| fromJSON('["ubuntu-24.04"]') }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
id: setup-step
- name: Build openpilot
run: ${{ env.RUN }} "scons -j$(nproc)"
- name: Run unit tests
timeout-minutes: ${{ contains(runner.name, 'nsc') && ((steps.setup-step.outputs.duration < 18) && 1 || 2) || 20 }}
run: |
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
# Pre-compile Python bytecode so each pytest worker doesn't need to
$PYTEST --collect-only -m 'not slow' -qq && \
MAX_EXAMPLES=1 $PYTEST -m 'not slow' && \
chmod -R 777 /tmp/comma_download_cache"
process_replay:
name: process replay
runs-on: ${{
(github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|| fromJSON('["ubuntu-24.04"]') }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
id: setup-step
- name: Cache test routes
id: dependency-cache
uses: actions/cache@v4
with:
path: .ci_cache/comma_download_cache
key: proc-replay-${{ hashFiles('selfdrive/test/process_replay/ref_commit', 'selfdrive/test/process_replay/test_processes.py') }}
- name: Build openpilot
run: |
${{ env.RUN }} "scons -j$(nproc)"
- name: Run replay
timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.dependency-cache.outputs.cache-hit == 'true') && ((steps.setup-step.outputs.duration < 18) && 1 || 2) || 20 }}
run: |
${{ env.RUN }} "selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
chmod -R 777 /tmp/comma_download_cache"
- name: Print diff
id: print-diff
if: always()
run: cat selfdrive/test/process_replay/diff.txt
- uses: actions/upload-artifact@v4
if: always()
continue-on-error: true
with:
name: process_replay_diff.txt
path: selfdrive/test/process_replay/diff.txt
- name: Upload reference logs
if: false # TODO: move this to github instead of azure
run: |
${{ env.RUN }} "unset PYTHONWARNINGS && AZURE_TOKEN='$AZURE_TOKEN' python3 selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only"
- name: Run regen
if: false
timeout-minutes: 4
run: |
${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \
chmod -R 777 /tmp/comma_download_cache"
simulator_driving:
name: simulator driving
runs-on: ${{
(github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|| fromJSON('["ubuntu-24.04"]') }}
if: false # FIXME: Started to timeout recently
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
id: setup-step
- name: Build openpilot
run: |
${{ env.RUN }} "scons -j$(nproc)"
- name: Driving test
timeout-minutes: ${{ (steps.setup-step.outputs.duration < 18) && 1 || 2 }}
run: |
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
source selfdrive/test/setup_vsound.sh && \
CI=1 pytest -s tools/sim/tests/test_metadrive_bridge.py"
create_raylib_ui_report:
name: Create raylib UI Report
runs-on: ${{
(github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|| fromJSON('["ubuntu-24.04"]') }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
- name: Build openpilot
run: ${{ env.RUN }} "scons -j$(nproc)"
- name: Create raylib UI Report
run: >
${{ env.RUN }} "PYTHONWARNINGS=ignore &&
source selfdrive/test/setup_xvfb.sh &&
python3 selfdrive/ui/tests/test_ui/raylib_screenshots.py"
- name: Upload Raylib UI Report
uses: actions/upload-artifact@v4
with:
name: raylib-report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
path: selfdrive/ui/tests/test_ui/raylib_report/screenshots
create_mici_raylib_ui_report:
name: Create mici raylib UI Report
runs-on: ${{
(github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))
&& fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]')
|| fromJSON('["ubuntu-24.04"]') }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
- name: Build openpilot
run: ${{ env.RUN }} "scons -j$(nproc)"
- name: Create mici raylib UI Report
run: >
${{ env.RUN }} "PYTHONWARNINGS=ignore &&
source selfdrive/test/setup_xvfb.sh &&
WINDOWED=1 python3 selfdrive/ui/tests/diff/replay.py"
- name: Upload Raylib UI Report
uses: actions/upload-artifact@v4
with:
name: mici-raylib-report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }}
path: selfdrive/ui/tests/diff/report
@@ -1,107 +0,0 @@
name: Update StarPilot Branch
on:
schedule:
- cron: "0 18 * * 6"
env:
BRANCH_STARPILOT: StarPilot
BRANCH_PREVIOUS: StarPilot-Previous
BRANCH_STAGING: StarPilot-Staging
GIT_EMAIL: "91348155+FrogAi@users.noreply.github.com"
GIT_NAME: "James"
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
TZ: America/Phoenix
UPDATE_FILE: .github/update_date
jobs:
check_update:
runs-on: ubuntu-latest
outputs:
update_due: ${{ steps.check_update.outputs.update_due }}
scheduled_date: ${{ steps.check_update.outputs.scheduled_date }}
steps:
- name: Check Update Status
id: check_update
env:
REPO_NAME: ${{ github.repository }}
run: |
URL="https://raw.githubusercontent.com/$REPO_NAME/$BRANCH_STAGING/$UPDATE_FILE"
STATUS=$(curl -o /dev/null -s -w "%{http_code}\n" "$URL")
if [ "$STATUS" != "200" ]; then
echo "update_due=false" >> "$GITHUB_OUTPUT"
exit 0
fi
SCHEDULED_DATE=$(curl -s "$URL")
CURRENT_DATE=$(TZ="$TZ" date +%F)
if [ "$SCHEDULED_DATE" == "$CURRENT_DATE" ]; then
echo "update_due=true" >> "$GITHUB_OUTPUT"
echo "scheduled_date=$SCHEDULED_DATE" >> "$GITHUB_OUTPUT"
else
echo "update_due=false" >> "$GITHUB_OUTPUT"
fi
update_branch:
needs: check_update
if: ${{ needs.check_update.outputs.update_due == 'true' }}
runs-on: ubuntu-latest
steps:
- name: Checkout Staging
uses: actions/checkout@v4
with:
ref: ${{ env.BRANCH_STAGING }}
fetch-depth: 0
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
- name: Configure Git Identity
run: |
git config --global user.name "$GIT_NAME"
git config --global user.email "$GIT_EMAIL"
- name: Update README and Cleanup
env:
SCHEDULED_DATE: ${{ needs.check_update.outputs.scheduled_date }}
run: |
DAY=$(TZ="$TZ" date +'%d' | sed 's/^0//')
case "$DAY" in
1|21|31) SUFFIX="st" ;;
2|22) SUFFIX="nd" ;;
3|23) SUFFIX="rd" ;;
*) SUFFIX="th" ;;
esac
MONTH=$(TZ="$TZ" date +'%B')
YEAR=$(TZ="$TZ" date +'%Y')
DATE_FMT="${MONTH} ${DAY}${SUFFIX}, ${YEAR}"
DATE_ESCAPED=$(printf '%s' "$DATE_FMT" | sed -E 's/ /%20/g; s/,/%2C/g')
sed -i -E "s|(Last%20Updated-)[^-)]*|\1${DATE_ESCAPED}|g" README.md
git rm -f "$UPDATE_FILE"
git add README.md
git commit -m "Updated README date to ${DATE_FMT}"
git reset --soft HEAD~2
ORIGINAL_MSG=$(git log -1 --pretty=%B HEAD)
COMMIT_PHX=$(TZ="$TZ" date -d "$SCHEDULED_DATE 12:00" +"%Y-%m-%dT%H:%M:%S %z")
GIT_COMMITTER_DATE="$COMMIT_PHX" GIT_AUTHOR_DATE="$COMMIT_PHX" git commit -m "$ORIGINAL_MSG"
- name: Wait Until Noon ${{ env.TZ }}
run: |
NOW=$(TZ="$TZ" date +%s)
TARGET=$(TZ="$TZ" date -d "12:00" +%s)
if [ "$NOW" -lt "$TARGET" ]; then
sleep $((TARGET - NOW))
fi
- name: Push and Sync Branches
run: |
git push origin "$BRANCH_STAGING" --force
git fetch origin "$BRANCH_STARPILOT:$BRANCH_STARPILOT"
git push origin "$BRANCH_STARPILOT:$BRANCH_PREVIOUS" --force
git push origin "$BRANCH_STAGING:$BRANCH_STARPILOT" --force
-95
View File
@@ -1,95 +0,0 @@
name: Update Tinygrad
on:
workflow_dispatch:
inputs:
runner:
description: "Select runner"
type: choice
options:
- c3
- c3x
default: "c3"
required: true
env:
GIT_EMAIL: "91348155+FrogAi@users.noreply.github.com"
GIT_NAME: "James"
GITLAB_REPO_DIR: "StarPilot-Resources"
GITLAB_URL: "gitlab.com/FrogAi/StarPilot-Resources.git"
OPENPILOT_DIR: "/data/openpilot"
jobs:
update_tinygrad:
runs-on: [self-hosted, "${{ inputs.runner }}"]
steps:
- name: Get Version
id: get_version
run: |
VERSION=$(grep -oP '^VERSION\s*=\s*"\K[^"]+' "$OPENPILOT_DIR/starpilot/assets/model_manager.py")
echo "VERSION=$VERSION"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Setup Workspace and Clone GitLab
id: setup
env:
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
run: |
WORK_DIR="$RUNNER_TEMP/starpilot_tinygrad"
rm -rf "$WORK_DIR" && mkdir -p "$WORK_DIR"
echo "work_dir=$WORK_DIR" >> "$GITHUB_OUTPUT"
cd "$WORK_DIR"
git clone --depth 1 --branch Tinygrad "https://oauth2:${GITLAB_TOKEN}@$GITLAB_URL"
- name: Create Tinygrad Archive
working-directory: ${{ env.OPENPILOT_DIR }}
env:
WORK_DIR: ${{ steps.setup.outputs.work_dir }}
VERSION: ${{ steps.get_version.outputs.version }}
run: |
set -euo pipefail
ARCHIVE_DEST="$WORK_DIR/$GITLAB_REPO_DIR"
ARCHIVE_NAME="Tinygrad_$VERSION.tar.gz"
DUMMY_DIR=$(mktemp -d)
touch "$DUMMY_DIR/SConscript"
tar -czf "$ARCHIVE_DEST/$ARCHIVE_NAME" \
--exclude="*.a" \
--exclude="*.o" \
--exclude="*.onnx" \
--exclude="*__pycache__*" \
--exclude="*tests*" \
--exclude="selfdrive/modeld/SConscript" \
selfdrive/modeld tinygrad_repo \
-C "$DUMMY_DIR" \
--transform 's|^SConscript$|selfdrive/modeld/SConscript|' \
SConscript
rm -rf "$DUMMY_DIR"
- name: Push Updated Tinygrad
working-directory: ${{ steps.setup.outputs.work_dir }}/${{ env.GITLAB_REPO_DIR }}
env:
VERSION: ${{ steps.get_version.outputs.version }}
run: |
git config user.name "$GIT_NAME"
git config user.email "$GIT_EMAIL"
git add Tinygrad_*.tar.gz
if git diff --staged --quiet; then
echo "No changes to commit."
else
git commit -m "Updated Tinygrad: $VERSION"
git push origin Tinygrad
fi
- name: Cleanup Temporary Files
if: always()
env:
WORK_DIR: ${{ steps.setup.outputs.work_dir }}
run: |
rm -rf "$WORK_DIR"
+2
View File
@@ -21,6 +21,7 @@ compiledmodels/
/docs_site/
*.mp4
!docs/assets/speed-limit-vision-demo*.mp4
*.dylib
*.DSYM
*.d
@@ -68,6 +69,7 @@ cppcheck_report.txt
comma*.sh
selfdrive/modeld/models/*.pkl
!selfdrive/modeld/models/driving_tinygrad.pkl
!selfdrive/modeld/models/driving_vision_tinygrad.pkl
!selfdrive/modeld/models/driving_policy_tinygrad.pkl
!selfdrive/modeld/models/driving_vision_metadata.pkl
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+11 -8
View File
@@ -1,14 +1,13 @@
# StarPilot
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/firestar5683/StarPilot)
[![Discord](https://img.shields.io/discord/1137853399715549214?label=Discord)](https://firestar.link/discord)
[![Discord](https://img.shields.io/discord/1387432184121393333?label=Discord)](https://firestar.link/discord)
[![Last Updated](https://img.shields.io/github/last-commit/firestar5683/StarPilot/StarPilot)](https://github.com/firestar5683/StarPilot)
[![Wiki](https://img.shields.io/badge/Wiki-StarPilot-blue?logo=wiki)](https://wiki.firestar.link)
**StarPilot** is a custom fork of [comma.ai's openpilot](https://comma.ai/openpilot),
an open source driver assistance system.
whoisdomi
Openpilot provides
* Automated Lane Centering
@@ -16,11 +15,11 @@ Openpilot provides
* Lane Change Assist
* Driver Monitoring *without wheel nags*
StarPilot adds support for many GM vehicles along with improved tuning,
especially for radar-less (camera only) vehicles.
StarPilot was formerly a GM targeted fork,
but [has expanded to offer Quality-Of-Life improvements for all](#features)!
StarPilot is built off of [StarPilot](https://github.com/FrogAi/StarPilot)
and supports the major features StarPilot offers.
StarPilot is built off of [FrogPilot](https://github.com/FrogAi/FrogPilot)
and supports the major features FrogPilot offers.
StarPilot has a vibrant, welcoming community [discord](https://firestar.link/discord).
Stop by to chat or ask questions!
@@ -33,9 +32,9 @@ installation guides, and software configuration.
## Features
* Full support for Comma C3, C3X, and C4
* C4 is currently in release testing. Join our fleet of C4 testers!
* Model switcher with all of comma's tinygrad driving models
* Special longitudinal planner tuning for VoACC (visual only, radar-less) vehicles
* Custom-tuned torque controllers for an expanding list of cars.
* Galaxy: StarPilot's portal to configure your comma device using your phone from anywhere.
Download models, change settings, update software, visualize live model outputs for tuning.
* Always On Lateral (full time steering assist)*
@@ -50,8 +49,9 @@ Download models, change settings, update software, visualize live model outputs
* ZSS support*
* High quality dashcam recordings*
* Enhanced tuning for CEM (dynamic experimental mode switching)
* And more!
\* [Inherited from StarPilot](https://github.com/FrogAi/StarPilot#openpilot-vs-starpilot)
\* [Inherited from FrogPilot](https://github.com/FrogAi/FrogPilot#openpilot-vs-frogpilot)
## GM-only Features
@@ -75,3 +75,6 @@ Download models, change settings, update software, visualize live model outputs
Uses your comma's sysroot/toolchain
* Toggle: "Use Precompiled Binaries" to allow switching between fast boot / editable builds
* Custom long maneuver tests, specifically designed for regen-only vehicles
## Third-Party Notices
* Portions of this software include modified versions of the Material Design Icons provided by Google under the Apache License 2.0. A copy of the license is included in the `LICENSE-MDI` file.
+17 -9
View File
@@ -153,7 +153,7 @@ lenv = {
}
# Allow callers to override cache/temp dirs used by subprocesses (e.g. tinygrad model compilation).
for key in ("HOME", "TMPDIR", "XDG_CACHE_HOME", "CACHEDB"):
for key in ("HOME", "TMPDIR", "XDG_CACHE_HOME", "CACHEDB", "PARAMS_ROOT"):
if key in os.environ:
lenv[key] = os.environ[key]
@@ -404,12 +404,22 @@ if arch == "larch64" and os.environ.get("SP_TICI_SYSROOT"):
qt_arm_moc = os.path.join(qt_tool_bin, "moc")
qt_arm_uic = os.path.join(qt_tool_bin, "uic")
qt_arm_rcc = os.path.join(qt_tool_bin, "rcc")
qt_host_bin = os.environ.get("SP_QT_HOST_BIN", "/usr/lib/qt5/bin")
qt_host_moc = os.environ.get("SP_QT_HOST_MOC", os.path.join(qt_host_bin, "moc"))
qt_host_uic = os.environ.get("SP_QT_HOST_UIC", os.path.join(qt_host_bin, "uic"))
qt_host_rcc = os.environ.get("SP_QT_HOST_RCC", "rcc")
if platform.machine() in ("aarch64", "arm64"):
if os.path.isfile(qt_arm_moc):
if "SP_QT_HOST_MOC" in os.environ:
qt_env['QT3_MOC'] = qt_host_moc
elif os.path.isfile(qt_arm_moc):
qt_env['QT3_MOC'] = qt_arm_moc
if os.path.isfile(qt_arm_uic):
if "SP_QT_HOST_UIC" in os.environ:
qt_env['QT3_UIC'] = qt_host_uic
elif os.path.isfile(qt_arm_uic):
qt_env['QT3_UIC'] = qt_arm_uic
if os.path.isfile(qt_arm_rcc):
if "SP_QT_HOST_RCC" in os.environ:
qt_env['SP_QT_RCC'] = qt_host_rcc
elif os.path.isfile(qt_arm_rcc):
qt_env['SP_QT_RCC'] = qt_arm_rcc
else:
qt_qemu = shutil.which("qemu-aarch64-static") or shutil.which("qemu-aarch64")
@@ -417,19 +427,17 @@ if arch == "larch64" and os.environ.get("SP_TICI_SYSROOT"):
if qt_qemu and os.path.isfile(qt_arm_moc):
qt_env['QT3_MOC'] = f"{qt_qemu} -L {qt_tool_root} {qt_arm_moc}"
else:
qt_host_bin = os.environ.get("SP_QT_HOST_BIN", "/usr/lib/qt5/bin")
qt_env['QT3_MOC'] = os.environ.get("SP_QT_HOST_MOC", os.path.join(qt_host_bin, "moc"))
qt_env['QT3_MOC'] = qt_host_moc
if qt_qemu and os.path.isfile(qt_arm_uic):
qt_env['QT3_UIC'] = f"{qt_qemu} -L {qt_tool_root} {qt_arm_uic}"
else:
qt_host_bin = os.environ.get("SP_QT_HOST_BIN", "/usr/lib/qt5/bin")
qt_env['QT3_UIC'] = os.environ.get("SP_QT_HOST_UIC", os.path.join(qt_host_bin, "uic"))
qt_env['QT3_UIC'] = qt_host_uic
if qt_qemu and os.path.isfile(qt_arm_rcc):
qt_env['SP_QT_RCC'] = f"{qt_qemu} -L {qt_tool_root} {qt_arm_rcc}"
else:
qt_env['SP_QT_RCC'] = os.environ.get("SP_QT_HOST_RCC", "rcc")
qt_env['SP_QT_RCC'] = qt_host_rcc
qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"]
qt_flags = [
+107 -1
View File
@@ -3,4 +3,110 @@
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec "${ROOT_DIR}/scripts/laptop_device_build.sh" build "$@"
original_args=("$@")
shortcut_targets=()
passthrough_args=()
shortcut_includes_panda=0
panda_generated_files=(
"panda/board/obj/gitversion.h"
"panda/board/obj/version"
)
add_panda_targets() {
local variants=(
panda
panda_h7
panda_remote
panda_h7_remote
panda_hkg_remote
panda_h7_hkg_remote
panda_can_ignition_only
panda_h7_can_ignition_only
panda_remote_can_ignition_only
panda_h7_remote_can_ignition_only
panda_hkg_remote_can_ignition_only
panda_h7_hkg_remote_can_ignition_only
panda_jungle_h7
body_h7
)
local variant
for variant in "${variants[@]}"; do
shortcut_targets+=("panda/board/obj/${variant}.bin.signed")
done
}
while [[ $# -gt 0 ]]; do
case "$1" in
--params|-params|-param)
shortcut_targets+=("common/params_pyx.so")
;;
--panda|-panda)
shortcut_includes_panda=1
add_panda_targets
;;
--ui|-ui)
shortcut_targets+=("selfdrive/ui/ui")
;;
--cereal|-cereal)
shortcut_targets+=(
"cereal/libcereal.a"
"cereal/libsocketmaster.a"
"cereal/messaging/bridge"
"cereal/services.h"
)
;;
*)
if [[ "$1" =~ ^[0-9]+$ ]]; then
passthrough_args+=("-j$1")
else
passthrough_args+=("$1")
fi
;;
esac
shift
done
if [[ "${#shortcut_targets[@]}" -gt 0 ]]; then
scons_args=("--no-scrub")
scons_args+=("${shortcut_targets[@]}")
if [[ "${#passthrough_args[@]}" -gt 0 ]]; then
scons_args+=("${passthrough_args[@]}")
fi
if [[ "${shortcut_includes_panda}" -eq 1 ]]; then
exec "${ROOT_DIR}/scripts/laptop_device_build.sh" scons "${scons_args[@]}"
fi
tmpdir="$(mktemp -d)"
for path in "${panda_generated_files[@]}"; do
if [[ -e "${ROOT_DIR}/${path}" ]]; then
cp -p "${ROOT_DIR}/${path}" "${tmpdir}/${path//\//__}"
else
touch "${tmpdir}/${path//\//__}.missing"
fi
done
if "${ROOT_DIR}/scripts/laptop_device_build.sh" scons "${scons_args[@]}"; then
status=0
else
status=$?
fi
for path in "${panda_generated_files[@]}"; do
if [[ -e "${tmpdir}/${path//\//__}.missing" ]]; then
rm -f "${ROOT_DIR}/${path}"
else
cp -p "${tmpdir}/${path//\//__}" "${ROOT_DIR}/${path}"
fi
done
rm -rf "${tmpdir}"
exit "${status}"
fi
if [[ "${#original_args[@]}" -gt 0 ]]; then
exec "${ROOT_DIR}/scripts/laptop_device_build.sh" build "${original_args[@]}"
fi
exec "${ROOT_DIR}/scripts/laptop_device_build.sh" build
+29 -2
View File
@@ -59,6 +59,8 @@ struct StarPilotCarParams @0xaedffd8f31e7b55d {
isHDA2 @4 :Bool;
openpilotLongitudinalControlDisabled @5 :Bool;
safetyConfigs @6 :List(SafetyConfig);
pcmCruiseSpeed @7 :Bool = true;
redneckCruiseAvailable @8 :Bool;
struct SafetyConfig {
safetyParam @0 :UInt16;
@@ -85,6 +87,17 @@ struct StarPilotCarState @0xf35cc4560bbf6ec2 {
modePressed @16 :Bool;
customPressed @17 :Bool;
alwaysOnLateralAllowed @18 :Bool;
dashboardStopSign @19 :UInt8; # 0 = no signal / platform doesn't publish
cancelPressed @20 :Bool;
cancelLongPressed @21 :Bool;
cancelVeryLongPressed @22 :Bool;
pedalMaxRegen @23 :Bool; # pedal at max regen, driver should use brake for more decel
pedalLongActive @24 :Bool; # Pre-AP pedal longitudinal mode is active (enableLongControl)
teslaCCEngaged @25 :Bool; # rising edge of stock Tesla CC engaging (no-pedal mode)
teslaCCDisengaged @26 :Bool; # falling edge of stock Tesla CC
teslaCCNotArmed @27 :Bool; # lateral engaged but DI_cruiseState != STANDBY/ENABLED
accelHardCruise @28 :Bool; # current/releasing accel cruise button came from GM hard-press signal
decelHardCruise @29 :Bool; # current/releasing decel cruise button came from GM hard-press signal
}
struct StarPilotDeviceState @0xda96579883444c35 {
@@ -102,7 +115,11 @@ struct StarPilotModelDataV2 @0x80ae746ee2596b11 {
}
}
struct StarPilotOnroadEvent @0xa5cd762cd951a455 {
struct StarPilotOnroadEvents @0xa5cd762cd951a455 {
events @0 :List(StarPilotOnroadEvent);
}
struct StarPilotOnroadEvent @0xe344718567f9ce71 {
name @0 :EventName;
enable @1 :Bool;
@@ -152,6 +169,14 @@ struct StarPilotOnroadEvent @0xa5cd762cd951a455 {
switchbackModeInactive @30;
lkasEnable @31;
lkasDisable @32;
lateralManeuver @33;
pedalCruiseEnabled @34;
pedalCruiseDisabled @35;
pedalMaxRegen @36;
teslaCCEngaged @37;
teslaCCDisengaged @38;
teslaCCNotArmed @39;
pedalNotCalibrated @40;
}
}
@@ -193,6 +218,7 @@ struct StarPilotPlan @0xf98d843bfd7004a3 {
weatherId @34 :Int16;
disableThrottle @35 :Bool;
trackingLead @36 :Bool;
stopSignConfirmed @37 :Bool;
}
struct StarPilotRadarState @0xb86e6369214c01c8 {
@@ -252,7 +278,8 @@ struct CustomReserved9 @0xa1680744031fdb2d {
wallTimeNanos @5 :UInt64;
}
struct CustomReserved10 @0xcb9fd56c7057593a {
struct StarPilotLateralManeuverPlanDEPRECATED @0xcb9fd56c7057593a {
desiredCurvature @0 :Float32; # 1/m
}
struct CustomReserved11 @0xc2243c65e0340384 {
Binary file not shown.
+125 -32
View File
@@ -68,12 +68,12 @@ struct OnroadEvent @0xc4fa6047f024e718 {
longitudinalManeuver @30;
steerTempUnavailableSilent @31;
resumeRequired @32;
preDriverDistracted @33;
promptDriverDistracted @34;
driverDistracted @35;
preDriverUnresponsive @36;
promptDriverUnresponsive @37;
driverUnresponsive @38;
driverDistracted1 @33;
driverDistracted2 @34;
driverDistracted3 @35;
driverUnresponsive1 @36;
driverUnresponsive2 @37;
driverUnresponsive3 @38;
belowSteerSpeed @39;
lowBattery @40;
accFaulted @41;
@@ -130,7 +130,6 @@ struct OnroadEvent @0xc4fa6047f024e718 {
userBookmark @95;
excessiveActuation @96;
audioFeedback @97;
lateralManeuver @98;
soundsUnavailableDEPRECATED @47;
}
@@ -826,13 +825,30 @@ struct SelfdriveState {
alertStatus @5 :AlertStatus;
alertSize @6 :AlertSize;
alertType @7 :Text;
alertSound @8 :Car.CarControl.HUDControl.AudibleAlert;
alertSound @13 :AudibleAlert;
alertHudVisual @12 :Car.CarControl.HUDControl.VisualAlert;
# configurable driving settings
experimentalMode @10 :Bool;
personality @11 :LongitudinalPersonality;
enum AudibleAlert {
none @0;
engage @1;
disengage @2;
refuse @3;
warningSoft @4;
warningImmediate @5;
prompt @6;
promptRepeat @7;
promptDistracted @8;
preAlert @9;
}
enum OpenpilotState @0xdbe58b96d2d1ac61 {
disabled @0;
preEnabled @1;
@@ -853,6 +869,10 @@ struct SelfdriveState {
mid @2;
full @3;
}
deprecated :group {
alertSound @8 :Car.CarControl.HUDControl.AudibleAlert;
}
}
struct ControlsState @0x97ff69c53601abf1 {
@@ -1088,7 +1108,7 @@ struct ModelDataV2 {
confidence @23: ConfidenceClass;
# Model perceived motion
temporalPose @21 :Pose;
temporalPoseDEPRECATED @21 :Pose;
# e2e lateral planner
action @26: Action;
@@ -1262,12 +1282,6 @@ struct LongitudinalPlan @0xe00b5b3eba12876c {
solverExecutionTime @35 :Float32;
# lead trajectories the MPC solved against (13 points at T_IDXS)
leadTrajectoryX0 @40 :List(Float32);
leadTrajectoryV0 @41 :List(Float32);
leadTrajectoryX1 @42 :List(Float32);
leadTrajectoryV1 @43 :List(Float32);
enum LongitudinalPlanSource {
cruise @0;
lead0 @1;
@@ -2172,14 +2186,13 @@ struct DriverStateV2 {
facePosition @2 :List(Float32);
facePositionStd @3 :List(Float32);
faceProb @4 :Float32;
eyesVisibleProb @14 :Float32;
eyesClosedProb @15 :Float32;
leftEyeProb @5 :Float32;
rightEyeProb @6 :Float32;
leftBlinkProb @7 :Float32;
rightBlinkProb @8 :Float32;
sunglassesProb @9 :Float32;
phoneProb @13 :Float32;
leftEyeProbDEPRECATED @5 :Float32;
rightEyeProbDEPRECATED @6 :Float32;
leftBlinkProbDEPRECATED @7 :Float32;
rightBlinkProbDEPRECATED @8 :Float32;
sunglassesProbDEPRECATED @9 :Float32;
sleepProb @14 :Float32;
notReadyProbDEPRECATED @12 :List(Float32);
occludedProbDEPRECATED @10 :Float32;
readyProbDEPRECATED @11 :List(Float32);
@@ -2221,7 +2234,7 @@ struct DriverStateDEPRECATED @0xb83c6cc593ed0a00 {
stdDEPRECATED @2 :Float32;
}
struct DriverMonitoringState @0xb83cda094a1da284 {
struct DriverMonitoringStateDEPRECATED @0xb83cda094a1da284 {
events @18 :List(OnroadEvent);
faceDetected @1 :Bool;
isDistracted @2 :Bool;
@@ -2239,12 +2252,91 @@ struct DriverMonitoringState @0xb83cda094a1da284 {
isActiveMode @16 :Bool;
isRHD @4 :Bool;
uncertainCount @19 :UInt32;
phoneProbOffset @20 :Float32;
phoneProbValidCount @21 :UInt32;
isPreviewDEPRECATED @15 :Bool;
rhdCheckedDEPRECATED @5 :Bool;
eventsDEPRECATED @0 :List(Car.OnroadEventDEPRECATED);
deprecated :group {
phoneProbOffset @20 :Float32;
phoneProbValidCount @21 :UInt32;
isPreview @15 :Bool;
rhdChecked @5 :Bool;
events @0 :List(Car.OnroadEventDEPRECATED);
}
}
struct DriverMonitoringState {
lockout @0 :Bool;
lockoutCount @15 :Int8;
lockoutMinutesRemaining @11 :Int8;
alert3Count @12 :Int8;
noResponseCount @13 :Int8;
noResponseForceDecel @14 :Bool;
alwaysOn @3 :Bool;
alwaysOnLockout @4 :Bool;
alertLevel @5 :AlertLevel;
activePolicy @6 :MonitoringPolicy;
isRHD @7 :Bool;
rhdCalibration @8 :CalibrationState;
visionPolicyState @9 :VisionPolicyState;
wheeltouchPolicyState @10 :WheeltouchPolicyState;
enum AlertLevel {
# ordinal must match the name to prevent bugs
# comparing against the raw ordinal value
none @0;
one @1;
two @2;
three @3;
}
enum MonitoringPolicy {
wheeltouch @0;
vision @1;
}
struct VisionPolicyState {
awarenessPercent @0 :Int8;
awarenessStep @1 :Float32;
isDistracted @2 :Bool;
distractedTypes @3 :DistractedTypes;
faceDetected @4 :Bool;
pose @5 :Pose;
wheeltouchFallbackPercent @6 :Int8;
uncertainOffroadAlertPercent @7 :Int8;
struct DistractedTypes {
pose @0: Bool;
eye @1: Bool;
phone @2: Bool;
}
struct Pose {
pitch @0 :Float32;
yaw @1 :Float32;
pitchCalib @2 :CalibrationState;
yawCalib @3 :CalibrationState;
calibrated @4 :Bool;
uncertainty @5 :Float32;
}
}
struct WheeltouchPolicyState {
awarenessPercent @0 :Int8;
awarenessStep @1 :Float32;
driverInteracting @2 :Bool;
}
struct CalibrationState {
calibratedPercent @0 :Int8;
offset @1 :Float32;
}
deprecated :group {
alertCountLockoutPercent @1 :Int8;
alertTimeLockoutPercent @2 :Int8;
}
}
struct Boot {
@@ -2565,7 +2657,7 @@ struct Event {
thumbnail @66: Thumbnail;
onroadEvents @134: List(OnroadEvent);
carParams @69: Car.CarParams;
driverMonitoringState @71: DriverMonitoringState;
driverMonitoringState @151 :DriverMonitoringState;
livePose @129 :LivePose;
modelV2 @75 :ModelDataV2;
drivingModelData @128 :DrivingModelData;
@@ -2614,8 +2706,8 @@ struct Event {
userBookmark @93 :UserBookmark;
bookmarkButton @148 :UserBookmark;
audioFeedback @149 :AudioFeedback;
lateralManeuverPlan @150 :LateralManeuverPlan;
lateralManeuverPlan @150 :LateralManeuverPlan;
# *********** debug ***********
testJoystick @52 :Joystick;
roadEncodeData @86 :EncodeData;
@@ -2644,12 +2736,12 @@ struct Event {
starpilotCarState @109 :Custom.StarPilotCarState;
starpilotDeviceState @110 :Custom.StarPilotDeviceState;
starpilotModelV2 @111 :Custom.StarPilotModelDataV2;
starpilotOnroadEvents @112 :List(Custom.StarPilotOnroadEvent);
starpilotOnroadEvents @112 :Custom.StarPilotOnroadEvents;
starpilotPlan @113 :Custom.StarPilotPlan;
starpilotRadarState @114 :Custom.StarPilotRadarState;
starpilotSelfdriveState @115 :Custom.StarPilotSelfdriveState;
customReserved9 @116 :Custom.CustomReserved9;
customReserved10 @136 :Custom.CustomReserved10;
starpilotLateralManeuverPlanDEPRECATED @136 :Custom.StarPilotLateralManeuverPlanDEPRECATED;
customReserved11 @137 :Custom.CustomReserved11;
customReserved12 @138 :Custom.CustomReserved12;
customReserved13 @139 :Custom.CustomReserved13;
@@ -2707,5 +2799,6 @@ struct Event {
gyroscope2DEPRECATED @100 :SensorEventData;
accelerometer2DEPRECATED @101 :SensorEventData;
temperatureSensor2DEPRECATED @123 :SensorEventData;
driverMonitoringStateDEPRECATED @71 :DriverMonitoringStateDEPRECATED;
}
}
+8
View File
@@ -268,6 +268,7 @@ class SubMaster:
class PubMaster:
def __init__(self, services: List[str]):
self.sock = {}
self._zmq_readers_settled = set()
for s in services:
self.sock[s] = pub_sock(s)
@@ -277,6 +278,13 @@ class PubMaster:
self.sock[s].send(dat)
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
if "ZMQ" in os.environ:
if s not in self._zmq_readers_settled:
time.sleep(min(timeout, 1.0))
self._zmq_readers_settled.add(s)
elif dt >= 0.05:
time.sleep(min(timeout, 1.0))
return True
for _ in range(int(timeout*(1./dt))):
if self.sock[s].all_readers_updated():
return True
Binary file not shown.
+69 -1
View File
@@ -1,5 +1,8 @@
#!/usr/bin/env python3
import io
import math
import os
import sys
from pathlib import Path
CHUNK_SIZE = 45 * 1024 * 1024 # 45MB, under GitHub's 50MB limit
@@ -13,9 +16,16 @@ def get_manifest_path(name):
return f"{name}.chunkmanifest"
def _chunk_paths(path, num_chunks):
return [get_manifest_path(path)] + [get_chunk_name(path, i, num_chunks) for i in range(num_chunks)]
def get_chunk_paths(path, file_size):
num_chunks = math.ceil(file_size / CHUNK_SIZE)
return [get_manifest_path(path)] + [get_chunk_name(path, i, num_chunks) for i in range(num_chunks)]
return _chunk_paths(path, num_chunks)
get_chunk_targets = get_chunk_paths
def chunk_file(path, targets):
@@ -31,6 +41,59 @@ def chunk_file(path, targets):
os.remove(path)
def get_existing_chunks(path):
if os.path.isfile(path):
return [path]
manifest_path = get_manifest_path(path)
if os.path.isfile(manifest_path):
num_chunks = int(Path(manifest_path).read_text().strip())
return _chunk_paths(path, num_chunks)
raise FileNotFoundError(path)
def file_chunked_exists(path) -> bool:
return os.path.isfile(path) or os.path.isfile(get_manifest_path(path))
class ChunkStream(io.RawIOBase):
def __init__(self, paths):
self._paths = iter(paths)
self._file = None
def readable(self):
return True
def readinto(self, buffer):
count = 0
view = memoryview(buffer)
while count < len(buffer):
if self._file is None:
path = next(self._paths, None)
if path is None:
break
self._file = open(path, "rb")
bytes_read = self._file.readinto(view[count:])
if not bytes_read:
self._file.close()
self._file = None
continue
count += bytes_read
return count
def close(self):
if self._file is not None:
self._file.close()
self._file = None
super().close()
def open_file_chunked(path):
chunks = get_existing_chunks(path)
if chunks and chunks[0] == get_manifest_path(path):
chunks = chunks[1:]
return io.BufferedReader(ChunkStream(chunks))
def read_file_chunked(path):
manifest_path = get_manifest_path(path)
if os.path.isfile(manifest_path):
@@ -39,3 +102,8 @@ def read_file_chunked(path):
if os.path.isfile(path):
return Path(path).read_bytes()
raise FileNotFoundError(path)
if __name__ == "__main__":
file_path = sys.argv[1]
chunk_file(file_path, get_chunk_targets(file_path, os.path.getsize(file_path)))
Binary file not shown.
+5 -1
View File
@@ -99,7 +99,7 @@ Params::Params(const std::string &path, bool memory) {
if (memory) {
params_folder = Path::shm_path() + "/params";
} else {
cache_path = "/cache/params" + params_prefix + "/";
cache_path = Path::params_cache() + params_prefix + "/";
params_folder = path;
}
params_path = ensure_params_path(params_prefix, params_folder);
@@ -309,6 +309,10 @@ int Params::getTuningLevel(const std::string &key) {
return keys[key].tuning_level;
}
ParamSettingsTier Params::getSettingsTier(const std::string &key) {
return keys[key].settings_tier;
}
std::optional<std::string> Params::getStockValue(const std::string &key) {
ParamKeyAttributes &attributes = keys[key];
if (attributes.stock_value) {
+10
View File
@@ -33,6 +33,11 @@ enum ParamKeyType {
BYTES = 6
};
enum ParamSettingsTier {
SETTINGS_SIMPLE = 0,
SETTINGS_ADVANCED = 1,
};
struct ParamKeyAttributes {
uint32_t flags;
ParamKeyType type;
@@ -42,6 +47,9 @@ struct ParamKeyAttributes {
std::optional<std::string> stock_value = std::nullopt;
int tuning_level = 0;
// Controls settings-page visibility only. It does not gate the param's runtime behavior.
ParamSettingsTier settings_tier = SETTINGS_ADVANCED;
};
class Params {
@@ -112,6 +120,8 @@ public:
int getTuningLevel(const std::string &key);
ParamSettingsTier getSettingsTier(const std::string &key);
std::optional<std::string> getStockValue(const std::string &key);
private:
+273 -58
View File
@@ -1,70 +1,285 @@
from openpilot.common.params_pyx import Params as _Params, ParamKeyFlag, ParamKeyType, UnknownKeyName
assert _Params
assert ParamKeyFlag
assert ParamKeyType
assert UnknownKeyName
from __future__ import annotations
from enum import IntEnum, IntFlag
from pathlib import Path
import tempfile
SETTINGS_SIMPLE = 0
SETTINGS_ADVANCED = 1
class Params(_Params):
def get(self, key, block=False, return_default=False, encoding=None, default=None):
try:
value = super().get(key, block=block, return_default=return_default)
except UnknownKeyName:
return default
if value is None:
return default
if encoding is not None and isinstance(value, bytes):
def _load_settings_tiers() -> dict[str, int]:
params_keys = Path(__file__).with_name("params_keys.h")
if not params_keys.exists():
return {}
tiers = {}
for line in params_keys.read_text(encoding="utf-8", errors="ignore").splitlines():
if not line.lstrip().startswith('{"'):
continue
parts = line.split('"')
if len(parts) >= 2:
tiers[parts[1]] = SETTINGS_SIMPLE if "SETTINGS_SIMPLE" in line else SETTINGS_ADVANCED
return tiers
_SETTINGS_TIERS = _load_settings_tiers()
try:
from openpilot.common.params_pyx import Params as _Params, ParamKeyFlag, ParamKeyType, UnknownKeyName
except Exception:
class UnknownKeyName(KeyError):
pass
class ParamKeyFlag(IntFlag):
PERSISTENT = 0x02
CLEAR_ON_MANAGER_START = 0x04
CLEAR_ON_ONROAD_TRANSITION = 0x08
CLEAR_ON_OFFROAD_TRANSITION = 0x10
DONT_LOG = 0x20
DEVELOPMENT_ONLY = 0x40
CLEAR_ON_IGNITION_ON = 0x80
ALL = 0xFFFFFFFF
class ParamKeyType(IntEnum):
STRING = 0
BOOL = 1
INT = 2
FLOAT = 3
TIME = 4
JSON = 5
BYTES = 6
def _load_key_types() -> dict[str, ParamKeyType]:
key_types: dict[str, ParamKeyType] = {}
params_keys = Path(__file__).with_name("params_keys.h")
if not params_keys.exists():
return key_types
for line in params_keys.read_text(encoding="utf-8", errors="ignore").splitlines():
if not line.lstrip().startswith('{"'):
continue
parts = line.split('"')
if len(parts) < 2:
continue
key = parts[1]
for type_name in ParamKeyType.__members__:
if f", {type_name}" in line:
key_types[key] = ParamKeyType[type_name]
break
else:
key_types[key] = ParamKeyType.STRING
return key_types
_KEY_TYPES = _load_key_types()
_PERSISTENT_STORE: dict[str, object] = {}
_MEMORY_STORE: dict[str, object] = {}
class Params:
def __init__(self, d: str | None = None, memory: bool = False, return_defaults: bool = False):
self.d = d if d is not None else ""
self.m = memory
self.return_defaults = return_defaults
self._store = _MEMORY_STORE if memory else _PERSISTENT_STORE
def __reduce__(self):
return type(self), (self.d, self.m, self.return_defaults)
def clear_all(self, tx_flag=ParamKeyFlag.ALL):
self._store.clear()
def check_key(self, key):
if isinstance(key, bytes):
key = key.decode("utf-8")
return str(key)
def _coerce_bool(self, value) -> bool:
if isinstance(value, bool):
return value
if isinstance(value, (int, float)):
return bool(value)
if isinstance(value, bytes):
return value == b"1"
if isinstance(value, str):
return value.strip().lower() not in ("", "0", "false", "none", "null")
return bool(value)
def _coerce_value(self, key: str, value):
value_type = self.get_type(key)
if value_type == ParamKeyType.BOOL:
return self._coerce_bool(value)
if value_type == ParamKeyType.INT:
return int(float(value))
if value_type == ParamKeyType.FLOAT:
return float(value)
if value_type == ParamKeyType.BYTES and isinstance(value, str):
return value.encode("utf-8")
return value
def get(self, key, block: bool = False, return_default: bool = False, encoding=None, default=None):
key = self.check_key(key)
value = self._store.get(key, default)
if value is None:
return default
if encoding is not None and isinstance(value, bytes):
try:
return value.decode(encoding)
except Exception:
return value.decode("utf-8", errors="replace")
return value
def get_bool(self, key, block: bool = False, default: bool = False):
value = self.get(key, block=block, return_default=True, default=default)
return self._coerce_bool(value)
def get_int(self, key, block: bool = False, return_default: bool = False, default: int = 0):
value = self.get(key, block=block, return_default=return_default, encoding="utf-8", default=default)
if value is None or value == "":
return default
try:
return value.decode(encoding)
except Exception:
return value.decode("utf-8", errors="replace")
return value
return int(float(value))
except (TypeError, ValueError):
return default
def get_bool(self, key, block=False, default=False):
try:
return super().get_bool(key, block=block)
except UnknownKeyName:
return bool(default)
def get_float(self, key, block: bool = False, return_default: bool = False, default: float = 0.0):
value = self.get(key, block=block, return_default=return_default, encoding="utf-8", default=default)
if value is None or value == "":
return default
try:
return float(value)
except (TypeError, ValueError):
return default
def get_int(self, key, block=False, return_default=False, default=0):
val = self.get(key, block=block, return_default=return_default, encoding="utf-8")
if val is None or val == "":
return default
try:
return int(float(val))
except ValueError:
return default
def put(self, key, dat):
key = self.check_key(key)
self._store[key] = self._coerce_value(key, dat)
def get_float(self, key, block=False, return_default=False, default=0.0):
val = self.get(key, block=block, return_default=return_default, encoding="utf-8")
if val is None or val == "":
return default
try:
return float(val)
except ValueError:
return default
def put_int(self, key, val):
t = self.get_type(key)
if t == ParamKeyType.FLOAT:
self.put(key, float(val))
elif t == ParamKeyType.INT:
self.put(key, int(val))
elif t == ParamKeyType.BOOL:
def put_bool(self, key, val: bool):
self.put(key, bool(val))
else:
self.put(key, str(int(val)))
def put_float(self, key, val):
t = self.get_type(key)
if t == ParamKeyType.FLOAT:
self.put(key, float(val))
elif t == ParamKeyType.INT:
def put_nonblocking(self, key, dat):
self.put(key, dat)
def put_bool_nonblocking(self, key, val: bool):
self.put_bool(key, val)
def put_int(self, key, val):
self.put(key, int(val))
elif t == ParamKeyType.BOOL:
self.put(key, bool(val))
else:
self.put(key, str(float(val)))
def put_float(self, key, val):
self.put(key, float(val))
def remove(self, key):
self._store.pop(self.check_key(key), None)
def get_param_path(self, key: str = ""):
base = Path(tempfile.gettempdir()) / ("params_memory" if self.m else "params")
base.mkdir(parents=True, exist_ok=True)
return str(base / key) if key else str(base)
def get_type(self, key):
return _KEY_TYPES.get(self.check_key(key), ParamKeyType.STRING)
def all_keys(self):
return list(_KEY_TYPES)
def get_default_value(self, key):
return None
def cpp2python(self, key, value):
return self._coerce_value(self.check_key(key), value)
def get_key_flag(self, key):
return ParamKeyFlag.PERSISTENT
def get_stock_value(self, key):
return None
def get_tuning_level(self, key):
return 0
def get_settings_tier(self, key):
return _SETTINGS_TIERS.get(self.check_key(key), SETTINGS_ADVANCED)
else:
assert _Params
assert ParamKeyFlag
assert ParamKeyType
assert UnknownKeyName
class Params(_Params):
def get_settings_tier(self, key):
try:
return super().get_settings_tier(key)
except AttributeError:
return _SETTINGS_TIERS.get(self.check_key(key), SETTINGS_ADVANCED)
def get(self, key, block=False, return_default=False, encoding=None, default=None):
try:
value = super().get(key, block=block, return_default=return_default)
except UnknownKeyName:
return default
if value is None:
return default
if encoding is not None and isinstance(value, bytes):
try:
return value.decode(encoding)
except Exception:
return value.decode("utf-8", errors="replace")
return value
def get_bool(self, key, block=False, default=False):
try:
result = super().get(key, block=block, return_default=True)
if result is None:
return bool(default)
return bool(result)
except UnknownKeyName:
return bool(default)
def get_int(self, key, block=False, return_default=False, default=0):
val = self.get(key, block=block, return_default=return_default, encoding="utf-8")
if val is None or val == "":
return default
try:
return int(float(val))
except ValueError:
return default
def get_float(self, key, block=False, return_default=False, default=0.0):
val = self.get(key, block=block, return_default=return_default, encoding="utf-8")
if val is None or val == "":
return default
try:
return float(val)
except ValueError:
return default
def put_int(self, key, val):
t = self.get_type(key)
if t == ParamKeyType.FLOAT:
self.put(key, float(val))
elif t == ParamKeyType.INT:
self.put(key, int(val))
elif t == ParamKeyType.BOOL:
self.put(key, bool(val))
else:
self.put(key, str(int(val)))
def put_float(self, key, val):
t = self.get_type(key)
if t == ParamKeyType.FLOAT:
self.put(key, float(val))
elif t == ParamKeyType.INT:
self.put(key, int(val))
elif t == ParamKeyType.BOOL:
self.put(key, bool(val))
else:
self.put(key, str(float(val)))
if __name__ == "__main__":
import sys
+303 -194
View File
@@ -8,10 +8,9 @@
inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"AccessToken", {CLEAR_ON_MANAGER_START | DONT_LOG, STRING}},
{"AdbEnabled", {PERSISTENT, BOOL}},
{"AlwaysAllowUploads", {PERSISTENT, BOOL, "0"}},
{"AlwaysAllowUploads", {PERSISTENT, BOOL, "0", std::nullopt, 0, SETTINGS_SIMPLE}},
{"AlwaysOnDM", {PERSISTENT, BOOL}},
{"ApiCache_Device", {PERSISTENT, STRING}},
{"ApiCache_FirehoseStats", {PERSISTENT, JSON}},
{"AssistNowToken", {PERSISTENT, STRING}},
{"AthenadPid", {PERSISTENT, INT}},
{"AthenadUploadQueue", {PERSISTENT, JSON}},
@@ -37,13 +36,19 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DoReboot", {CLEAR_ON_MANAGER_START, BOOL}},
{"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}},
{"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}},
{"DoUserReboot", {CLEAR_ON_MANAGER_START, BOOL}},
{"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}},
{"DriverLockoutCount", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, INT, "0"}},
{"EcuDisableFailed", {CLEAR_ON_MANAGER_START, BOOL}},
{"AlphaLongitudinalEnabled", {PERSISTENT, BOOL}},
{"ExperimentalLongitudinalEnabled", {PERSISTENT, BOOL}},
{"ExperimentalMode", {PERSISTENT, BOOL}},
{"ExperimentalModeConfirmed", {PERSISTENT, BOOL}},
{"PersistExperimentalState", {PERSISTENT, BOOL, "0", "0", 1}},
{"LongitudinalModelPreference", {PERSISTENT, INT, "0", "0", 1, SETTINGS_SIMPLE}},
{"LongitudinalModelPreferenceOverride", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, INT, "-1", "-1"}},
{"PersistChillState", {PERSISTENT, BOOL, "0", "0", 1}},
{"PersistExperimentalState", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"PersistedCCStatus", {PERSISTENT, INT, "0", "0"}},
{"PersistedCEStatus", {PERSISTENT, INT, "0", "0"}},
{"FirmwareQueryDone", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
{"ForcePowerDown", {PERSISTENT, BOOL}},
@@ -55,10 +60,14 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"GithubUsername", {PERSISTENT, STRING}},
{"GitRemote", {PERSISTENT, STRING}},
{"GsmApn", {PERSISTENT, STRING}},
{"GsmMetered", {PERSISTENT, BOOL, "1"}},
{"GsmMetered", {PERSISTENT, BOOL, "1", std::nullopt, 0, SETTINGS_SIMPLE}},
{"GsmRoaming", {PERSISTENT, BOOL}},
{"HardwareSerial", {PERSISTENT, STRING}},
{"HasAcceptedTerms", {PERSISTENT, STRING, "0"}},
{"HondaGasFactorParams", {PERSISTENT, FLOAT}},
{"HondaLateralPidKiScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"HondaLateralPidKpScale", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"HondaWindFactorParams", {PERSISTENT, FLOAT}},
{"InstallDate", {PERSISTENT, TIME}},
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsEngaged", {PERSISTENT, BOOL}},
@@ -66,7 +75,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"IsMetric", {PERSISTENT, BOOL}},
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsOnroad", {PERSISTENT, BOOL}},
{"IsRHD", {PERSISTENT, BOOL, std::nullopt, std::nullopt, 0, SETTINGS_SIMPLE}},
{"IsRhdDetected", {PERSISTENT, BOOL}},
{"IsRHDOverride", {PERSISTENT, BOOL}},
{"IsReleaseBranch", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
@@ -111,6 +122,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"PandaSomResetTriggered", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"PandaSignatures", {CLEAR_ON_MANAGER_START, BYTES}},
{"PrimeType", {PERSISTENT, INT}},
{"PriusClusterOffsetMigrated", {PERSISTENT, BOOL, "0", "0"}},
{"RecordAudio", {PERSISTENT, BOOL}},
{"RecordAudioFeedback", {PERSISTENT, BOOL, "0"}},
{"RecordFront", {PERSISTENT, BOOL}},
@@ -118,6 +130,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"SecOCKey", {PERSISTENT | DONT_LOG, STRING}},
{"ShowDebugInfo", {PERSISTENT, BOOL}},
{"ShowAllToggles", {PERSISTENT, BOOL, "0", "0", 3}},
{"TryRaylibUI", {PERSISTENT, BOOL, "1"}},
{"UseOldUI", {PERSISTENT, BOOL, "0", std::nullopt, 0, SETTINGS_SIMPLE}},
{"UsePrebuilt", {PERSISTENT, BOOL, "1"}},
{"RouteCount", {PERSISTENT, INT, "0"}},
{"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
@@ -138,26 +152,30 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"UpdaterLastFetchTime", {PERSISTENT, TIME}},
{"UptimeOffroad", {PERSISTENT, FLOAT, "0.0"}},
{"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
{"UsbGpuActive", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"UsbGpuCompiled", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"UsbGpuPresent", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
{"Version", {PERSISTENT, STRING}},
// StarPilot variables
{"AccelerationPath", {PERSISTENT, BOOL, "1", "0", 2}},
{"AccelerationProfile", {PERSISTENT, INT, "2", "0", 0}},
{"AccelerationPath", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"AccelerationProfile", {PERSISTENT, INT, "0", "0", 0, SETTINGS_SIMPLE}},
{"AdjacentLeadsUI", {PERSISTENT, BOOL, "1", "0", 3}},
{"AdjacentPath", {PERSISTENT, BOOL, "0", "0", 3}},
{"AdjacentPath", {PERSISTENT, BOOL, "0", "0", 3, SETTINGS_SIMPLE}},
{"AdjacentPathMetrics", {PERSISTENT, BOOL, "0", "0", 3}},
{"AdvancedCustomUI", {PERSISTENT, BOOL, "0", "0", 2}},
{"AdvancedCustomUI", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"AdvancedLateralTune", {PERSISTENT, BOOL, "1", "0", 2}},
{"AdvancedLongitudinalTune", {PERSISTENT, BOOL, "1", "0", 3}},
{"AggressiveFollow", {PERSISTENT, FLOAT, "1.25", "1.25", 2}},
{"AggressiveFollowHigh", {PERSISTENT, FLOAT, "1.25", "1.25", 2}},
{"AggressiveFollowHigh", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"AggressiveJerkAcceleration", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"AggressiveJerkDanger", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"AggressiveJerkDeceleration", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"AggressiveJerkSpeed", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"AggressiveJerkSpeedDecrease", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"AlertVolumeControl", {PERSISTENT, BOOL, "0", "0", 2}},
{"AlwaysOnLateral", {PERSISTENT, BOOL, "1", "0", 0}},
{"AlertVolumeControl", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"AllowImpossibleAcceleration", {PERSISTENT, BOOL, "0", "0", 3}},
{"AlwaysOnLateral", {PERSISTENT, BOOL, "1", "0", 0, SETTINGS_SIMPLE}},
{"AlwaysOnLateralLKAS", {PERSISTENT, BOOL, "1", "0", 2}},
{"ApiCache_DriveStats", {PERSISTENT, JSON, "{}", "{}"}},
{"AutomaticallyDownloadModels", {PERSISTENT, BOOL, "1", "0", 1}},
@@ -165,45 +183,55 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"AvailableModelNames", {PERSISTENT, STRING, "", "", 1}},
{"AvailableModelSeries", {PERSISTENT, STRING, "", "", 1}},
{"AvailableModels", {PERSISTENT, STRING, "", "", 1}},
{"AvailableModelArtifactFormats", {PERSISTENT, STRING, "", "", 1}},
{"BlacklistedModels", {PERSISTENT, STRING, "", "", 2}},
{"BootLogo", {PERSISTENT, STRING, "starpilot", "stock", 0}},
{"BuildMetadata", {PERSISTENT, STRING, "", "", 0}},
{"BlindSpotMetrics", {PERSISTENT, BOOL, "1", "0", 3}},
{"BlindSpotPath", {PERSISTENT, BOOL, "1", "0", 1}},
{"BelowSteerSpeedVolume", {PERSISTENT, INT, "101", "101", 2}},
{"BlindSpotPath", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"BelowSteerSpeedVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"BorderMetrics", {PERSISTENT, BOOL, "0", "0", 3}},
{"BorderWidth", {PERSISTENT, FLOAT, "100.0", "100.0", 2}},
{"BorderWidth", {PERSISTENT, FLOAT, "100.0", "100.0", 2, SETTINGS_SIMPLE}},
{"CalibratedLateralAcceleration", {PERSISTENT, FLOAT, "2.0", "2.0", 2}},
{"CalibrationProgress", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"CameraView", {PERSISTENT, INT, "3", "0", 2}},
{"CameraOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"CameraView", {PERSISTENT, INT, "3", "0", 2, SETTINGS_SIMPLE}},
{"CancelDownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DisableWideRoad", {PERSISTENT, BOOL, "0", "0", 3}},
{"CancelModelDownload", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"CancelThemeDownload", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"CarMake", {PERSISTENT, STRING, "mock", "mock", 0}},
{"CarModel", {PERSISTENT, STRING, "MOCK", "MOCK", 0}},
{"CarMake", {PERSISTENT, STRING, "mock", "mock", 0, SETTINGS_SIMPLE}},
{"CarModel", {PERSISTENT, STRING, "MOCK", "MOCK", 0, SETTINGS_SIMPLE}},
{"CarModelName", {PERSISTENT, STRING, "", "", 0}},
{"CECurves", {PERSISTENT, BOOL, "0", "0", 1}},
{"CECurves", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"CECurvesLead", {PERSISTENT, BOOL, "0", "0", 1}},
{"CELead", {PERSISTENT, BOOL, "1", "0", 1}},
{"CEModelStopTime", {PERSISTENT, FLOAT, "7.0", "0.0", 2}},
{"CELead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CEModelStopTime", {PERSISTENT, FLOAT, "7.0", "0.0", 2, SETTINGS_SIMPLE}},
{"CESignalLaneDetection", {PERSISTENT, BOOL, "1", "0", 2}},
{"CESignalSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1}},
{"CESpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"CESpeedLead", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"CESignalSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CESpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"CESpeedLead", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"CCMLead", {PERSISTENT, BOOL, "1", "0", 1}},
{"CCMLaunchAssist", {PERSISTENT, BOOL, "0", "0", 1}},
{"CCMSetSpeedMargin", {PERSISTENT, FLOAT, "3.0", "0.0", 1}},
{"CCMSpeed", {PERSISTENT, FLOAT, "45.0", "0.0", 1}},
{"CCMSpeedLead", {PERSISTENT, FLOAT, "35.0", "0.0", 1}},
{"CCStatus", {CLEAR_ON_OFFROAD_TRANSITION, INT, "0", "0"}},
{"CEStatus", {CLEAR_ON_OFFROAD_TRANSITION, INT, "0", "0"}},
{"CEStopLights", {PERSISTENT, BOOL, "1", "0", 1}},
{"CEStoppedLead", {PERSISTENT, BOOL, "1", "0", 1}},
{"ClusterOffset", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"ColorScheme", {PERSISTENT, STRING, "frog", "stock", 0}},
{"CEStopLights", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CEStoppedLead", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"ClusterOffset", {PERSISTENT, FLOAT, "1.0", "1.0", 2, SETTINGS_SIMPLE}},
{"ColorScheme", {PERSISTENT, STRING, "stock", "stock", 0}},
{"ColorToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"BootLogoToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"Compass", {PERSISTENT, BOOL, "0", "0", 1}},
{"Compass", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"CommunityFavorites", {PERSISTENT, STRING, "", "", 1}},
{"ConditionalExperimental", {PERSISTENT, BOOL, "1", "0", 1}},
{"ConditionalChill", {PERSISTENT, BOOL, "0", "0", 1}},
{"ConditionalExperimental", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CurvatureData", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1}},
{"CustomAlerts", {PERSISTENT, BOOL, "0", "0", 0}},
{"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"CustomAlerts", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"CustomAccelProfile", {PERSISTENT, BOOL, "0", "0", 3}},
{"CustomAccelProfileInitialized", {PERSISTENT, BOOL, "0", "0", 3}},
{"CustomAccelProfile0MPH", {PERSISTENT, FLOAT, "3.0", "3.0", 3}},
@@ -213,17 +241,20 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CustomAccelProfile45MPH", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"CustomAccelProfile56MPH", {PERSISTENT, FLOAT, "0.8", "0.8", 3}},
{"CustomAccelProfile89MPH", {PERSISTENT, FLOAT, "0.6", "0.6", 3}},
{"CustomCruise", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"CustomCruiseLong", {PERSISTENT, FLOAT, "5.0", "5.0", 2}},
{"CustomCruise", {PERSISTENT, FLOAT, "1.0", "1.0", 2, SETTINGS_SIMPLE}},
{"CustomCruiseLong", {PERSISTENT, FLOAT, "5.0", "5.0", 2, SETTINGS_SIMPLE}},
{"CustomPersonalities", {PERSISTENT, BOOL, "0", "0", 2}},
{"CancelButtonControl", {PERSISTENT, INT, "1", "0", 2, SETTINGS_SIMPLE}},
{"CancelButtonControlsMigrated", {PERSISTENT, BOOL, "0", "0"}},
{"AOLLKASMigratedToButtonControl", {PERSISTENT, BOOL, "0", "0"}},
{"TrafficPersonalityProfile", {PERSISTENT, BOOL, "1", "1", 2}},
{"AggressivePersonalityProfile", {PERSISTENT, BOOL, "1", "1", 2}},
{"StandardPersonalityProfile", {PERSISTENT, BOOL, "1", "1", 2}},
{"RelaxedPersonalityProfile", {PERSISTENT, BOOL, "1", "1", 2}},
{"CustomThemes", {PERSISTENT, BOOL, "1", "0", 0}},
{"CustomUI", {PERSISTENT, BOOL, "1", "0", 1}},
{"CustomThemes", {PERSISTENT, BOOL, "0", "0", 0}},
{"CustomUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"DebugMode", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
{"DecelerationProfile", {PERSISTENT, INT, "1", "0", 2}},
{"DecelerationProfile", {PERSISTENT, INT, "1", "0", 2, SETTINGS_SIMPLE}},
{"DeveloperMetrics", {PERSISTENT, BOOL, "1", "0", 3}},
{"DeveloperSidebar", {PERSISTENT, BOOL, "1", "0", 3}},
{"DeveloperSidebarMetric1", {PERSISTENT, INT, "1", "0", 3}},
@@ -234,14 +265,15 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DeveloperSidebarMetric6", {PERSISTENT, INT, "6", "0", 3}},
{"DeveloperSidebarMetric7", {PERSISTENT, INT, "7", "0", 3}},
{"DeveloperUI", {PERSISTENT, BOOL, "0", "0", 3}},
{"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}},
{"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1}},
{"DeviceShutdown", {PERSISTENT, INT, "9", "33", 1}},
{"DisableOnroadUploads", {PERSISTENT, BOOL, "0", "0", 2}},
{"DisableOpenpilotLongitudinal", {PERSISTENT, BOOL, "0", "0", 0}},
{"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"DeviceShutdown", {PERSISTENT, INT, "9", "33", 1, SETTINGS_SIMPLE}},
{"DisableOnroadUploads", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"DisableOpenpilotLongitudinal", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"DiscordUsername", {PERSISTENT, STRING, "", "", 0}},
{"DisengageVolume", {PERSISTENT, INT, "101", "101", 2}},
{"DistanceButtonControl", {PERSISTENT, INT, "1", "0", 2}},
{"DisengageVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"DistanceButtonControl", {PERSISTENT, INT, "1", "0", 2, SETTINGS_SIMPLE}},
{"DistanceIconPack", {PERSISTENT, STRING, "stock", "stock", 0}},
{"DistanceIconToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"DownloadableBootLogos", {PERSISTENT, STRING, "", ""}},
@@ -253,104 +285,147 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DownloadableWheels", {PERSISTENT, STRING, "", ""}},
{"DownloadAllModels", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DriverCamera", {PERSISTENT, BOOL, "0", "0", 1}},
{"DriverCamera", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"Model", {PERSISTENT, STRING, "sc2", "sc2", 1}},
{"ModelVersion", {PERSISTENT, STRING, "v11", "v11", 1}},
{"DrivingModel", {PERSISTENT, STRING, "sc2", "sc2", 1}},
{"DrivingModelName", {PERSISTENT, STRING, "South Carolina", "South Carolina", 1}},
{"DrivingModelVersion", {PERSISTENT, STRING, "v11", "v11", 1}},
{"DynamicPathWidth", {PERSISTENT, BOOL, "0", "0", 2}},
{"DynamicPedalsOnUI", {PERSISTENT, BOOL, "1", "0", 1}},
{"EngageVolume", {PERSISTENT, INT, "101", "101", 2}},
{"DynamicPathWidth", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"DynamicPedalsOnUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"EngageVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"EVTuning", {PERSISTENT, BOOL, "0", "0", 3}},
{"Fahrenheit", {PERSISTENT, BOOL, "0", "0", 3}},
{"FlashPanda", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"GMDashSpoofOffsets", {PERSISTENT, BOOL, "0", "0", 2}},
{"GMPedalLongitudinal", {PERSISTENT, BOOL, "1", "1", 2}},
{"LongPitch", {PERSISTENT, BOOL, "1", "0", 2}},
{"RemoteStartBootsComma", {PERSISTENT, BOOL, "0", "0"}},
{"RemapCancelToDistance", {PERSISTENT, BOOL, "0", "0"}},
{"GMDashSpoofOffsets", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"GMPedalLongitudinal", {PERSISTENT, BOOL, "1", "1", 2, SETTINGS_SIMPLE}},
{"HKGRemoteStartBootsComma", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"IgnoreIgnitionLine", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"LongPitch", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"RemoteStartBootsComma", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"RemapCancelToDistance", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"NAPAdaptiveAccel", {PERSISTENT, BOOL, "1", "1", 0, SETTINGS_SIMPLE}},
{"NAPFollowDistance", {PERSISTENT, INT, "4", "4"}},
{"NAPForcePreAP", {PERSISTENT, BOOL, "0", "0"}},
{"NAPPedalEnabled", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"NAPPedalCanBus", {PERSISTENT, INT, "2", "2", 0, SETTINGS_SIMPLE}},
{"NAPPedalCalibDone", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"NAPPedalCalibMin", {PERSISTENT, FLOAT, "-3.0", "-3.0"}},
{"NAPPedalCalibMax", {PERSISTENT, FLOAT, "99.6", "99.6"}},
{"NAPPedalCalibFactor", {PERSISTENT, FLOAT, "1.0", "1.0", 0, SETTINGS_SIMPLE}},
{"NAPPedalCalibZero", {PERSISTENT, FLOAT, "0.0", "0.0", 0, SETTINGS_SIMPLE}},
{"NAPPedalProfile", {PERSISTENT, INT, "4", "4"}},
{"NAPRadarBehindNosecone", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"NAPRadarEnabled", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"NAPRadarOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 0, SETTINGS_SIMPLE}},
{"ForceAutoTune", {PERSISTENT, BOOL, "0", "0", 3}},
{"ForceAutoTuneOff", {PERSISTENT, BOOL, "1", "0", 2}},
{"ForceFingerprint", {PERSISTENT, BOOL, "0", "0", 2}},
{"ForceFingerprint", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"ForceOffroad", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"ForceOnroad", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"ForceStops", {PERSISTENT, BOOL, "0", "0", 2}},
{"ForceStandstill", {PERSISTENT, BOOL, "0", "0", 2}},
{"ForceStops", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"ForceStopDistanceOffset", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ForceStandstill", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"ForceTorqueController", {PERSISTENT, BOOL, "0", "0", 3}},
{"FPSCounter", {PERSISTENT, BOOL, "1", "0", 3}},
{"FLMActiveOverrides", {PERSISTENT, JSON, "{}", "{}", 2}},
{"FLMActiveProfileId", {PERSISTENT, STRING, "", "", 2}},
{"FLMTrialBaseline", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"FLMTrialApplied", {PERSISTENT, BOOL, "0", "0", 2}},
{"FPSCounter", {PERSISTENT, BOOL, "0", "0", 3}},
{"GalaxyDashboardStats", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"StarPilotApiToken", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"StarPilotCarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES, "", ""}},
{"StarPilotCarParamsPersistent", {PERSISTENT, BYTES, "", ""}},
{"StarPilotDongleId", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"StarPilotFavoriteSlots", {PERSISTENT, JSON, "[]", "[]", 1}},
{"StarPilotStats", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"StarPilotTogglesUpdated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"FrogsGoMoosTweak", {PERSISTENT, BOOL, "1", "0", 2}},
{"GoatScream", {PERSISTENT, BOOL, "0", "0", 1}},
{"GoatScreamCriticalAlerts", {PERSISTENT, BOOL, "0", "0", 1}},
{"GreenLightAlert", {PERSISTENT, BOOL, "0", "0", 0}},
{"HideAlerts", {PERSISTENT, BOOL, "0", "0", 2}},
{"GoatScream", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"GoatScreamCriticalAlerts", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"GreenLightAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"HideAlerts", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HideChangingLanesBanner", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HideDistanceProfileBanner", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HideTurningBanner", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HideDMIcon", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HideLeadMarker", {PERSISTENT, BOOL, "0", "0", 2}},
{"HideMaxSpeed", {PERSISTENT, BOOL, "0", "0", 2}},
{"HideSpeed", {PERSISTENT, BOOL, "0", "0", 2}},
{"HideSpeedLimit", {PERSISTENT, BOOL, "0", "0", 2}},
{"HigherBitrate", {PERSISTENT, BOOL, "0", "0", 2}},
{"HolidayThemes", {PERSISTENT, BOOL, "1", "0", 0}},
{"HumanAcceleration", {PERSISTENT, BOOL, "0", "0", 2}},
{"HumanFollowing", {PERSISTENT, BOOL, "0", "0", 2}},
{"CoastUpToLeads", {PERSISTENT, BOOL, "1", "1", 2}},
{"HumanLaneChanges", {PERSISTENT, BOOL, "0", "0", 2}},
{"IconPack", {PERSISTENT, STRING, "frog-animated", "stock", 0}},
{"HideMaxSpeed", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HideSpeed", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HideSpeedLimit", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HideSteeringWheel", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HigherBitrate", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"HolidayThemes", {PERSISTENT, BOOL, "1", "0", 0, SETTINGS_SIMPLE}},
{"HumanLaneChanges", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"IconPack", {PERSISTENT, STRING, "stock", "stock", 0}},
{"IconToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"IncreasedStoppedDistance", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"IncreasedStoppedDistanceLowVisibility", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"IncreasedStoppedDistanceRain", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"IncreasedStoppedDistanceRainStorm", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"IncreasedStoppedDistanceSnow", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"IncreaseFollowingLowVisibility", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"IncreaseFollowingRain", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"IncreaseFollowingRainStorm", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"IncreaseFollowingSnow", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"IncreaseThermalLimits", {PERSISTENT, BOOL, "0", "0", 2}},
{"IncreasedStoppedDistance", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"IncreasedStoppedDistanceLowVisibility", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"IncreasedStoppedDistanceRain", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"IncreasedStoppedDistanceRainStorm", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"IncreasedStoppedDistanceSnow", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"RedneckCruise", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"IncreaseFollowingLowVisibility", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"IncreaseFollowingRain", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"IncreaseFollowingRainStorm", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"IncreaseFollowingSnow", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"IncreaseThermalLimits", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"IssueReported", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
{"KonikDongleId", {PERSISTENT, STRING, "", "", 0}},
{"KonikMinutes", {PERSISTENT, INT, "0", "0", 0}},
{"LaneChanges", {PERSISTENT, BOOL, "1", "1", 0}},
{"LaneChangeSmoothing", {PERSISTENT, INT, "10", "10", 1}},
{"LaneChangeTime", {PERSISTENT, FLOAT, "1.0", "0.0", 1}},
{"LaneDetectionWidth", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"LaneLinesColor", {PERSISTENT, STRING, "", "", 2}},
{"LaneLinesWidth", {PERSISTENT, FLOAT, "4.0", "2.0", 2}},
{"LaneCentering", {PERSISTENT, BOOL, "0", "0", 2}},
{"LaneCenteringE2EAuthority", {PERSISTENT, FLOAT, "1.0", "1.0", 3}},
{"LaneCenterOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"LaneChanges", {PERSISTENT, BOOL, "1", "1", 0, SETTINGS_SIMPLE}},
{"LaneChangeSmoothing", {PERSISTENT, INT, "5", "10", 1, SETTINGS_SIMPLE}},
{"LaneChangeTime", {PERSISTENT, FLOAT, "1.0", "0.0", 1, SETTINGS_SIMPLE}},
{"LaneDetectionWidth", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"LaneLinesColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
{"LaneLinesWidth", {PERSISTENT, FLOAT, "4.0", "2.0", 2, SETTINGS_SIMPLE}},
{"LastMapsUpdate", {PERSISTENT, STRING, "", ""}},
{"LateralTune", {PERSISTENT, BOOL, "1", "0", 1}},
{"LeadDepartingAlert", {PERSISTENT, BOOL, "0", "0", 0}},
{"LeadDepartingAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"LeadDetectionThreshold", {PERSISTENT, INT, "35", "50", 3}},
{"LeadIndicator", {PERSISTENT, BOOL, "1", "1", 2}},
{"LeadIndicator", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"LeadInfo", {PERSISTENT, BOOL, "1", "0", 3}},
{"LKASButtonControl", {PERSISTENT, INT, "5", "0", 2}},
{"LKASButtonControl", {PERSISTENT, INT, "5", "0", 2, SETTINGS_SIMPLE}},
{"LockDoors", {PERSISTENT, BOOL, "1", "0", 0}},
{"LockDoorsTimer", {PERSISTENT, INT, "0", "0", 0}},
{"LongDistanceButtonControl", {PERSISTENT, INT, "5", "0", 2}},
{"LongModeButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"LongStarButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"LongCancelButtonControl", {PERSISTENT, INT, "5", "0", 2, SETTINGS_SIMPLE}},
{"LongDistanceButtonControl", {PERSISTENT, INT, "5", "0", 2, SETTINGS_SIMPLE}},
{"LongModeButtonControl", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"LongStarButtonControl", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"LongitudinalActuatorDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"LongitudinalActuatorDelayStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"LateralManeuverStatus", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}},
{"LongitudinalManeuverPaddleMode", {PERSISTENT, STRING, "auto", "auto"}},
{"LongitudinalManeuverStatus", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}},
{"LongitudinalTune", {PERSISTENT, BOOL, "1", "0", 0}},
{"LoudBlindspotAlert", {PERSISTENT, BOOL, "0", "0", 0}},
{"LowVoltageShutdown", {PERSISTENT, FLOAT, "11.8", "11.8", 3}},
{"LongitudinalTune", {PERSISTENT, BOOL, "1", "0", 0, SETTINGS_SIMPLE}},
{"LoudBlindspotAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"LoudBlindspotAlertWhenDisengaged", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"LowVoltageShutdown", {PERSISTENT, FLOAT, "11.8", "11.8", 3, SETTINGS_SIMPLE}},
{"MainCruiseButtonControl", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ManualUpdateInitiated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"AMapKey1", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"AMapKey2", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"ApiCache_NavDestinations", {PERSISTENT, JSON, "[]", "[]"}},
{"FavoriteDestinations", {PERSISTENT, JSON, "[]", "[]"}},
{"MapAcceleration", {PERSISTENT, BOOL, "0", "0", 1}},
{"MapboxPublicKey", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"MapBoxRequests", {PERSISTENT, JSON, "{}", "{}"}},
{"MapboxSecretKey", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"MapDeceleration", {PERSISTENT, BOOL, "0", "0", 1}},
{"MapdSettings", {PERSISTENT, JSON, "{}", "{}"}},
{"MapGears", {PERSISTENT, BOOL, "0", "0", 2}},
{"MapGears", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"MapsSelected", {PERSISTENT, STRING, "", "", 0}},
{"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
{"NavDesiresAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
{"NavLongitudinalAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
{"ClearNavOnOffroad", {PERSISTENT, BOOL, "1", "1", 2, SETTINGS_SIMPLE}},
{"ClearNavOnOffroadTimeoutMinutes", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"NavDestination", {PERSISTENT | CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"NavInstructionCollapsed", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
{"NavInstructionState", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}},
{"NextMapSpeedLimit", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
{"VisionSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
{"VisionSpeedLimitConfidence", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
@@ -359,27 +434,31 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"VisionSpeedLimitLastEvent", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"VisionSpeedLimitStatus", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"VisionSpeedLimitStream", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"VisionSpeedLimitSupportCount", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"VisionSpeedLimitSupportSpeed", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
{"MaxDesiredAcceleration", {PERSISTENT, FLOAT, "4.0", "2.0", 2}},
{"MinimumBackupSize", {PERSISTENT, INT, "0", "0"}},
{"MinimumLaneChangeSpeed", {PERSISTENT, FLOAT, "20.0", "20.0", 2}},
{"ModeButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"MinimumLaneChangeSpeed", {PERSISTENT, FLOAT, "20.0", "20.0", 2, SETTINGS_SIMPLE}},
{"ModeButtonControl", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ModelDownloadProgress", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"ModelDrivesAndScores", {PERSISTENT, JSON, "{}", "{}"}},
{"ModelReleasedDates", {PERSISTENT, STRING, "", "", 1}},
{"ModelRandomizer", {PERSISTENT, BOOL, "0", "0", 2}},
{"ModelSortMode", {PERSISTENT, STRING, "alphabetical", "alphabetical", 1}},
{"ModelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"ModelUI", {PERSISTENT, BOOL, "1", "0", 2}},
{"ModelUI", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"ModelVersions", {PERSISTENT, STRING, "", "", 1}},
{"NavigationUI", {PERSISTENT, BOOL, "1", "0", 1}},
{"ModelManifestVersion", {PERSISTENT, STRING, "", "", 1}},
{"NavigationUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"NNFF", {PERSISTENT, BOOL, "0", "0", 2}},
{"NNFFLite", {PERSISTENT, BOOL, "0", "0", 2}},
{"NostalgiaMode", {PERSISTENT, BOOL, "0", "0", 2}},
{"NostalgiaMode", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"NNFFModelName", {CLEAR_ON_MANAGER_START, STRING, "", "", 0}},
{"NoLogging", {PERSISTENT, BOOL, "0", "0", 2}},
{"NoUploads", {PERSISTENT, BOOL, "0", "0", 2}},
{"NudgelessLaneChange", {PERSISTENT, BOOL, "1", "0", 0}},
{"NumericalTemp", {PERSISTENT, BOOL, "1", "0", 3}},
{"NoLogging", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"NoUploads", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"NudgelessLaneChange", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"NudgelessLaneChangeOnlyWhenEngaged", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"NumericalTemp", {PERSISTENT, BOOL, "0", "0", 3}},
{"Offset1", {PERSISTENT, FLOAT, "5.0", "0.0", 0}},
{"Offset2", {PERSISTENT, FLOAT, "5.0", "0.0", 0}},
{"Offset3", {PERSISTENT, FLOAT, "5.0", "0.0", 0}},
@@ -387,102 +466,112 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"Offset5", {PERSISTENT, FLOAT, "10.0", "0.0", 0}},
{"Offset6", {PERSISTENT, FLOAT, "10.0", "0.0", 0}},
{"Offset7", {PERSISTENT, FLOAT, "10.0", "0.0", 0}},
{"OneLaneChange", {PERSISTENT, BOOL, "1", "0", 2}},
{"OnroadDistanceButton", {PERSISTENT, BOOL, "0", "0", 0}},
{"OneLaneChange", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"OnroadDistanceButton", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"OnroadDistanceButtonPressed", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"FavoriteVirtualAccelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"FavoriteVirtualDecelCruiseCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"WheelButtonBookmarkCounter", {CLEAR_ON_MANAGER_START, INT, "0", "0"}},
{"openpilotMinutes", {PERSISTENT, INT, "0", "0", 0}},
{"OverpassRequests", {PERSISTENT, JSON, "{}", "{}"}},
{"PathColor", {PERSISTENT, STRING, "", "", 2}},
{"PathEdgesColor", {PERSISTENT, STRING, "", "", 2}},
{"PathEdgeWidth", {PERSISTENT, FLOAT, "20.0", "0.0", 2}},
{"PathWidth", {PERSISTENT, FLOAT, "6.1", "5.9", 2}},
{"PauseAOLOnBrake", {PERSISTENT, BOOL, "0", "0", 1}},
{"PauseLateralOnSignal", {PERSISTENT, BOOL, "0", "0", 1}},
{"PauseLateralSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"PedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1}},
{"PondPaired", {PERSISTENT, BOOL, "0", "0", 0}},
{"PondUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
{"PathColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
{"PathEdgesColor", {PERSISTENT, STRING, "", "", 2, SETTINGS_SIMPLE}},
{"PathEdgeWidth", {PERSISTENT, FLOAT, "20.0", "0.0", 2, SETTINGS_SIMPLE}},
{"PathWidth", {PERSISTENT, FLOAT, "6.1", "5.9", 2, SETTINGS_SIMPLE}},
{"PauseAOLOnBrake", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"PauseLateralOnSignal", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"PauseLateralSpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"LateralResumeDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 1, SETTINGS_SIMPLE}},
{"PedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"GalaxyPaired", {PERSISTENT, BOOL, "0", "0", 0}},
{"GalaxyUploadPending", {PERSISTENT, BOOL, "0", "0", 0}},
{"PreferredSchedule", {PERSISTENT, INT, "2", "0", 0}},
{"PreviousSpeedLimit", {PERSISTENT, FLOAT, "0.0", "0.0"}},
{"PromptDistractedVolume", {PERSISTENT, INT, "101", "101", 2}},
{"PromptVolume", {PERSISTENT, INT, "101", "101", 2}},
{"QOLLateral", {PERSISTENT, BOOL, "1", "0", 1}},
{"QOLLongitudinal", {PERSISTENT, BOOL, "1", "0", 1}},
{"QOLVisuals", {PERSISTENT, BOOL, "1", "0", 0}},
{"PromptDistractedVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"PromptVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"QOLLateral", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"QOLLongitudinal", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"QOLVisuals", {PERSISTENT, BOOL, "1", "0", 0, SETTINGS_SIMPLE}},
{"RadarTakeoffs", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"RadarTracksUI", {PERSISTENT, BOOL, "0", "0", 3}},
{"RainbowPath", {PERSISTENT, BOOL, "0", "0", 1}},
{"RainbowPath", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"RandomEvents", {PERSISTENT, BOOL, "0", "0", 1}},
{"RandomThemes", {PERSISTENT, BOOL, "0", "0", 1}},
{"RandomThemesHolidays", {PERSISTENT, BOOL, "0", "0", 1}},
{"ReduceAccelerationLowVisibility", {PERSISTENT, INT, "0", "0", 2}},
{"ReduceAccelerationRain", {PERSISTENT, INT, "0", "0", 2}},
{"ReduceAccelerationRainStorm", {PERSISTENT, INT, "0", "0", 2}},
{"ReduceAccelerationSnow", {PERSISTENT, INT, "0", "0", 2}},
{"ReduceLateralAccelerationLowVisibility", {PERSISTENT, INT, "0", "0", 2}},
{"ReduceLateralAccelerationRain", {PERSISTENT, INT, "0", "0", 2}},
{"ReduceLateralAccelerationRainStorm", {PERSISTENT, INT, "0", "0", 2}},
{"ReduceLateralAccelerationSnow", {PERSISTENT, INT, "0", "0", 2}},
{"RefuseVolume", {PERSISTENT, INT, "101", "101", 2}},
{"RelaxedFollow", {PERSISTENT, FLOAT, "1.75", "1.75", 2}},
{"RelaxedFollowHigh", {PERSISTENT, FLOAT, "1.75", "1.75", 2}},
{"RelaxedJerkAcceleration", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"ReduceAccelerationLowVisibility", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ReduceAccelerationRain", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ReduceAccelerationRainStorm", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ReduceAccelerationSnow", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ReduceLateralAccelerationLowVisibility", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ReduceLateralAccelerationRain", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ReduceLateralAccelerationRainStorm", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"ReduceLateralAccelerationSnow", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"RefuseVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"RelaxedFollow", {PERSISTENT, FLOAT, "1.6", "1.6", 2}},
{"RelaxedFollowHigh", {PERSISTENT, FLOAT, "1.4", "1.4", 2}},
{"RelaxedJerkAcceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RelaxedJerkDanger", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RelaxedJerkDeceleration", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"RelaxedJerkSpeed", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"RelaxedJerkSpeedDecrease", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"RelaxedJerkDeceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RelaxedJerkSpeed", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"RelaxedJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"ReverseCruise", {PERSISTENT, BOOL, "0", "0", 1}},
{"RecoveryPower", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"RoadEdgesWidth", {PERSISTENT, FLOAT, "2.0", "2.0", 2}},
{"RoadNameUI", {PERSISTENT, BOOL, "1", "0", 1}},
{"RotatingWheel", {PERSISTENT, BOOL, "1", "0", 1}},
{"ScreenBrightness", {PERSISTENT, INT, "101", "101", 2}},
{"ScreenBrightnessOnroad", {PERSISTENT, INT, "101", "101", 2}},
{"ScreenManagement", {PERSISTENT, BOOL, "1", "0", 1}},
{"ScreenRecorder", {PERSISTENT, BOOL, "1", "0", 2}},
{"ScreenTimeout", {PERSISTENT, INT, "30", "30", 2}},
{"ScreenTimeoutOnroad", {PERSISTENT, INT, "30", "10", 2}},
{"RoadEdgesWidth", {PERSISTENT, FLOAT, "2.0", "2.0", 2, SETTINGS_SIMPLE}},
{"RoadNameUI", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"RotatingWheel", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"ScreenBrightness", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"ScreenBrightnessOnroad", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"ScreenManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"ScreenRecorder", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"ScreenTimeout", {PERSISTENT, INT, "30", "30", 2, SETTINGS_SIMPLE}},
{"ScreenTimeoutOnroad", {PERSISTENT, INT, "30", "10", 2, SETTINGS_SIMPLE}},
{"SecOCKeys", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"SafeMode", {PERSISTENT, BOOL, "0", "0", 0}},
{"SafeModeBackup", {PERSISTENT, JSON, "{}", "{}"}},
{"SetSpeedLimit", {PERSISTENT, BOOL, "0", "0", 1}},
{"SetSpeedOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"ShowCEMStatus", {PERSISTENT, BOOL, "1", "0", 2}},
{"ShowCPU", {PERSISTENT, BOOL, "1", "0", 3}},
{"ShowCSCStatus", {PERSISTENT, BOOL, "1", "0", 2}},
{"SetSpeedOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 2, SETTINGS_SIMPLE}},
{"ShowCEMStatus", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"ShowCCMStatus", {PERSISTENT, BOOL, "0", "0", 2}},
{"ShowCPU", {PERSISTENT, BOOL, "0", "0", 3}},
{"ShowCSCStatus", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"ShowGPU", {PERSISTENT, BOOL, "0", "0", 3}},
{"ShowIP", {PERSISTENT, BOOL, "0", "0", 3}},
{"ShowMemoryUsage", {PERSISTENT, BOOL, "1", "0", 3}},
{"ShowMemoryUsage", {PERSISTENT, BOOL, "0", "0", 3}},
{"ShowModeStatusBanner", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"ShownToggleDescriptions", {PERSISTENT, JSON, "{}", "{}"}},
{"ShowSLCOffset", {PERSISTENT, BOOL, "1", "0", 0}},
{"ShowSpeedLimits", {PERSISTENT, BOOL, "1", "0", 1}},
{"ShowSpeedLimits", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"ShowSteering", {PERSISTENT, BOOL, "0", "0", 3}},
{"ShowStoppingPoint", {PERSISTENT, BOOL, "1", "0", 3}},
{"ShowStoppingPointMetrics", {PERSISTENT, BOOL, "1", "0", 3}},
{"ShowStorageLeft", {PERSISTENT, BOOL, "0", "0", 3}},
{"ShowStorageUsed", {PERSISTENT, BOOL, "0", "0", 3}},
{"SidebarMetrics", {PERSISTENT, BOOL, "1", "0", 3}},
{"SidebarMetrics", {PERSISTENT, BOOL, "0", "0", 3}},
{"SidebarOpen", {PERSISTENT, BOOL, "0", "0", 0}},
{"SignalAnimation", {PERSISTENT, STRING, "frog", "stock", 0}},
{"SignalAnimation", {PERSISTENT, STRING, "stock", "stock", 0}},
{"SignalMetrics", {PERSISTENT, BOOL, "0", "0", 3}},
{"SignalToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"SimpleMode", {PERSISTENT, BOOL, "0", "0", 0}},
{"SimpleMode", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"SLCAbbreviatedSources", {PERSISTENT, BOOL, "0", "0", 3}},
{"SLCActiveSourcesOnly", {PERSISTENT, BOOL, "0", "0", 3}},
{"SLCConfirmation", {PERSISTENT, BOOL, "0", "0", 0}},
{"SLCConfirmationHigher", {PERSISTENT, BOOL, "0", "0", 0}},
{"SLCConfirmationLower", {PERSISTENT, BOOL, "0", "0", 0}},
{"SLCFallback", {PERSISTENT, INT, "2", "0", 1}},
{"SLCLookaheadHigher", {PERSISTENT, INT, "0", "0", 2}},
{"SLCLookaheadLower", {PERSISTENT, INT, "0", "0", 2}},
{"SLCMapboxFiller", {PERSISTENT, BOOL, "1", "0", 1}},
{"SLCMapboxFiller", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
{"SLCOverride", {PERSISTENT, INT, "1", "0", 1}},
{"SLCPriority", {PERSISTENT, STRING, "", "", 2}},
{"SLCPriority1", {PERSISTENT, STRING, "Map Data", "Map Data", 2}},
{"SLCPriority2", {PERSISTENT, STRING, "Dashboard", "Dashboard", 2}},
{"SNGHack", {PERSISTENT, BOOL, "1", "0", 2}},
{"SoundPack", {PERSISTENT, STRING, "frog", "stock", 0}},
{"SLCPriority1", {PERSISTENT, STRING, "Vision", "Map Data", 2}},
{"SLCPriority2", {PERSISTENT, STRING, "Map Data", "Dashboard", 2}},
{"SNGHack", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"SoundPack", {PERSISTENT, STRING, "stock", "stock", 0}},
{"SoundToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"SLCAdoptSpeedLimit", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"SLCForceCruiseSpeed", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
{"SpeedLimitAccepted", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"SpeedLimitChangedAlert", {PERSISTENT, BOOL, "0", "0", 0}},
{"SpeedLimitChangedAlert", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"SpeedLimitController", {PERSISTENT, BOOL, "0", "0", 0}},
{"SpeedLimitFiller", {PERSISTENT, BOOL, "0", "0", 0}},
{"SpeedLimits", {PERSISTENT | DONT_LOG, JSON, "[]", "[]"}},
@@ -490,22 +579,23 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"SpeedLimitSources", {PERSISTENT, BOOL, "0", "0", 3}},
{"VisionSpeedLimitAutoBookmark", {PERSISTENT, BOOL, "0", "0", 0}},
{"VisionSpeedLimitAutoPreserveSegment", {PERSISTENT, BOOL, "0", "0", 0}},
{"VisionSpeedLimitDetection", {PERSISTENT, BOOL, "0", "0", 0}},
{"VisionSpeedLimitDetection", {PERSISTENT, BOOL, "1", "0", 0}},
{"VisionSpeedLimitTrainingCollector", {PERSISTENT, BOOL, "1", "1", 0}},
{"StandardFollow", {PERSISTENT, FLOAT, "1.45", "1.45", 2}},
{"StandardFollowHigh", {PERSISTENT, FLOAT, "1.45", "1.45", 2}},
{"StandardJerkAcceleration", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"StandardFollowHigh", {PERSISTENT, FLOAT, "1.2", "1.2", 2}},
{"StandardJerkAcceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"StandardJerkDanger", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"StandardJerkDeceleration", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"StandardJerkSpeed", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"StandardJerkSpeedDecrease", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"StandbyMode", {PERSISTENT, BOOL, "0", "0", 1}},
{"StandardJerkDeceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"StandardJerkSpeed", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"StandardJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"StandbyMode", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"StartAccel", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"StartAccelStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"StartupMessageBottom", {PERSISTENT, STRING, "Human-tested, frog-approved 🐸", "Always keep hands on wheel and eyes on road", 0}},
{"StartupMessageTop", {PERSISTENT, STRING, "Hop in and buckle up!", "Be ready to take over at any time", 0}},
{"StaticPedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1}},
{"StartupMessageBottom", {PERSISTENT, STRING, "Always keep hands on wheel and eyes on road", "Always keep hands on wheel and eyes on road", 0}},
{"StartupMessageTop", {PERSISTENT, STRING, "Be ready to take over at any time", "Be ready to take over at any time", 0}},
{"StaticPedalsOnUI", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"SteerDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"SteerDelayModeMigrated", {PERSISTENT, BOOL}},
{"SteerDelayStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"SteerFriction", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"SteerFrictionStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
@@ -517,19 +607,21 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"SteerOffsetStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"SteerRatio", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"SteerRatioStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"EnableTorqueBarWidget", {PERSISTENT, BOOL, "1", "0", 0}},
{"StockConfidenceBallWidget", {PERSISTENT, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
{"StockDongleId", {PERSISTENT, STRING, "", ""}},
{"StopAccel", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"StopAccelStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"StoppedTimer", {PERSISTENT, BOOL, "0", "0", 1}},
{"StopDistance", {PERSISTENT, FLOAT, "6.0", "6.0", 2}},
{"StoppedTimer", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"StoppingDecelRate", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"StoppingDecelRateStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"StarButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"SwitchbackModeCooldown", {PERSISTENT, INT, "5", "0", 2}},
{"StarButtonControl", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"SwitchbackModeCooldown", {PERSISTENT, INT, "5", "0", 2, SETTINGS_SIMPLE}},
{"SwitchbackModeEnabled", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
{"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2}},
{"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2, SETTINGS_SIMPLE}},
{"SubaruSNGManualParkingBrake", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"TacoTune", {PERSISTENT, BOOL, "0", "0", 2}},
{"TacoTuneHacks", {PERSISTENT, BOOL, "0", "0", 2}},
{"TeslaCoopSteering", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"TestAlert", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"TetheringEnabled", {PERSISTENT, INT, "0", "0", 0}},
{"ThemeDownloadProgress", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
@@ -537,12 +629,13 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"Timezone", {PERSISTENT, STRING, "", ""}},
{"TinygradUpdateAvailable", {PERSISTENT, BOOL, "0", "0", 1}},
{"ToyotaDoors", {PERSISTENT, BOOL, "1", "0", 0}},
{"TrafficFollow", {PERSISTENT, FLOAT, "0.5", "0.5", 2}},
{"TrafficJerkAcceleration", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"TrailerLoad", {PERSISTENT, INT, "0", "0", 2}},
{"TrafficFollow", {PERSISTENT, FLOAT, "0.75", "0.75", 2}},
{"TrafficJerkAcceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"TrafficJerkDanger", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"TrafficJerkDeceleration", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"TrafficJerkSpeed", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"TrafficJerkSpeedDecrease", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
{"TrafficJerkDeceleration", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"TrafficJerkSpeed", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"TrafficJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"TruckTuning", {PERSISTENT, BOOL, "0", "0", 3}},
{"TuningLevel", {PERSISTENT, INT, "0", "0", 0}},
{"TuningLevelConfirmed", {PERSISTENT, BOOL, "0", "0", 0}},
@@ -554,24 +647,40 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"UpdateTinygrad", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"UpdateWheelImage", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"UseActiveTheme", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"UseKonikServer", {PERSISTENT, BOOL, "0", "0", 2}},
{"UseAutoSteerDelay", {PERSISTENT, BOOL, "1", "1", 3}},
{"UseKonikServer", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"UseSI", {PERSISTENT, BOOL, "1", "1", 3}},
{"UserFavorites", {PERSISTENT, STRING, "", "", 1}},
{"UseVienna", {PERSISTENT, BOOL, "0", "0", 1}},
{"UseVienna", {PERSISTENT, BOOL, "0", "0", 1, SETTINGS_SIMPLE}},
{"VASMAnnotationConfig", {PERSISTENT, JSON, "{}", "{}", 2}},
{"VASMConfidenceThreshold", {PERSISTENT, FLOAT, "0.85", "0.85", 2}},
{"VASMEnabled", {PERSISTENT, BOOL, "0", "0", 1}},
{"VASMLeftActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMLeftConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}},
{"VASMLastUpdateMonoTime", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMRightActive", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VASMRightConfidence", {CLEAR_ON_MANAGER_START, STRING, "0.0", "0.0", 2}},
{"VASMSmoothSeconds", {PERSISTENT, FLOAT, "0.2", "0.2", 2}},
{"VASMTimestampEof", {CLEAR_ON_MANAGER_START, STRING, "0", "0", 2}},
{"VEgoStarting", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VEgoStartingStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VEgoStopping", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VEgoStoppingStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VeryLongDistanceButtonControl", {PERSISTENT, INT, "6", "0", 2}},
{"VeryLongModeButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"VeryLongStarButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"VoltSNG", {PERSISTENT, BOOL, "0", "0", 2}},
{"WarningImmediateVolume", {PERSISTENT, INT, "101", "101", 2}},
{"WarningSoftVolume", {PERSISTENT, INT, "101", "101", 2}},
{"WeatherPresets", {PERSISTENT, BOOL, "0", "0", 2}},
{"VeryLongCancelButtonControl", {PERSISTENT, INT, "6", "0", 2, SETTINGS_SIMPLE}},
{"VeryLongDistanceButtonControl", {PERSISTENT, INT, "6", "0", 2, SETTINGS_SIMPLE}},
{"VeryLongModeButtonControl", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"VeryLongStarButtonControl", {PERSISTENT, INT, "0", "0", 2, SETTINGS_SIMPLE}},
{"VoltSNG", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"JeepBrakeHold", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"GMAutoHold", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"VoltOnePedalMode", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"ToyotaAutoHold", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"WarningImmediateVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"WarningSoftVolume", {PERSISTENT, INT, "101", "101", 2, SETTINGS_SIMPLE}},
{"WeatherPresets", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"WeatherToken", {PERSISTENT | DONT_LOG, STRING, "", "", 2}},
{"WheelControls", {PERSISTENT, STRING, "", "", 2}},
{"WheelIcon", {PERSISTENT, STRING, "frog", "stock", 0}},
{"WheelSpeed", {PERSISTENT, BOOL, "0", "0", 2}},
{"WheelIcon", {PERSISTENT, STRING, "stock", "stock", 0}},
{"WheelSpeed", {PERSISTENT, BOOL, "0", "0", 2, SETTINGS_SIMPLE}},
{"WheelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
};
+1104 -855
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -32,6 +32,10 @@ cdef extern from "common/params.h":
JSON
BYTES
cdef enum ParamSettingsTier:
SETTINGS_SIMPLE
SETTINGS_ADVANCED
cdef cppclass c_Params "Params":
c_Params(string, bool) except + nogil
string get(string, bool) nogil
@@ -55,6 +59,8 @@ cdef extern from "common/params.h":
int getTuningLevel(string) nogil
ParamSettingsTier getSettingsTier(string) nogil
PYTHON_2_CPP = {
(str, STRING): lambda v: v,
(builtins.bool, BOOL): lambda v: "1" if v else "0",
@@ -255,3 +261,6 @@ cdef class Params:
cdef string k = self.check_key(key)
cdef optional[int] level = self.p.getTuningLevel(k)
return level.value() if level.has_value() else 0
def get_settings_tier(self, key):
return self.p.getSettingsTier(self.check_key(key))
Binary file not shown.
+34
View File
@@ -0,0 +1,34 @@
from pathlib import Path
from openpilot.common import file_chunker
def test_chunked_stream_round_trip(tmp_path, monkeypatch):
monkeypatch.setattr(file_chunker, "CHUNK_SIZE", 7)
path = tmp_path / "artifact.pkl"
payload = b"a model artifact spanning several chunks"
path.write_bytes(payload)
targets = file_chunker.get_chunk_targets(path, len(payload))
file_chunker.chunk_file(path, targets)
assert file_chunker.file_chunked_exists(path)
assert file_chunker.read_file_chunked(path) == payload
with file_chunker.open_file_chunked(path) as stream:
assert stream.read(9) + stream.read() == payload
def test_unchunked_stream_does_not_materialize_file(tmp_path, monkeypatch):
path = tmp_path / "fat.onnx"
payload = b"large model read through bounded buffers"
path.write_bytes(payload)
original_read_bytes = Path.read_bytes
def reject_whole_file_read(candidate):
if candidate == path:
raise AssertionError("streaming must not call Path.read_bytes()")
return original_read_bytes(candidate)
monkeypatch.setattr(Path, "read_bytes", reject_whole_file_read)
with file_chunker.open_file_chunked(path) as stream:
assert stream.read() == payload
+10
View File
@@ -25,3 +25,13 @@ TEST_CASE("params_nonblocking_put") {
REQUIRE(p.get(name) == "1");
}
}
TEST_CASE("settings_tier_is_independent_from_tuning_level") {
Params params;
REQUIRE(params.getSettingsTier("AlwaysOnLateral") == SETTINGS_SIMPLE);
REQUIRE(params.getTuningLevel("AlwaysOnLateral") == 0);
REQUIRE(params.getSettingsTier("HumanLaneChanges") == SETTINGS_SIMPLE);
REQUIRE(params.getTuningLevel("HumanLaneChanges") == 2);
REQUIRE(params.getSettingsTier("AdvancedLateralTune") == SETTINGS_ADVANCED);
}
+4 -7
View File
@@ -50,11 +50,8 @@ class TestParams:
assert self.params.get("CarParams", block=True) == b"test"
def test_params_unknown_key_fails(self):
with pytest.raises(UnknownKeyName):
self.params.get("swag")
with pytest.raises(UnknownKeyName):
self.params.get_bool("swag")
assert self.params.get("swag") is None
assert not self.params.get_bool("swag")
with pytest.raises(UnknownKeyName):
self.params.put("swag", "abc")
@@ -133,8 +130,8 @@ class TestParams:
def test_params_get_type(self):
# json
self.params.put("ApiCache_FirehoseStats", {"a": 0})
assert self.params.get("ApiCache_FirehoseStats") == {"a": 0}
self.params.put("ApiCache_DriveStats", {"a": 0})
assert self.params.get("ApiCache_DriveStats") == {"a": 0}
# int
self.params.put("BootCount", 1441)
+54 -2
View File
@@ -1,8 +1,49 @@
import contextlib
import gc
import os
import platform
import sys
from pathlib import Path
import pytest
try:
int(os.environ.get("DEBUG", "0"))
except ValueError:
os.environ["DEBUG"] = "0"
if platform.system() == "Darwin":
os.environ["SP_HEADLESS_TEST"] = "1"
def _prepend_host_pytest_runtime() -> None:
if platform.system() != "Darwin" or os.getenv("SP_DISABLE_HOST_PYTEST_REDIRECT") == "1":
return
root_dir = Path(__file__).resolve().parent
work_dir = root_dir / ".host_runtime" / "darwin" / "worktree"
required_extension = work_dir / "msgq_repo" / "msgq" / "ipc_pyx.so"
if not required_extension.exists():
return
extra_paths = [work_dir, work_dir / "starpilot" / "third_party"]
extra_paths.extend(sorted(work_dir.glob("*_repo")))
acados_dir = work_dir / "third_party" / "acados"
if acados_dir.is_dir():
extra_paths.append(acados_dir)
existing = set(sys.path)
insert_at = 0
for path in [str(p) for p in extra_paths if p.exists()]:
if path in existing:
continue
sys.path.insert(insert_at, path)
insert_at += 1
_prepend_host_pytest_runtime()
from openpilot.common.prefix import OpenpilotPrefix
from openpilot.system.manager import manager
from openpilot.system.hardware import TICI, HARDWARE
@@ -57,8 +98,7 @@ def openpilot_function_fixture(request):
# ensure the test doesn't change the prefix
assert "OPENPILOT_PREFIX" in os.environ and prefix == os.environ["OPENPILOT_PREFIX"]
# cleanup any started processes
manager.manager_cleanup()
manager.manager_cleanup()
# some processes disable gc for performance, re-enable here
if not gc.isenabled():
@@ -86,6 +126,9 @@ def tici_setup_fixture(request, openpilot_function_fixture):
@pytest.hookimpl(tryfirst=True)
def pytest_collection_modifyitems(config, items):
skipper = pytest.mark.skip(reason="Skipping tici test on PC")
darwin_fake_event_skipper = pytest.mark.skip(reason="Fake socket events are unavailable on macOS")
darwin_tmpfs_skipper = pytest.mark.skip(reason="tmpfs mount tests require Linux")
darwin_proxy_skipper = pytest.mark.skip(reason="Athena local proxy socket test requires Linux select semantics")
for item in items:
if "tici" in item.keywords:
if not TICI:
@@ -98,6 +141,15 @@ def pytest_collection_modifyitems(config, items):
class_property_value = getattr(item.cls, class_property_name)
item.add_marker(pytest.mark.xdist_group(class_property_value))
if platform.system() == "Darwin" and item.path.name in ("test_fuzzy.py", "test_processes.py") and "process_replay" in item.path.parts:
item.add_marker(darwin_fake_event_skipper)
if platform.system() == "Darwin" and item.path.name == "test_git.py" and "updated" in item.path.parts:
item.add_marker(darwin_tmpfs_skipper)
if platform.system() == "Darwin" and item.name == "test_start_local_proxy" and "athena" in item.path.parts:
item.add_marker(darwin_proxy_skipper)
@pytest.hookimpl(trylast=True)
def pytest_configure(config):
+6 -1
View File
@@ -4,7 +4,7 @@
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
# 325 Supported Cars
# 326 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video|Setup Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
@@ -110,6 +110,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera 2022">Buy Here</a></sub></details>|||
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid 2019">Buy Here</a></sub></details>|||
|Hyundai|Azera Hybrid 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid 2020">Buy Here</a></sub></details>|||
|Hyundai|Azera Hybrid (with HDA II & LFA2) 2025|Highway Driving Assist II & Lane Follow Assist 2|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai S connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid (with HDA II & LFA2) 2025">Buy Here</a></sub></details>|||
|Hyundai|Custin 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Custin 2023">Buy Here</a></sub></details>|||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2017-18">Buy Here</a></sub></details>|||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 OBD-C cable (2 ft)<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2019">Buy Here</a></sub></details>|||
@@ -230,13 +231,17 @@ A supported vehicle is one that just works when you install a comma device. All
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Ateca 2016-23">Buy Here</a></sub></details>|||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=SEAT Leon 2014-20">Buy Here</a></sub></details>|||
|Subaru|Ascent 2019-21|All[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Ascent 2023|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Ascent 2023">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Crosstrek 2025|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Crosstrek 2025">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Forester 2019-21|All[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Forester 2022-24|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru C connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Forester 2022-24">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Legacy 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Legacy 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Outback 2020-22|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru B connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|Outback 2023|All[<sup>6</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru D connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 2023">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>6</sup>](#footnotes)|openpilot available[<sup>1,7</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 Subaru A connector<br>- 1 comma four<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|||
|Škoda|Fabia 2022-23[<sup>13</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-C cable (2 ft)<br>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma four<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Fabia 2022-23">Buy Here</a></sub></details>[<sup>15</sup>](#footnotes)|||
+182
View File
@@ -0,0 +1,182 @@
# StarPilot Unified Model Rebuild
This workflow rebuilds StarPilot driving and driver-monitoring artifacts for the vendored tinygrad revision. Driving-model behavior versions remain manifest metadata; every runtime driving artifact uses the `tinygrad_single_v1` layout.
## Safety
- The supported build device is `comma@192.168.3.110`.
- Never run these commands against `192.168.3.109`.
- Normal artifacts target QCOM. External-GPU artifacts must be compiled explicitly and tagged in the manifest.
- Keep source ONNX files and compiled PKLs on the T5 workspace, not the comma.
## Workspace
The default workspace is:
```text
/Volumes/T5/StarPilot-Model-Rebuild-2026-06-22/
```
Important directories:
- `onnx/<model-id>/`: ID-prefixed source ONNX files.
- `compiled/`: completed unified driving PKLs.
- `driver-monitoring/`: DM ONNX, model PKL, metadata, and camera warps.
- `ready-for-resources/`: flat repository-upload handoff.
- Oversized models are represented by repository-safe `.p00`, `.p01`, and `.sha256` files in `ready-for-resources/`.
- `logs/`: one remote compilation log per model.
- `results/`: source and artifact checksum records.
- `manifests/`: generated `model_names_v22.json`.
## Initialize And Extract
```bash
python3 scripts/model_rebuild_pipeline.py init
python3 scripts/model_rebuild_pipeline.py extract \
--base-manifest /path/to/model_names_v21.json
```
Extraction streams Git blobs directly to disk. LFS pointers are resolved from the local object cache or fetched by object ID, then checked against the pointer SHA-256 and size. Binary ONNX data is never stored in a shell variable.
To retry one source:
```bash
python3 scripts/model_rebuild_pipeline.py extract \
--model pop22 \
--base-manifest /path/to/model_names_v21.json
```
Source commits are defined in `scripts/model_source_map_v22.json`.
## Compile
Compile one model:
```bash
python3 scripts/model_rebuild_pipeline.py compile \
--model pop22 \
--base-manifest /path/to/model_names_v21.json
```
Compile or resume the full catalog:
```bash
python3 scripts/model_rebuild_pipeline.py compile \
--base-manifest /path/to/model_names_v21.json
```
Existing artifacts are skipped unless `--force` is passed. Each model is staged in its own remote input directory, compiled on `.110`, copied back to the T5, hashed, and copied into `ready-for-resources/`. Failures are written to `results/<id>_failure.json`; rerunning the same command resumes incomplete models.
Validate one or all completed artifacts with synthetic camera inputs on QCOM:
```bash
python3 scripts/model_rebuild_pipeline.py validate \
--model pop22 \
--base-manifest /path/to/model_names_v21.json
```
The lower-level device compiler also supports direct use:
```bash
./models --model pop22 --input-format split --version v11
./models --model deeprl3v2 --input-format supercombo --version v15
```
For a model that cannot run on the device GPU, compile with the USB AMD GPU attached:
```bash
./models --lebowski --gpu
```
The ASM2464PD bridge must run the current tinygrad custom firmware from
https://github.com/tinygrad/asm2464pd-firmware. Its USB product string starts
with `custom`; the legacy `USB 3.2 PCIe TinyEnclosure` patch is not compatible
with comma's current external-GPU runtime. Firmware flashing is a separate,
explicit hardware setup step and StarPilot never performs it automatically.
The dynamic flag (`--lebowski` above) sets the output and manifest model ID;
when only one source model is staged, its ONNX filename does not need to match
that ID. Input format and behavior version are inferred. `--external-gpu`
remains available as a compatibility alias for `--gpu`.
This emits a streaming out-of-band pickle and keeps QCOM available for camera warps. Its manifest entry must include:
```json
{
"id": "lebowski",
"uses_external_gpu": true
}
```
Only tagged models activate the external GPU. If the GPU or artifact is unavailable, runtime falls back to the built-in model; all untagged models retain the existing QCOM path.
`--version` records behavioral semantics only. It does not change artifact layout.
If the compiled PKL exceeds 100 MiB, `./models` automatically keeps the full
local PKL and creates 95 MiB upload parts beside it:
```text
deeprl3v2_driving_tinygrad.pkl
deeprl3v2_driving_tinygrad.pkl.p00
deeprl3v2_driving_tinygrad.pkl.p01
deeprl3v2_driving_tinygrad.pkl.sha256
```
To split an already compiled artifact:
```bash
./models --split-artifact /path/to/deeprl3v2_driving_tinygrad.pkl \
--output-dir /path/to/upload-ready
```
Upload only the numbered parts and checksum when the full PKL exceeds the
repository limit. The downloader reassembles into a temporary file, verifies
the companion SHA-256, and atomically installs the final PKL. No manifest field
is required for multipart artifacts.
## Driver Monitoring
Stage the current DM ONNX in `uncompiledmodels`, then run:
```bash
./models --dm \
--input-dir /data/openpilot/uncompiledmodels \
--output-dir /tmp/dm_artifacts
```
This builds:
- `dmonitoring_model_tinygrad.pkl`
- `dmonitoring_model_metadata.pkl`
- `dm_warp_1928x1208_tinygrad.pkl`
- `dm_warp_1344x760_tinygrad.pkl`
All four files must be updated together.
## Manifest
Generate v22 after compilation:
```bash
python3 scripts/model_rebuild_pipeline.py manifest \
--base-manifest /path/to/model_names_v21.json
```
The generator preserves existing IDs and behavioral metadata and adds
`deeprl3v2`. Manifest v22 implies the unified single-PKL runtime layout.
Repository-hosted multipart files are discovered by naming convention, so no
size, hash, format, or part-count metadata is required.
`uses_external_gpu` is optional and defaults to `false`.
## Runtime Verification
Compilation validates JIT capture/replay, pickle round-trip, finite outputs, metadata slices, and both camera warps. Before release:
1. Select representative v8, v11, v12, v15, and supercombo models.
2. Confirm `modeld` stays running.
3. Confirm finite `modelV2` path, lane-line, lead, pose, and action data.
4. Confirm `driverStateV2` on both supported camera resolutions.
5. Test download, selection, deletion, randomization, migration, and fallback in QT, raylib/mici, and Galaxy.
The built-in South Carolina artifact is `selfdrive/modeld/models/driving_tinygrad.pkl`. If migration cannot download the selected v22 artifact, StarPilot switches to that built-in model.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.
+102
View File
@@ -0,0 +1,102 @@
# Contribute to StarPilot
Contributions are welcome. StarPilot is driver-assistance software, so changes should be focused, testable, and safe for vehicles outside the change's intended scope.
## Pull requests
Open all pull requests against the **`Dom` branch**. `Dom` is StarPilot's testing and integration branch; do not target the release branch directly.
A pull request should:
* have one clear purpose and contain only changes needed for that purpose;
* explain what changed, why it changed, and how it was tested;
* link the relevant issue or feedback item when one exists;
* avoid unrelated cleanup, refactors, dependency changes, and formatting churn; and
* pass the existing tests and checks.
Keep commits reviewable and update documentation when behavior or configuration changes. If a change needs a large refactor, separate that work from the behavior change when practical.
### Vehicle-specific changes
Do your best to ensure a vehicle-specific change affects only the intended vehicle, platform, or brand. Prefer the narrowest appropriate condition instead of changing shared behavior for every vehicle.
Tests should prove both sides of that boundary:
* the affected vehicle receives the new or corrected behavior; and
* an unaffected vehicle, platform, brand, or configuration retains the existing behavior.
Include the vehicle and hardware used for on-road or bench testing in the pull request. Hardware testing is valuable, but it does not replace an automated regression test when the behavior can be tested in code.
## Development environment
StarPilot keeps host-native development tools separate from device-target builds. Run the setup and development commands from the repository root.
Install the Python dependencies before starting:
```bash
tools/install_python_dependencies.sh
```
On Ubuntu, `tools/ubuntu_setup.sh` installs both the system and Python dependencies. The development tools also require `uv`.
Use `./dev` for host-native tools. It creates and reuses an isolated environment under `.host_runtime/`, keeping host build artifacts out of the working tree:
```bash
./dev replay
./dev cabana
./dev plotjuggler
./dev shell
```
For desktop UI work, use `./c3`, `./c4`, or `./raybig`. These commands use the same isolated host environment.
Use `./build` when you need comma-compatible device artifacts. This is the expected validation for changes that affect compiled device code or runtime behavior:
```bash
./build
```
Device builds require Docker Desktop or Podman with Linux/aarch64 support and a configured comma sysroot. See the [laptop device-build guide](../how-to/laptop-device-build.md) for setup instructions and the [complete StarPilot development workflow](https://github.com/firestar5683/StarPilot/blob/Dom/tools/STARPILOT_DEVELOPMENT.md) for all host commands and troubleshooting.
## Code formatting
Match the style of the code around your change and do not reformat unrelated files. Python formatting and lint rules are defined in `pyproject.toml`; the project uses two-space indentation and Ruff.
Run Ruff on changed Python files while developing:
```bash
ruff check path/to/changed_file.py
ruff format --check path/to/changed_file.py
```
Before submitting, run the repository lint checks from the project root:
```bash
./scripts/lint/lint.sh
```
## Testing standards
Every behavior change or bug fix should include focused automated tests when practical. Recent StarPilot tests favor small regression cases that construct the relevant state, exercise one behavior, and assert the exact result.
At minimum:
1. Add or update a test that would fail without the change.
2. Cover important boundaries, modes, and disabled states related to the change.
3. For vehicle-specific behavior, add a negative case showing the change does not bleed into an unaffected vehicle or configuration.
4. Run the directly affected test module and the existing tests for the affected subsystem.
5. Ensure the pull request passes all existing CI checks before it is ready to merge.
Run a focused test module with pytest:
```bash
pytest path/to/test_file.py
```
Run the full test suite when your development environment supports it:
```bash
pytest
```
If a test requires special hardware or cannot run in your environment, say so in the pull request and document the closest validation you completed.
+1 -1
View File
@@ -2,7 +2,7 @@
This flow builds **device-target (`larch64`) binaries on your laptop** using a Linux/aarch64 container and a synced comma sysroot.
For the full StarPilot branch workflow, including host-native shorthand tools such as `./dev`, `./c3`, `./c4`, and `./raybig`, see [tools/STARPILOT_DEVELOPMENT.md](../../tools/STARPILOT_DEVELOPMENT.md).
For the full StarPilot branch workflow, including host-native shorthand tools such as `./dev`, `./c3`, `./c4`, and `./raybig`, see the [StarPilot development guide](https://github.com/firestar5683/StarPilot/blob/Dom/tools/STARPILOT_DEVELOPMENT.md).
## Prerequisites
+109
View File
@@ -302,3 +302,112 @@ For temporal behavior on a saved frame directory or route extract, replay the ru
```bash
.venv/bin/python scripts/replay_speed_limit_vision.py .tmp/vision_iter/seg10_5fps --frames-fps 5
```
The detector/classifier runtime is model-only by default. Use `--crop-ocr` with
`evaluate_runtime_manifest.py` or `replay_route_runtime.py` only for an explicit
legacy comparison. A model-only release must match reviewed-manifest accuracy
and pass representative route replays at measured on-device cadence. Evaluate
candidate recognition and temporal publish behavior separately: a correct
single-frame candidate can still be suppressed by the history and speed-change
confirmation policy.
Ignored review rows label the proposed crop, not the entire camera frame.
Consequently, negative-window candidate and publish counts from
`evaluate_reviewed_route_events.py` are an upper bound until the full frame is
audited; another valid sign can be present outside the rejected crop. Use the
per-row output and frame image to audit any regression delta before treating it
as a runtime false positive.
## Promotion Gate
Do not promote a checkpoint from classifier validation accuracy alone. Export it
to an isolated model directory and run the complete runtime pipeline against the
reviewed positive, hard-negative, and failed-drive manifests. A candidate must
preserve exact-value recall, avoid new wrong-value reads, and remain within the
accepted false-positive budget before route replay.
Mine detector proposals that fool an integrated-reject classifier into a new
reject class before retraining:
```bash
.venv/bin/python scripts/speed_limit_vision/mine_classifier_reject_crops.py \
--models-dir /path/to/candidate/models \
--dataset /path/to/versioned/classifier \
--manifest /path/to/reviewed-negative-manifest.csv
```
Keep the resulting dataset version separate from the current training set. If a
hard-negative retrain lowers reviewed recall, reject the checkpoint even when it
improves aggregate validation accuracy or removes a known false positive.
## Active-Learning Review Pass
Keep parallel miners in separate directories and merge them only when their
model and mining fingerprints match:
```bash
.venv/bin/python scripts/speed_limit_vision/merge_manual_review_queues.py \
/path/to/shard0 /path/to/shard1 /path/to/shard2 /path/to/shard3 \
--output-dir /path/to/merged
```
When rescanning with a new model, compare the fingerprinted queues before
selecting another batch. The optional review output retains the full queue
schema so it can be passed directly to the selector and review server:
```bash
.venv/bin/python scripts/speed_limit_vision/compare_manual_review_queues.py \
--before /path/to/baseline/manual_review_queue.csv \
--after /path/to/candidate/manual_review_queue.csv \
--output-csv /path/to/comparison.csv \
--review-output /path/to/disagreements/manual_review_queue.csv
.venv/bin/python scripts/speed_limit_vision/select_manual_review_queue.py \
--input /path/to/disagreements/manual_review_queue.csv \
--output /path/to/review/manual_review_queue.csv \
--max-rows 1200 \
--min-seconds-per-route-speed 3
```
The selector prioritizes value changes and gained/lost reads, balances routes
and speed classes, and removes adjacent same-speed frames from one scene. Start
the reviewer and import its labels without moving route media off the training
volume:
```bash
.venv/bin/python scripts/speed_limit_vision/serve_manual_review_queue.py \
--manifest /path/to/review/manual_review_queue.csv \
--port 8765
.venv/bin/python scripts/speed_limit_vision/import_manual_review_queue.py \
--queue /path/to/review/manual_review_queue.csv
```
## Re-mine the Route Backlog
Re-run the backlog after a candidate passes the reviewed-manifest and route
replay gates. Use a model fingerprinted run so new pseudo-labels are staged next
to, rather than merged into, the original route-mining data:
```bash
.venv/bin/python scripts/speed_limit_vision/mine_route_training_samples.py \
--workspace /Volumes/T5/starpilot_speed_limit/workspace/speed_limit_training_clean \
--models-dir /path/to/promoted/models \
--model-only \
--run-id auto \
--sample-every 2.0 \
--transition-step 0.5 \
--max-frames-per-route 720 \
--max-positives-per-route 120 \
--max-negatives-per-route 200
```
The output is written under
`staging/route_mining/model_<model-fingerprint>_run_<mining-fingerprint>/` with
its own detector images, classifier labels, review manifest, and per-route
completion state. The mining fingerprint includes the model-only mode,
thresholds, sampling configuration, and relevant source code. Review and
deduplicate that staged run before merging it into a training dataset. Never
overwrite the canonical route samples or automatically train on every mined
positive; map agreement and human review remain required because a stronger
model can still reproduce its own mistakes at larger scale.
+113
View File
@@ -0,0 +1,113 @@
# TrueNAS SCALE GitHub Build Runner
This setup runs a single GitHub self-hosted runner as a TrueNAS SCALE custom app and routes the `Compile StarPilot` workflow onto that runner.
The app container:
- registers one repository-scoped GitHub Actions runner
- stays visible in the TrueNAS Apps UI
- mounts the host Docker socket so `./build` can launch the existing larch64 build container flow
- persists runner state and build caches in one dataset mounted at `/runner`
## What this workflow does
`.github/workflows/compile_starpilot.yaml` now:
- lets an admin choose a `target_ref` branch from the Actions UI
- checks out that branch on the NAS runner
- runs `./build`
- prunes the tree with `scripts/ci_package_prebuilt_tree.sh`
- commits the result as `build`
- pushes that commit back to the selected branch without force-pushing
Use a branch intended for built output. The prune step removes developer-facing files and is not meant for normal day-to-day development branches.
## 1. Publish the runner image
You need a registry image for TrueNAS to deploy. The repo includes `.github/workflows/publish_truenas_runner.yaml` for this.
1. Open **Actions** on GitHub.
2. Run **Publish TrueNAS Runner Image**.
3. Leave `image_tag` as `latest` unless you want a versioned tag.
4. After it finishes, the image is available at:
```text
ghcr.io/<repo-owner>/starpilot-truenas-runner:latest
```
If you prefer to build it locally, run:
```bash
docker build -f tools/truenas_github_runner/Dockerfile -t ghcr.io/<repo-owner>/starpilot-truenas-runner:latest .
docker push ghcr.io/<repo-owner>/starpilot-truenas-runner:latest
```
## 2. Create a runner token
Generate a repository-scoped self-hosted runner token in GitHub:
1. Open the repository.
2. Go to **Settings > Actions > Runners**.
3. Click **New self-hosted runner**.
4. Choose **Linux** and **x64**.
5. Copy the one-time registration token from the generated setup commands.
That token expires quickly. Paste it into TrueNAS during deployment and restart the app if you need to re-register.
## 3. Deploy on TrueNAS SCALE
TrueNAS custom apps support Docker Compose YAML through **Apps > Discover Apps > Custom App > Install via YAML**.
Create a dataset for persistent runner state first, for example:
```text
/mnt/<pool>/apps/starpilot-runner
```
Then paste this compose YAML into TrueNAS after replacing the placeholders:
```yaml
services:
starpilot-runner:
image: ghcr.io/<repo-owner>/starpilot-truenas-runner:latest
container_name: starpilot-runner
restart: unless-stopped
environment:
GITHUB_REPOSITORY_URL: https://github.com/<repo-owner>/<repo-name>
RUNNER_NAME: starpilot-truenas-runner
RUNNER_LABELS: self-hosted,truenas,starpilot-build
RUNNER_WORKDIR: /runner/_work
RUNNER_TOKEN: <paste-one-time-runner-token>
DOCKER_GID: ""
REMOVE_RUNNER_ON_EXIT: "0"
volumes:
- /mnt/<pool>/apps/starpilot-runner:/runner
- /var/run/docker.sock:/var/run/docker.sock
```
If the container starts but cannot talk to Docker, inspect the Docker socket group on TrueNAS and set `DOCKER_GID` to that numeric group id.
## 4. Verify runner registration
Confirm all of the following:
- the app shows as `Running` in TrueNAS
- the container passes its healthcheck
- GitHub shows the runner as online with labels `self-hosted`, `truenas`, and `starpilot-build`
## 5. Run a build
1. Open **Actions > Compile StarPilot**.
2. Click **Run workflow**.
3. Enter the branch name in `target_ref`.
4. Optionally set `jobs` to the parallelism you want for `./build`.
5. Start the run.
On success, the workflow pushes a new commit named `build` back to that branch.
## Operational notes
- `RUNNER_TOKEN` is only required on first registration or when you want to replace a stale runner with the same name.
- Runner state is persisted in `/runner`, so normal restarts do not need a new token.
- `REMOVE_RUNNER_ON_EXIT=1` enables best-effort deregistration on shutdown, but that only works when the provided token is still valid.
- The build cache, GitHub workspace, and `.comma_sysroot` data all persist under the runner dataset as long as the workflow runs in the same mounted work area.
+278
View File
@@ -0,0 +1,278 @@
# I Taught My Comma to Read Speed Limit Signs
<video controls playsinline preload="metadata" poster="assets/speed-limit-vision-demo-poster.jpg" style="width: 100%; max-width: 1280px;">
<source src="assets/speed-limit-vision-demo.mp4" type="video/mp4">
</video>
[Watch the speed-limit vision demo](assets/speed-limit-vision-demo.mp4)
This whole project started because I was lazy.
If youve driven an HKG or Toyota vehicle in recent years, youve probably seen the dashboard automatically pick up speed limits using the camera. Coming from a car that didn't have this functionality, I was very jealous. Those cars can feed those speed limits directly into openpilot forks speed limit controllers. Mine couldn't.
The “solution” has been to manually add speed limits to Mapbox or OpenStreetMaps. It worked, but it was tedious. I live in rural Kansas, where my commute is almost entirely devoid of nerds contributing open source map data. I began mapping my commute when I first joined the project and within an hour said, “I ain't doin this”
We have an AI model that's good enough to drive our cars running on a smartphone chipset from years ago. How hard could it be to build one that just reads speed limit signs? I wanted StarPilot to look out the windshield, see a speed limit sign, and just know what it said.
That sounded simple enough.
It wasnt.
The first prototype was basically held together with duct tape: I used all the public speed limit datasets I could find (glare and Lisa), some OpenCV, a little OCR, and a lot of wishful thinking. It could occasionally read a sign, but it missed 90% of them and produced enough false positives that you definitely wouldnt want to trust it.
The important part wasnt that it sucked - it was that it worked just well enough to start collecting better training data.
I run a fork of openpilot called StarPilot. We're heavily focused on tuning and testing wild ideas, which made my users the perfect candidates for this project.
Instead of relying on public datasets that barely resembled comma camera footage, StarPilot started collecting its own. Community members submitted routes from all over the country using bookmarks that were generated automatically when the model said "I think this might've been a sign," and every promising detection went through manual review. Eventually that grew into hundreds of gigabytes of real driving footage and thousands of carefully labeled speed limit signs.
From there it became an endless cycle:
- Train a better model.
- Mine more routes.
- Find more missed signs.
- Label them.
- Repeat.
The funny part is that training the neural network wasnt actually the hardest problem.
The hard part was everything around it.
One of the biggest challenges wasnt accuracy, it was speed. Every millisecond spent processing was another frame the model didn't have time to see. The faster it could process frames, the more chances it had to catch a sharp, readable speed limit sign before it disappeared. This was particularly imperative at night, when naturally camera frame rates drop alongside your chances of picking up a clear sign.
Its slowly evolved from a proof of concept into a model thats trained primarily on real comma footage instead of generic traffic sign datasets. It now runs entirely on-device, publishes vision-based speed limits directly into StarPilot, and no longer depends on OCR or manually maintaining map data.
And best of all…
While I'm too lazy to hand write hundreds of speed limit signs into OpenStreetMaps, this tool can now be used to automate the entire process, giving back to the open source mapping community that helps those in larger areas so well.
Give my vision speed limits a try, or help continue to build a better one than mine! All info and training stack is available on the StarPilot repo.
---
*For a full LLM style, more technical breakdown for those interested in the process, please read below:*
## Teaching StarPilot to Read Speed Limit Signs
In March 2026, this project started with a practical question: could StarPilot use the road camera to recognize speed-limit signs, attach them to GPS data, and help fill gaps in OpenStreetMap?
The first answer was "probably." A clean 40 mph sign in recorded comma footage was large enough to detect and read. StarPilot already had access to the live road-camera stream through VisionIPC, ONNX models could run through OpenCV DNN, and the existing Speed Limit Controller already knew how to combine several sources. The pieces existed.
What did not exist was a model trained for this camera, a trustworthy dataset, an honest replay benchmark, or a runtime that could analyze enough frames without interfering with openpilot. Building those became the real project.
This is the story of how we went from a weak imported model that was barely useful for automatic bookmarks to a custom detector and classifier trained primarily from real comma footage, how community routes changed the quality of the data, and why model accuracy on a laptop turned out to be only half of the problem.
### The first prototype
The first live implementation used an imported Ultralytics-style checkpoint called `ayoubsa_best`. Its provenance was thin: the ONNX metadata identified it as a Kaggle-trained detector, but there was no training notebook or source dataset in the repository. More importantly, its classes were a poor fit for American roads. It knew speed limits in 10 mph increments, such as 20, 30, and 40, but not the common 25, 35, 45, 55, or 65 mph signs.
That led to a hybrid design. The model proposed a sign region, then lightweight OpenCV and OCR-like digit logic tried to read the crop. It was enough to prove the complete path:
1. Read the live road-camera stream.
2. Search the right side of the frame for likely signs.
3. Produce a candidate speed and confidence.
4. Confirm it over time.
5. Publish it as a selectable `Vision` source for the Speed Limit Controller.
6. Save debug frames and bookmarks for later training.
It was not yet a good speed-limit reader. It missed most signs, produced false positives, and struggled badly with 5 mph increments. But it could occasionally find real signs, which meant it could help us collect the data needed to replace itself.
That bootstrap capability mattered more than its initial accuracy.
### Public data gave us a starting point
We chose a two-stage architecture early: one model would answer "where is the speed-limit sign and what kind is it?" while another would answer "what number is printed on it?" Detection and reading are related, but they are not the same task. Keeping them separate let the detector learn the general shape and location of a sign without needing a separate object class for every posted speed.
Three public U.S. traffic-sign datasets formed the initial training base:
- [LISA](https://cvrr.ucsd.edu/lisa-traffic-signs-dataset) provided U.S. road scenes, 47 sign types, and 7,855 annotations across 6,610 frames. Its annotations also included useful information such as occlusion and whether a sign belonged to a side road.
- [GLARE](https://arxiv.org/abs/2209.08716) provided 2,157 U.S. traffic-sign images taken from 33 dashcam videos under strong sun glare. The paper itself demonstrated why mixed normal and glare training was important.
- [ARTS](https://swshah.w3.uvm.edu/vail/datasets.php), the Automotive Repository of Traffic Signs, provided additional U.S. signs in easy, challenging, and video-log configurations.
The clean first pass imported 3,078 ARTS images with 3,139 relevant boxes. When a working LISA archive was found, it added 1,577 images and 1,680 boxes, including 15, 25, 35, 45, 55, and 65 mph classes. GLARE was downloaded selectively to avoid pulling a large collection of unrelated checkpoints.
### More data made the first retrain worse
The first clean public-data retrain looked reasonable in conventional validation metrics and failed badly on real comma routes.
The stronger older model found a candidate in 9 of 39 bookmarked route windows. The clean public-data model found only 1 of 39. It also regressed the saved-frame suite. We restored the older model instead of promoting a checkpoint merely because it was newer or had better training curves.
The domain gap was larger than image dimensions suggested. LISA, GLARE, ARTS, and comma footage were all forward-looking road imagery, but they differed in lens distortion, mounting position, exposure, dynamic range, compression, motion blur, sign position, and the number of pixels available when a sign first appeared. Public data often contained a cleaner or more centered sign than the live comma pipeline would see.
This established a rule that guided every later pass: public data was useful for bootstrapping and preservation, but real comma footage had to dominate final training and evaluation.
### Turning StarPilot into a data engine
The next large improvement did not come from a new backbone. It came from collecting better data.
StarPilot gained an automatic training collector, automatic bookmarks, manual bookmarks, debug snapshots, route metadata, and tools to preserve full-resolution video segments. A route-bundling script verified that a contributed route was public, contained the required qlogs, rlogs, and `fcamera.hevc` files, and had the vision collector enabled before packaging it.
That allowed StarPilot users to contribute real driving data from different cars, cameras, roads, states, lighting conditions, and sign styles. Eventually, nearly 200 GB of zipped comma routes landed on disk. This was enormously more useful than another generic sign dataset because it matched the exact production domain:
- the same road camera and encoding path;
- the same wide-angle geometry;
- the same night exposure and motion blur;
- the same right-shoulder sign placement;
- the same live crop errors;
- and the same hard negatives seen by the runtime detector.
The model could then scan old routes, find likely signs and mistakes, and generate another review queue. A better model could rescan the same backlog and find candidates the weaker model had never seen. Each iteration improved not only the deployed model, but also the quality of the next dataset.
### Human review was the quality control
Automatic labels were never trusted blindly. A map transition did not prove that a sign was visible, a bookmark did not prove that the best frame had been selected, and a confident model prediction did not prove that the crop contained the correct sign.
The manual review UI evolved around throughput. Typing a number labeled a regulatory sign. Single-key shortcuts marked advisory (`a`), school-zone (`s`), regulatory (`r`), uncertain (`u`), or ignored/not-a-sign (`i` or `x`) samples. Enter or Space accepted a prediction. Reviewers could also redraw a bad bounding box.
Those details affected model quality directly:
- A readable but slightly imperfect crop was useful.
- A crop that showed only the minimum-speed portion of a 65/40 sign was not a valid 40 mph regulatory label.
- Stop signs and empty crops became hard negatives.
- Advisory signs were labeled explicitly, even though overall sign recall remained the product priority.
- Uncertain night crops were retained separately instead of being treated as equally strong labels.
- Repeated frames from the same sign track were deduplicated so one scene could not dominate the dataset.
- Incorrectly large or shifted boxes were redrawn once the review tool exposed that capability.
One labeling ambiguity forced a larger re-review: earlier sessions had not made regulatory versus advisory state clear enough. Rather than preserve potentially poisoned labels, affected advisory candidates were put back into the queue under the corrected UI contract.
This was active learning in a practical form: spend human time on disagreements, weak reads, false publishes, missed signs, bad boxes, and rare conditions, not on thousands of easy duplicate frames.
By one later OCR-free promotion audit, the backlog covered 80 routes and 366,946 sampled frames. The model under audit produced 34,260 candidates for rescoring, while the canonical review database contained 5,383 unique human-reviewed crops: 593 positive reads and 4,146 usable crop-level rejects, with the remainder reserved for uncertain or otherwise excluded decisions. The raw route collection was large, but those reviewed examples were the part that made it trustworthy.
### The architecture that survived
The current production path is model-only. OCR remains in the source tree for legacy compatibility and offline experiments, but both full-frame OCR and crop OCR are disabled for the active detector/classifier pipeline.
The deployed stack contains:
- A YOLO11n-derived detector exported as a fixed `256x256` ONNX model. It proposes regulatory, advisory, and school-zone speed-limit signs.
- A YOLO11n-classifier-derived `128x128` ONNX model. It predicts 15 through 75 mph in 5 mph increments and includes a learned reject class for crops that are not valid speed-limit reads.
- Runtime logic that evaluates several crop expansions, combines their support, applies geometry and sign-type checks, and confirms lower-confidence changes over multiple frames.
- A right-side region of interest, which reduces wasted work while retaining the part of U.S. road scenes where most applicable signs appear.
The detector is about 9.9 MB and the classifier about 5.9 MB. They remain separate ONNX files intentionally. Joining the graphs into one file would make packaging look tidier, but it would not eliminate the detector or classifier computation. Separate models also let us change detector resolution, classifier training, reject behavior, and crop strategy independently.
A third standalone reject model was tested and discarded. It added another inference pass without measurably improving the reviewed positives or surviving false positive. Folding rejection into the value classifier produced a better cost/accuracy tradeoff.
OCR was removed only after the model-only path could pass the preservation suites on its own. In the decisive audit, model consensus improved the targeted 20 mph events from 1/14 to 11/14 and the broader targeted set from 21/36 to 27/36 without regressing the established legacy suites. At that point, OCR's occasional rescue was no longer worth the latency, extra failure modes, and frames lost while the device waited for it to finish.
Direct-value detectors, smaller input sizes, MobileNet-style classifiers, optical-flow tracking, and multiple crop strategies were also tested. Some looked attractive on desktop metrics and failed where it mattered. In particular, a 224-pixel detector was faster but dropped the hometown 20 mph suite from 14/14 to 9/14. The 256-pixel detector remained the better production choice.
### Frame rate is part of accuracy
The most important evaluation lesson came from a route with seven manually bookmarked signs.
An early offline replay sampled the video at 5 fps and found several signs. The actual comma found almost none. The model files matched and the vision process was running, so the discrepancy initially looked mysterious.
The replay had been landing on lucky frames.
The camera produced 25 frames per second, but the live process only attempted inference every 0.4 seconds. When we replayed all 25 source frames while enforcing that real inference gate, the local result fell to 0 of 7, matching the drive. Halving the interval to 0.2 seconds moved the same honest replay to 5 of 7 candidate windows and 3 of 7 actual publishes.
From then on, a model was not evaluated only as a collection of independent images. Route replay had to include:
- source-frame timing;
- the measured detector and classifier cost;
- steady and follow-up inference intervals;
- temporal confirmation rules;
- CPU backoff;
- and the distinction between a candidate and a value actually published to the UI or controller.
This distinction explained many arguments over numbers. A candidate means the detector and reader noticed something in a sign window. A publish means the temporal and confidence gates accepted it as the live speed limit. A model can read a sign correctly once and still fail to publish if a weak read requires a second frame that the device never processes.
Later-frame mining showed why this mattered. One pass revisited 405 known sign events and extracted 939 clearer frames from later in their tracks. Combined with track-aware classifier training and a reduction from four classifier crops to three, the measured runtime suite improved from 247 to 265 correct publications, including a gain from 211 to 229 in the priority 30-65 mph range. Better frame selection and less per-frame work helped at the same time.
### Making it fit beside openpilot
The comma is already running camera processing, the main driving models, localization, controls, the UI, and vehicle communication. A speed-limit sidecar cannot assume an idle CPU.
The early hybrid pipeline could take roughly 1.5 seconds per frame when the detector, crop reader, and OCR paths all fired. At that cadence, signs could pass through their brief readable window without ever being analyzed. It also added enough CPU pressure to coincide with camera/model frame-sync errors and temporary `locationd` alerts on some night drives.
Changing process priority was not the solution. The daemon was already running at a very low scheduling priority. The useful changes were to remove OCR from production, restrict detection to the right-side ROI, shrink the models carefully, avoid the extra reject-model pass, add device-load backoff, and use a faster follow-up cadence after a candidate appeared.
The current runtime requests a 0.15-second steady interval and a 0.10-second follow-up interval, but inference cost is the real limiter. On two measured routes, the complete process sustained about 1.77 to 1.81 inferences per second. The detector alone took roughly 0.43 to 0.44 seconds, and each classifier crop could add about 0.066 seconds. A sign may receive only 4 to 13 analyzed frames in a seven-second approach window.
This is why "run it at 10 Hz" is not a configuration change. The process can ask for 10 Hz, but it cannot start the next inference until the current one finishes.
### Debugging the system, not just the model
Several apparent model regressions were actually system problems.
These failures led to better observability: model hashes, inference counts, interval reasons, detector and classifier timing, CPU backoff state, candidates, publications, and debug captures all became part of route analysis. We stopped asking only "is the model accurate?" and started asking "which exact model and runtime processed which exact frames, and what did it publish?"
### How we decide whether a model is better
The promotion process now uses several independent gates:
- Reviewed crop accuracy checks whether the classifier can read localized signs.
- Hard-negative sets contain parking signs, traffic signals, truck restrictions, taillights, and other shapes that previously caused false reads.
- A 100-event main route suite tests full candidate and publication behavior at measured comma cadence.
- A separate 34-event held-out suite guards against tuning directly to the main set.
- A hometown 20 mph suite protects a class that earlier models repeatedly missed.
- Legacy suites ensure that old wins do not disappear.
- Targeted night and glare replays test the conditions most likely to break normal validation assumptions.
- On-device timing and live routes remain the final authority.
Many experiments were rejected despite improving one number. A glare-focused model lost broader recall. A traffic-signal hard-negative detector fixed one false positive and lost legitimate 35 mph signs. A more aggressive reject-classifier update reduced errors and then changed enough timing to expose different false publishes. Conservative weight interpolation often produced the safest result because it taught a narrow correction without erasing the representation that already worked.
The drive currently contains 87 detector experiment directories and 72 classifier experiment directories. Those are not 159 successive improvements. They are the record of resolution bake-offs, failed hard-negative passes, direct-value experiments, night/glare runs, integrated-reject models, temporal-crop training, and interpolations that mapped the boundaries of the system.
### Where accuracy is now
The current classifier, internally called `distilled-moonstone v3`, improved the deployed route suite without changing model size or runtime cost:
| Runtime suite | Previous tree | Current model |
| --- | ---: | ---: |
| Main route publishes | 78/100 | **92/100** |
| Main wrong publishes | 0 | **0** |
| Held-out publishes | 24/34 | **26/34** |
| Hometown 20 mph signs | 14/14 | **14/14** |
| Hard sun-glare check | 70 mph published | **70 mph published** |
These denominators are manually confirmed sign events, not arbitrary video frames. `92/100` means the full runtime pipeline published the correct value in 92 of 100 known sign windows while running with measured comma timing. It does not mean the model is 92 percent accurate on every road or every possible sign.
In ordinary daylight scenes, current performance is very good. The model is now reliable when signs are reasonably exposed and readable, while extreme image quality and limited frame opportunities remain the dominant failures.
The current result is also substantially better than the first public-data prototype, which missed nearly every sign on several routes and sometimes produced only a single useful event in an entire drive.
### The next hard barriers
The remaining misses are unusually informative. Of the 18 main-suite events the current model does not publish:
- 6 never produce a correct candidate at measured cadence.
- 4 produce exactly one weak correct read, but cannot satisfy the two-read confirmation rule.
- At an idealized 6.7 Hz cadence, the same model recovers 7 of those 10 publishes, reaching a theoretical 97/100, but also introduces one wrong publish.
- The three stubborn cases are all 45 mph scenes: two remain unreadable even at ideal cadence, and one first reads 40 before seeing 45 too late.
That theoretical 97/100 is not a production accuracy claim. It is a diagnostic result showing that most remaining failures already contain a readable frame that the device does not process.
The next large improvement is therefore likely to come from throughput and temporal reuse, not from simply lowering confidence thresholds:
1. Make the detector materially faster without giving up the small-sign and 20 mph recall lost by the 224- and 192-pixel experiments.
2. After a detector finds a sign, track or cheaply reclassify that crop across nearby frames instead of paying for another full detector pass every time.
3. Investigate a more efficient inference backend or model architecture on comma hardware. Direct model microbenchmarks are useful, but the complete process and onroad CPU contention must remain the acceptance metric.
4. Add targeted, human-reviewed sequences for the remaining 45 mph failures, night ghosting, distant signs, and direct-sun approaches.
5. Improve sign applicability for minimum-speed, truck-only, school-zone, advisory, side-road, and exit-ramp signs without sacrificing the product's primary goal: finding normal regulatory speed limits.
6. Keep model-fingerprinted backlog mining so every promoted model can rescan old routes into an isolated review set without silently replacing canonical labels.
Night remains difficult because the camera often produces fewer sharp frames, motion blur can create double digits, and reflective signs may be detected while they are still too distant to read. Glare is difficult for the opposite reason: contrast collapses and sign edges disappear into the sky. Both problems require sequence-level examples, not just one selected crop.
### What we learned
This was never one long training run. It was the construction of a data and evaluation system.
Public datasets made the first detector possible. A weak model made automatic collection possible. StarPilot users supplied the camera-native diversity that public data could not. Human review turned model proposals into trustworthy labels. Full-cadence replay exposed timing mistakes that image metrics hid. Live device telemetry kept CPU and process failures from being mistaken for neural-network failures. Conservative promotion gates preserved hard-won behavior while narrow experiments improved specific weaknesses.
The result is already useful and, in ordinary scenes, often impressively accurate. The path to the next jump is also clearer than it was at the beginning. We do not mainly need another giant pile of generic sign images. We need to process more of the good frames the comma already sees, teach the remaining hard sequences carefully, and continue judging the complete on-device system rather than the model in isolation.
That is the difference between training a traffic-sign classifier and building a speed-limit reader that works in a car.
### Technical references
- Runtime implementation: [`starpilot/system/speed_limit_vision.py`](../starpilot/system/speed_limit_vision.py)
- Training runbook: [`docs/how-to/train-speed-limit-vision.md`](how-to/train-speed-limit-vision.md)
- Training, mining, review, and evaluation tools: [`scripts/speed_limit_vision`](../scripts/speed_limit_vision)
- Deployed model assets: [`starpilot/assets/vision_models`](../starpilot/assets/vision_models)
+70 -65
View File
@@ -4,7 +4,25 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
source "$DIR/launch_env.sh"
export SP_BOOT_TIMING_LOG="${SP_BOOT_TIMING_LOG:-/tmp/starpilot_boot_timing.log}"
: > "$SP_BOOT_TIMING_LOG" 2>/dev/null || true
SP_LAUNCH_LAST_SECONDS=$SECONDS
function sp_boot_timing_line {
echo "$1"
printf '%s\n' "$1" >> "$SP_BOOT_TIMING_LOG" 2>/dev/null || true
}
function sp_launch_timing {
local now=$SECONDS
local delta=$((now - SP_LAUNCH_LAST_SECONDS))
sp_boot_timing_line "SP_BOOT_TIMING launch $1 +${delta}s total=${now}s"
SP_LAUNCH_LAST_SECONDS=$now
}
function agnos_init {
sp_launch_timing "agnos_init_start"
# TODO: move this to agnos
sudo rm -f /data/etc/NetworkManager/system-connections/*.nmmeta
@@ -33,67 +51,17 @@ function agnos_init {
# StarPilot variables
sudo chmod 0777 /cache
# Weston loads display color correction from /data/misc/display/color_cal/color_cal.
# Prefer a factory /persist/comma/color_cal blob when present. Otherwise, derive a
# Weston-compatible calibration blob from the device's legacy dwo gamma tables.
COLOR_CAL_SRC="/persist/comma/color_cal"
DWO_GAMMA_SRC="/persist/comma/dwo_gamma_curves"
COLOR_CAL_DST_DIR="/data/misc/display/color_cal"
COLOR_CAL_DST="${COLOR_CAL_DST_DIR}/color_cal"
COLOR_CAL_HASH_PATH="${COLOR_CAL_DST_DIR}/source.sha256"
DWO_REFERENCE="$DIR/tools/reference_dwo_gamma_curves.txt"
DWO_GENERATOR="$DIR/tools/generate_color_cal_from_dwo.py"
COLOR_CAL_UPDATED=0
COLOR_CAL_TMP=""
DWO_SOURCE_HASH=""
if [ -f "$COLOR_CAL_SRC" ]; then
sudo mkdir -p "$COLOR_CAL_DST_DIR"
if [ ! -f "$COLOR_CAL_DST" ] || ! cmp -s "$COLOR_CAL_SRC" "$COLOR_CAL_DST"; then
sudo cp "$COLOR_CAL_SRC" "$COLOR_CAL_DST"
sudo chown -R comma:comma "$COLOR_CAL_DST_DIR"
sudo chmod 664 "$COLOR_CAL_DST"
sudo rm -f "$COLOR_CAL_HASH_PATH"
COLOR_CAL_UPDATED=1
fi
elif [ -f "$DWO_GAMMA_SRC" ] && [ -f "$DWO_REFERENCE" ] && [ -f "$DWO_GENERATOR" ]; then
DWO_SOURCE_HASH="$(cat "$DWO_GAMMA_SRC" "$DWO_REFERENCE" "$DWO_GENERATOR" | sha256sum | awk '{print $1}')"
if [ ! -f "$COLOR_CAL_DST" ] || [ ! -f "$COLOR_CAL_HASH_PATH" ] || [ "$(cat "$COLOR_CAL_HASH_PATH" 2>/dev/null)" != "$DWO_SOURCE_HASH" ]; then
COLOR_CAL_TMP="$(mktemp)"
if python3 "$DWO_GENERATOR" --reference "$DWO_REFERENCE" --input "$DWO_GAMMA_SRC" --output "$COLOR_CAL_TMP"; then
sudo mkdir -p "$COLOR_CAL_DST_DIR"
if [ ! -f "$COLOR_CAL_DST" ] || ! cmp -s "$COLOR_CAL_TMP" "$COLOR_CAL_DST"; then
sudo cp "$COLOR_CAL_TMP" "$COLOR_CAL_DST"
COLOR_CAL_UPDATED=1
fi
printf '%s' "$DWO_SOURCE_HASH" | sudo tee "$COLOR_CAL_HASH_PATH" >/dev/null
sudo chown -R comma:comma "$COLOR_CAL_DST_DIR"
sudo chmod 664 "$COLOR_CAL_DST" "$COLOR_CAL_HASH_PATH"
fi
rm -f "$COLOR_CAL_TMP"
fi
fi
if [ "$COLOR_CAL_UPDATED" = "1" ] && systemctl is-active --quiet weston.service; then
sudo systemctl restart weston.service
# Weston can recreate wayland-0 as root on service restart before weston-ready
# fixes ownership. Repair it here so the Qt UI can always reconnect.
if [ -d /var/tmp/weston ]; then
for _ in $(seq 1 50); do
if [ -S /var/tmp/weston/wayland-0 ]; then
sudo chown -R comma:comma /var/tmp/weston 2>/dev/null || true
sudo chmod -R 700 /var/tmp/weston 2>/dev/null || true
SOCKET_OWNER="$(stat -c '%U:%G' /var/tmp/weston/wayland-0 2>/dev/null || true)"
[ "$SOCKET_OWNER" = "comma:comma" ] && break
fi
sleep 0.1
done
fi
fi
# Check if AGNOS update is required
if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then
AGNOS_CURRENT_VERSION="$(< /VERSION)"
AGNOS_UPDATE_REQUIRED=1
for accepted_version in $AGNOS_ACCEPTED_VERSIONS; do
if [ "$AGNOS_CURRENT_VERSION" = "$accepted_version" ]; then
AGNOS_UPDATE_REQUIRED=0
break
fi
done
if [ "$AGNOS_UPDATE_REQUIRED" = "1" ]; then
AGNOS_PY="$DIR/system/hardware/tici/agnos.py"
MANIFEST="$DIR/system/hardware/tici/agnos.json"
if $AGNOS_PY --verify $MANIFEST; then
@@ -101,9 +69,13 @@ function agnos_init {
fi
$DIR/system/hardware/tici/updater $AGNOS_PY $MANIFEST
fi
sp_launch_timing "agnos_init_done"
}
function launch {
sp_launch_timing "launch_start"
# Remove orphaned git lock if it exists on boot
[ -f "$DIR/.git/index.lock" ] && rm -f $DIR/.git/index.lock
@@ -140,30 +112,37 @@ function launch {
fi
fi
fi
sp_launch_timing "overlay_check_done"
# handle pythonpath
ln -sfn $(pwd) /data/pythonpath
export BASEDIR="$DIR"
export PYTHONPATH="$DIR/starpilot/third_party:$PWD"
sp_launch_timing "pythonpath_done"
# hardware specific init
if [ -f /AGNOS ]; then
agnos_init
fi
sp_launch_timing "hardware_init_done"
# write tmux scrollback to a file
tmux capture-pane -pq -S-1000 > /tmp/launch_log
sp_launch_timing "capture_launch_log_done"
# start manager
cd system/manager
sp_launch_timing "launch_param_migrations_start"
if ! python3 ./launch_param_migrations.py; then
echo "Launch param migrations failed; continuing boot."
fi
sp_launch_timing "launch_param_migrations_done"
# Bootstrap runtime (e.g. /usr/comma after reset/uninstall) must go straight
# to manager/setup flow. Do not run StarPilot prebuilt checks/builds here.
if [ "$DIR" = "/usr/comma" ] || [ ! -d "$DIR/.git" ]; then
sp_launch_timing "bootstrap_manager_start"
./manager.py
while true; do sleep 1; done
fi
@@ -171,15 +150,35 @@ function launch {
function prebuilt_runtime_compatible {
python3 - <<'PY'
import importlib
import os
from pathlib import Path
import sys
import time
start = time.monotonic()
last = start
log_path = os.environ.get("SP_BOOT_TIMING_LOG")
def emit(line):
print(line, flush=True)
if log_path:
try:
with open(log_path, "a") as f:
f.write(line + "\n")
except OSError:
pass
def log_step(label):
global last
now = time.monotonic()
emit(f"SP_BOOT_TIMING prebuilt_compat {label} +{now - last:.3f}s total={now - start:.3f}s")
last = now
mods = [
"openpilot.common.params_pyx",
"msgq.ipc_pyx",
"msgq.visionipc.visionipc_pyx",
"openpilot.common.transformations.transformations",
"openpilot.selfdrive.modeld.models.commonmodel_pyx",
"openpilot.selfdrive.pandad.pandad_api_impl",
"openpilot.selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx",
"openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx",
@@ -191,15 +190,15 @@ for mod in mods:
except Exception as e:
print(f"Prebuilt compatibility failure in {mod}: {e}", file=sys.stderr)
raise
log_step(f"import:{mod}")
repo_root = Path.cwd().parents[1]
required_files = [
repo_root / "selfdrive/modeld/models/driving_vision_metadata.pkl",
repo_root / "selfdrive/modeld/models/driving_policy_metadata.pkl",
repo_root / "selfdrive/modeld/models/driving_vision_tinygrad.pkl",
repo_root / "selfdrive/modeld/models/driving_policy_tinygrad.pkl",
repo_root / "selfdrive/modeld/models/driving_tinygrad.pkl",
repo_root / "selfdrive/modeld/models/dmonitoring_model_metadata.pkl",
repo_root / "selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl",
repo_root / "selfdrive/modeld/models/dm_warp_1928x1208_tinygrad.pkl",
repo_root / "selfdrive/modeld/models/dm_warp_1344x760_tinygrad.pkl",
repo_root / "selfdrive/pandad/pandad_api_impl.so",
repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so",
repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/libacados_ocp_solver_lat.so",
@@ -211,6 +210,7 @@ required_files = [
for path in required_files:
if not path.is_file():
raise FileNotFoundError(f"Missing prebuilt runtime artifact: {path}")
log_step("required_files")
PY
}
@@ -219,14 +219,19 @@ PY
USE_PREBUILT=$(tr -d '\n' < /data/params/d/UsePrebuilt)
fi
sp_launch_timing "prebuilt_decision_done"
if [ "$USE_PREBUILT" = "1" ] && [ -f $DIR/prebuilt ] && ! prebuilt_runtime_compatible; then
echo "Prebuilt runtime artifacts are incompatible on this device; rebuilding locally."
USE_PREBUILT=0
fi
sp_launch_timing "prebuilt_compat_done"
if [ "$USE_PREBUILT" != "1" ] || [ ! -f $DIR/prebuilt ]; then
sp_launch_timing "build_start"
./build.py
sp_launch_timing "build_done"
fi
sp_launch_timing "manager_start"
./manager.py
# if broken, keep on screen error
+5 -1
View File
@@ -21,7 +21,11 @@ fi
export QCOM_PRIORITY=12
if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="12.8.16"
export AGNOS_VERSION="12.8.28"
fi
if [ -z "$AGNOS_ACCEPTED_VERSIONS" ]; then
export AGNOS_ACCEPTED_VERSIONS="$AGNOS_VERSION"
fi
export STAGING_ROOT="/data/safe_staging"
Executable
+600
View File
@@ -0,0 +1,600 @@
#!/bin/sh
""":"
REPO_ROOT="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
PYTHON_BIN="$REPO_ROOT/.venv/bin/python"
if [ ! -x "$PYTHON_BIN" ]; then
echo "Missing $PYTHON_BIN. Run 'uv sync' from $REPO_ROOT first." >&2
exit 1
fi
exec "$PYTHON_BIN" "$0" "$@"
":"""
from __future__ import annotations
import argparse
import bz2
import io
import json
import os
import re
import shutil
import sys
import zipfile
from dataclasses import dataclass
from datetime import UTC, datetime
from email.utils import parsedate_to_datetime
from pathlib import Path
from typing import Any
from urllib.parse import quote, urlparse
import requests
import zstandard
from cereal import log
from openpilot.tools.lib.auth_config import DEFAULT_API_HOST, KONIK_API_HOST, get_token, normalize_api_host
API_HOST = normalize_api_host(os.getenv("COMMA_API_HOST") or os.getenv("API_HOST") or DEFAULT_API_HOST)
API_HOSTS = [API_HOST] if os.getenv("COMMA_API_HOST") or os.getenv("API_HOST") else [DEFAULT_API_HOST, KONIK_API_HOST]
ROUTE_ID_RE = re.compile(r"([0-9a-f]{16})/([^/]+)")
@dataclass(frozen=True)
class StreamSpec:
api_key: str
display_name: str
@dataclass(frozen=True)
class RouteId:
dongle_id: str
log_id: str
@property
def canonical_name(self) -> str:
return f"{self.dongle_id}|{self.log_id}"
@property
def cli_name(self) -> str:
return f"{self.dongle_id}/{self.log_id}"
@property
def safe_name(self) -> str:
return f"{self.dongle_id}_{self.log_id}"
@dataclass
class DownloadedFile:
segment: int
stream: str
filename: str
relative_path: str
mtime_epoch: int | None
@dataclass
class MapTileSummary:
qlogs_scanned: int = 0
mapd_messages: int = 0
tile_loaded_messages: int = 0
first_tile_segment: int | None = None
@property
def tile_loaded_any(self) -> bool:
return self.tile_loaded_messages > 0
class ValidationError(Exception):
def __init__(self, route: RouteId, reasons: list[str]):
self.route = route
self.reasons = reasons
super().__init__(self._render())
def _render(self) -> str:
lines = [f"Validation failed for {self.route.cli_name}:"]
lines.extend(f"- {reason}" for reason in self.reasons)
return "\n".join(lines)
REQUIRED_STREAMS = (
StreamSpec("qlogs", "qlog"),
StreamSpec("logs", "rlog"),
StreamSpec("cameras", "fcamera.hevc"),
)
def parse_args() -> argparse.Namespace:
argv = list(sys.argv[1:])
if argv and ROUTE_ID_RE.fullmatch(argv[0].lstrip("-")):
if argv[0].startswith("--"):
argv[0] = argv[0][2:]
argv = ["--routeid", argv[0], *argv[1:]]
parser = argparse.ArgumentParser(
description="Validate and bundle a public comma route for speed-limit vision review."
)
parser.add_argument("routeid_positional", nargs="?", help="Route id like 'dongle/logid' or 'dongle/logid--7'.")
parser.add_argument("--routeid", help="Route id like 'dongle/logid' or 'dongle/logid--7'.")
parser.add_argument("--desktop-root", type=Path, default=Path.home() / "Desktop", help="Destination root for the bundle folder and zip.")
parser.add_argument("--timeout", type=float, default=60.0, help="HTTP timeout in seconds.")
parser.add_argument("--overwrite", action="store_true", help="Replace an existing Desktop bundle for this route.")
parser.add_argument("--validate-only", action="store_true", help="Run validation only and skip downloads/zipping.")
args = parser.parse_args(argv)
args.routeid = args.routeid or args.routeid_positional
if not args.routeid:
parser.error("the following arguments are required: --routeid")
return args
def parse_route_id(raw: str) -> RouteId:
text = raw.strip().strip("'\"").replace("|", "/")
match = ROUTE_ID_RE.fullmatch(text)
if match is None:
raise ValueError(f"Unrecognized route id: {raw}")
dongle_id = match.group(1)
tail = match.group(2)
parts = tail.split("--")
if len(parts) == 3 and parts[-1].isdigit():
log_id = "--".join(parts[:2])
else:
log_id = tail
if len(log_id) != 20:
raise ValueError(f"Invalid log id in route: {raw}")
return RouteId(dongle_id=dongle_id, log_id=log_id)
def route_url(route: RouteId, api_host: str) -> str:
return f"{api_host}/v1/route/{quote(route.canonical_name, safe='')}/"
def route_files_url(route: RouteId, api_host: str) -> str:
return f"{api_host}/v1/route/{quote(route.canonical_name, safe='')}/files"
def format_segments(segments: list[int]) -> str:
if not segments:
return "none"
ranges: list[str] = []
start = prev = segments[0]
for segment in segments[1:]:
if segment == prev + 1:
prev = segment
continue
ranges.append(f"{start}-{prev}" if start != prev else str(start))
start = prev = segment
ranges.append(f"{start}-{prev}" if start != prev else str(start))
return ", ".join(ranges)
def as_int(value: Any) -> int | None:
if isinstance(value, bool):
return int(value)
if isinstance(value, int):
return value
if isinstance(value, str) and value.isdigit():
return int(value)
return None
def relative_posix(path: Path, root: Path) -> str:
return path.relative_to(root).as_posix()
def api_headers(api_host: str) -> dict[str, str] | None:
token = get_token(api_host)
return {"Authorization": f"JWT {token}"} if token else None
def fetch_json(session: requests.Session, url: str, timeout: float, api_host: str | None = None) -> Any:
response = session.get(url, timeout=timeout, allow_redirects=True, headers=api_headers(api_host) if api_host else None)
response.raise_for_status()
return response.json()
def fetch_bytes(session: requests.Session, url: str, timeout: float) -> bytes:
response = session.get(url, timeout=timeout, allow_redirects=True)
response.raise_for_status()
return response.content
def fetch_stream_to_path(session: requests.Session, url: str, dest_path: Path, timeout: float) -> int | None:
dest_path.parent.mkdir(parents=True, exist_ok=True)
response = session.get(url, stream=True, timeout=timeout, allow_redirects=True)
response.raise_for_status()
temp_path = dest_path.with_suffix(dest_path.suffix + ".part")
with temp_path.open("wb") as handle:
for chunk in response.iter_content(chunk_size=1 << 20):
if chunk:
handle.write(chunk)
temp_path.replace(dest_path)
last_modified = response.headers.get("Last-Modified")
if not last_modified:
return None
epoch = int(parsedate_to_datetime(last_modified).timestamp())
os.utime(dest_path, (epoch, epoch))
return epoch
def decompress_log_bytes(payload: bytes) -> bytes:
if payload[:3] == b"BZh":
return bz2.decompress(payload)
if payload[:4] == b"\x28\xb5\x2f\xfd":
reader = zstandard.ZstdDecompressor().stream_reader(io.BytesIO(payload))
try:
return reader.read()
finally:
reader.close()
return payload
def load_init_params(qlog_bytes: bytes) -> dict[str, str]:
payload = decompress_log_bytes(qlog_bytes)
for msg in log.Event.read_multiple_bytes(payload):
if msg.which() != "initData":
continue
params: dict[str, str] = {}
entries = msg.initData.params.to_dict().get("entries", [])
for entry in entries:
key = entry.get("key")
if not key:
continue
value = entry.get("value", b"")
if isinstance(value, bytes):
value = value.decode("utf-8", "replace")
elif value is None:
value = ""
else:
value = str(value)
params[str(key)] = value
return params
raise RuntimeError("No initData params found in qlog.")
def scan_qlogs_for_map_tiles(session: requests.Session, qlog_urls: list[str | None], timeout: float) -> MapTileSummary:
summary = MapTileSummary()
for segment, url in enumerate(qlog_urls):
if not isinstance(url, str) or not url:
continue
summary.qlogs_scanned += 1
payload = decompress_log_bytes(fetch_bytes(session, url, timeout))
for msg in log.Event.read_multiple_bytes(payload):
if msg.which() != "mapdOut":
continue
summary.mapd_messages += 1
if msg.mapdOut.tileLoaded:
summary.tile_loaded_messages += 1
if summary.first_tile_segment is None:
summary.first_tile_segment = segment
if summary.tile_loaded_any:
break
return summary
def expected_segment_count(route_meta: dict[str, Any], files_payload: dict[str, Any]) -> int:
candidates: list[int] = []
for key in ("maxqlog", "maxlog"):
value = as_int(route_meta.get(key))
if value is not None:
candidates.append(value + 1)
for key in ("qlogs", "logs", "cameras"):
value = files_payload.get(key)
if isinstance(value, list):
candidates.append(len(value))
return max(candidates, default=0)
def collect_missing_segments(urls: list[Any], expected_segments: int) -> list[int]:
missing: list[int] = []
for segment in range(expected_segments):
url = urls[segment] if segment < len(urls) else None
if not isinstance(url, str) or not url:
missing.append(segment)
return missing
def first_available_url(urls: list[Any]) -> str | None:
for url in urls:
if isinstance(url, str) and url:
return url
return None
def filename_from_url(url: str) -> str:
return Path(urlparse(url).path).name
def validate_route(route: RouteId, session: requests.Session, timeout: float) -> dict[str, Any]:
route_meta = None
files_payload = None
api_host = None
not_found_hosts = []
for candidate_host in API_HOSTS:
try:
route_meta = fetch_json(session, route_url(route, candidate_host), timeout, candidate_host)
except requests.HTTPError as exc:
status_code = exc.response.status_code if exc.response is not None else "unknown"
if status_code == 404 and len(API_HOSTS) > 1:
not_found_hosts.append(candidate_host)
continue
raise ValidationError(route, [f"route is not publicly accessible from {candidate_host} (HTTP {status_code})."]) from exc
try:
files_payload = fetch_json(session, route_files_url(route, candidate_host), timeout, candidate_host)
except requests.HTTPError as exc:
status_code = exc.response.status_code if exc.response is not None else "unknown"
if status_code == 404 and len(API_HOSTS) > 1:
not_found_hosts.append(candidate_host)
continue
raise ValidationError(route, [f"public route files could not be fetched from {candidate_host} (HTTP {status_code})."]) from exc
api_host = candidate_host
break
if route_meta is None or files_payload is None or api_host is None:
raise ValidationError(route, [f"route was not found on: {', '.join(not_found_hosts) or ', '.join(API_HOSTS)}."])
if not route_meta.get("is_public", False):
raise ValidationError(route, ["route metadata loaded, but `is_public` was false."])
expected_segments = expected_segment_count(route_meta, files_payload)
if expected_segments <= 0:
raise ValidationError(route, ["could not determine any route segments from the route API."])
failures: list[str] = []
stream_urls: dict[str, list[Any]] = {}
for spec in REQUIRED_STREAMS:
urls = files_payload.get(spec.api_key)
if not isinstance(urls, list):
urls = []
stream_urls[spec.api_key] = urls
missing_segments = collect_missing_segments(urls, expected_segments)
if missing_segments:
failures.append(f"missing uploaded {spec.display_name} files for segment(s): {format_segments(missing_segments)}.")
first_qlog_url = first_available_url(stream_urls["qlogs"])
params: dict[str, str] = {}
map_tiles = MapTileSummary()
if first_qlog_url is None:
failures.append("no qlog was available to inspect route params.")
else:
try:
params = load_init_params(fetch_bytes(session, first_qlog_url, timeout))
except Exception as exc:
failures.append(f"could not read `initData.params` from the first qlog: {exc}.")
if params:
auto_bookmark = params.get("VisionSpeedLimitAutoBookmark", "")
if auto_bookmark != "1":
failures.append(f"`VisionSpeedLimitAutoBookmark` was {auto_bookmark!r}; it must be '1'.")
vision_detection = params.get("VisionSpeedLimitDetection", "")
if vision_detection != "1":
failures.append(f"`VisionSpeedLimitDetection` was {vision_detection!r}; it must be '1' for useful vision-model collection.")
try:
qlog_urls = [url if isinstance(url, str) and url else None for url in stream_urls["qlogs"]]
map_tiles = scan_qlogs_for_map_tiles(session, qlog_urls, timeout)
if not map_tiles.tile_loaded_any:
maps_selected = params.get("MapsSelected", "")
if maps_selected:
failures.append(
"offline map tiles never loaded during this route even though "
f"`MapsSelected` was {maps_selected!r}; tell the user to download local maps for the driven area so collection trains faster."
)
else:
failures.append(
"offline map tiles never loaded during this route and `MapsSelected` was empty; "
"tell the user to download local maps for the driven area so collection trains faster."
)
except Exception as exc:
failures.append(f"could not inspect qlogs for offline map usage: {exc}.")
if failures:
raise ValidationError(route, failures)
return {
"api_host": api_host,
"route_meta": route_meta,
"files_payload": files_payload,
"expected_segments": expected_segments,
"params": params,
"map_tiles": map_tiles,
}
def prepare_output_paths(route: RouteId, desktop_root: Path, overwrite: bool) -> tuple[Path, Path]:
desktop_root = desktop_root.expanduser().resolve()
desktop_root.mkdir(parents=True, exist_ok=True)
bundle_root = desktop_root / f"speed_limit_route_bundle_{route.safe_name}"
zip_path = desktop_root / f"{bundle_root.name}.zip"
if overwrite:
if bundle_root.exists():
shutil.rmtree(bundle_root)
if zip_path.exists():
zip_path.unlink()
else:
if bundle_root.exists():
raise FileExistsError(f"Bundle folder already exists: {bundle_root}")
if zip_path.exists():
raise FileExistsError(f"Bundle zip already exists: {zip_path}")
return bundle_root, zip_path
def write_bundle_manifests(
bundle_root: Path,
route: RouteId,
validation: dict[str, Any],
downloaded_files: list[DownloadedFile],
) -> None:
live_routes_meta = bundle_root / "live_routes_meta"
live_routes_meta.mkdir(parents=True, exist_ok=True)
files_txt_lines: list[str] = []
qlog_mtimes_lines: list[str] = []
for record in sorted(downloaded_files, key=lambda item: (item.segment, item.stream, item.filename)):
segment_name = f"{route.log_id}--{record.segment}"
files_txt_lines.append(f"{segment_name} {record.relative_path}")
if record.filename.startswith("qlog") and record.mtime_epoch is not None:
qlog_mtimes_lines.append(f"{record.relative_path} {record.mtime_epoch}")
(live_routes_meta / "files.txt").write_text("\n".join(files_txt_lines) + ("\n" if files_txt_lines else ""), encoding="utf-8")
(live_routes_meta / "qlog_mtimes.txt").write_text("\n".join(qlog_mtimes_lines) + ("\n" if qlog_mtimes_lines else ""), encoding="utf-8")
params = validation["params"]
route_meta = validation["route_meta"]
map_tiles: MapTileSummary = validation["map_tiles"]
manifest = {
"bundleCreatedAt": datetime.now(UTC).isoformat(),
"routeId": route.cli_name,
"routeFullname": route.canonical_name,
"expectedSegments": validation["expected_segments"],
"downloadedStreams": [spec.display_name for spec in REQUIRED_STREAMS],
"validation": {
"isPublic": bool(route_meta.get("is_public")),
"visionSpeedLimitAutoBookmark": params.get("VisionSpeedLimitAutoBookmark", ""),
"visionSpeedLimitDetection": params.get("VisionSpeedLimitDetection", ""),
"mapsSelected": params.get("MapsSelected", ""),
"lastMapsUpdate": params.get("LastMapsUpdate", ""),
"mapdMessagesScanned": map_tiles.mapd_messages,
"offlineTileLoaded": map_tiles.tile_loaded_any,
"firstTileSegment": map_tiles.first_tile_segment,
},
"routeMeta": {
"startTime": route_meta.get("start_time"),
"endTime": route_meta.get("end_time"),
"distance": route_meta.get("distance"),
"startLat": route_meta.get("start_lat"),
"startLng": route_meta.get("start_lng"),
"endLat": route_meta.get("end_lat"),
"endLng": route_meta.get("end_lng"),
"gitBranch": route_meta.get("git_branch"),
"gitCommit": route_meta.get("git_commit"),
"platform": route_meta.get("platform"),
"version": route_meta.get("version"),
"make": route_meta.get("make"),
},
"files": [
{
"segment": record.segment,
"stream": record.stream,
"filename": record.filename,
"relativePath": record.relative_path,
"mtimeEpoch": record.mtime_epoch,
}
for record in sorted(downloaded_files, key=lambda item: (item.segment, item.stream, item.filename))
],
}
(bundle_root / "bundle_manifest.json").write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8")
def zip_bundle(bundle_root: Path, zip_path: Path) -> None:
with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_STORED) as archive:
for path in sorted(bundle_root.rglob("*")):
if path.is_file():
archive.write(path, arcname=Path(bundle_root.name) / path.relative_to(bundle_root))
def download_bundle(
route: RouteId,
validation: dict[str, Any],
session: requests.Session,
desktop_root: Path,
timeout: float,
overwrite: bool,
) -> tuple[Path, Path]:
bundle_root, zip_path = prepare_output_paths(route, desktop_root, overwrite)
clip_root = bundle_root / "data" / "media" / "0" / "realdata"
expected_segments = validation["expected_segments"]
files_payload = validation["files_payload"]
downloaded_files: list[DownloadedFile] = []
for spec in REQUIRED_STREAMS:
urls = files_payload.get(spec.api_key, [])
for segment in range(expected_segments):
url = urls[segment]
if not isinstance(url, str) or not url:
raise RuntimeError(f"Unexpected missing {spec.display_name} URL for segment {segment} after validation.")
filename = filename_from_url(url)
segment_name = f"{route.log_id}--{segment}"
dest_path = clip_root / segment_name / filename
print(f"Downloading {segment_name}/{filename}")
mtime_epoch = fetch_stream_to_path(session, url, dest_path, timeout)
downloaded_files.append(
DownloadedFile(
segment=segment,
stream=spec.display_name,
filename=filename,
relative_path=relative_posix(dest_path, bundle_root),
mtime_epoch=mtime_epoch,
)
)
write_bundle_manifests(bundle_root, route, validation, downloaded_files)
print(f"Creating {zip_path.name}")
zip_bundle(bundle_root, zip_path)
return bundle_root, zip_path
def print_validation_summary(route: RouteId, validation: dict[str, Any]) -> None:
params = validation["params"]
map_tiles: MapTileSummary = validation["map_tiles"]
print(f"Validated {route.cli_name}")
print(f" route API: {validation['api_host']}")
print(f" public route: yes")
print(f" segments: {validation['expected_segments']}")
print(f" VisionSpeedLimitDetection: {params.get('VisionSpeedLimitDetection', '')}")
print(f" VisionSpeedLimitAutoBookmark: {params.get('VisionSpeedLimitAutoBookmark', '')}")
print(f" MapsSelected: {params.get('MapsSelected', '') or '(empty)'}")
print(f" offline tile loaded: {'yes' if map_tiles.tile_loaded_any else 'no'}")
def main() -> int:
args = parse_args()
route = parse_route_id(args.routeid)
session = requests.Session()
session.headers.update({"User-Agent": "starpilot-speed-limit-route-bundler/1.0"})
try:
validation = validate_route(route, session, args.timeout)
print_validation_summary(route, validation)
if args.validate_only:
return 0
bundle_root, zip_path = download_bundle(route, validation, session, args.desktop_root, args.timeout, args.overwrite)
print(f"Bundle folder: {bundle_root}")
print(f"Bundle zip: {zip_path}")
return 0
except ValidationError as exc:
print(str(exc), file=sys.stderr)
return 2
except FileExistsError as exc:
print(f"{exc}\nUse --overwrite to replace the existing Desktop bundle, or --validate-only to skip packaging.", file=sys.stderr)
return 3
except Exception as exc:
print(f"Error: {exc}", file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())
+2 -2
View File
@@ -32,10 +32,10 @@ nav:
- What is a car port?: car-porting/what-is-a-car-port.md
- Porting a car brand: car-porting/brand-port.md
- Porting a car model: car-porting/model-port.md
- Contributing:
- Contribute:
- Contributing Guide: contributing/contribute.md
- Roadmap: contributing/roadmap.md
#- Architecture: contributing/architecture.md
- Contributing Guide →: https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md
- Links:
- Blog →: https://blog.comma.ai
- Bounties →: https://comma.ai/bounties
+3
View File
@@ -21,6 +21,9 @@ static size_t fnv1a_hash(const std::string &str) {
static std::string namespaced_endpoint(std::string endpoint) {
const char *namespace_env = std::getenv("OPENPILOT_ZMQ_NAMESPACE");
if (namespace_env == nullptr || namespace_env[0] == '\0') {
namespace_env = std::getenv("OPENPILOT_PREFIX");
}
if (namespace_env != nullptr && namespace_env[0] != '\0') {
endpoint = std::string(namespace_env) + ":" + endpoint;
}
-4
View File
@@ -15,10 +15,6 @@ const bool MUST_USE_ZMQ = false;
bool messaging_use_zmq(){
if (std::getenv("ZMQ") || MUST_USE_ZMQ) {
if (std::getenv("OPENPILOT_PREFIX")) {
std::cerr << "OPENPILOT_PREFIX not supported with ZMQ backend\n";
assert(false);
}
return true;
}
return false;
Binary file not shown.
@@ -61,6 +61,7 @@ class TestVisionIpc:
recv_buf = self.client.recv()
assert recv_buf is not None
assert recv_buf.data.view('<i4')[0] == 1234
assert recv_buf.frame_id == 1337
assert self.client.frame_id == 1337
del self.client
del self.server
+1
View File
@@ -30,6 +30,7 @@ cdef extern from "msgq/visionipc/visionbuf.h":
size_t idx
cl_mem buf_cl
void set_frame_id(uint64_t id)
uint64_t get_frame_id()
cdef extern from "msgq/visionipc/visionipc.h":
struct VisionIpcBufExtra:
@@ -67,6 +67,10 @@ cdef class VisionBuf:
def fd(self):
return self.buf.fd
@property
def frame_id(self):
return self.buf.get_frame_id()
cdef class VisionIpcServer:
cdef cppVisionIpcServer * server
Binary file not shown.
+1 -1
View File
@@ -19,7 +19,7 @@ test:
run: codespell {files} -L tge,stdio -S *.dbc
files: git ls-tree -r HEAD --name-only
cpplint:
run: cpplint --exclude=opendbc/safety/tests/misra/cppcheck/ --exclude=opendbc/can/*_pyx.cpp --recursive --quiet --counting=detailed --linelength=240 --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces opendbc/
run: cpplint --exclude=opendbc/safety/tests/misra/cppcheck/ --exclude=opendbc/safety/tests/.venv/ --exclude=opendbc/can/*_pyx.cpp --recursive --quiet --counting=detailed --linelength=240 --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces opendbc/
misra:
run: opendbc/safety/tests/misra/test_misra.sh
+2 -2
View File
@@ -106,7 +106,7 @@ def make_tester_present_msg(addr, bus, subaddr=None, suppress_response=False):
return CanData(addr, bytes(dat), bus)
def get_safety_config(safety_model: structs.CarParams.SafetyModel, safety_param: int = None) -> structs.CarParams.SafetyConfig:
def get_safety_config(safety_model, safety_param: int = None) -> structs.CarParams.SafetyConfig:
ret = structs.CarParams.SafetyConfig()
ret.safetyModel = safety_model
if safety_param is not None:
@@ -122,7 +122,7 @@ class CanBusBase:
assert fingerprint is not None
num = max([k for k, v in fingerprint.items() if len(v)], default=0) // 4 + 1
else:
num = len(CP.safetyConfigs)
num = max(1, len(CP.safetyConfigs))
self.offset = 4 * (num - 1)
+24 -2
View File
@@ -11,6 +11,7 @@ from opendbc.car.structs import CarParams, CarParamsT
from opendbc.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars
from opendbc.car.fw_versions import ObdCallback, get_fw_versions_ordered, get_present_ecus, match_fw_to_car
from opendbc.car.mock.values import CAR as MOCK
from opendbc.car.toyota.values import ToyotaSafetyFlags
from opendbc.car.values import BRANDS
from opendbc.car.vin import get_vin, is_valid_vin, VIN_UNKNOWN
from openpilot.common.params import Params
@@ -108,6 +109,20 @@ def _normalize_gm_bolt_candidate(candidate: str | None, fingerprints: dict[int,
return candidate
def _apply_disable_openpilot_long(CP: CarParams, FPCP: StarPilotCarParams) -> None:
CP.openpilotLongitudinalControl = False
CP.pcmCruise = True
FPCP.openpilotLongitudinalControlDisabled = True
if CP.brand == "toyota":
# Toyota stock longitudinal safety changes the forwarding rules so the
# camera's ACC_CONTROL message can reach the PT bus again.
for cfg in CP.safetyConfigs:
cfg.safetyParam |= ToyotaSafetyFlags.STOCK_LONGITUDINAL.value
for cfg in FPCP.safetyConfigs:
cfg.safetyParam |= ToyotaSafetyFlags.STOCK_LONGITUDINAL.value
def _normalize_gm_volt_candidate(candidate: str | None, fingerprints: dict[int, dict]) -> str | None:
cam = fingerprints.get(GM_CAMERA_BUS, {})
has_live_camera_msg = GM_VOLT_CAMERA_MSG in cam
@@ -196,6 +211,11 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
disable_fw_cache = os.environ.get('DISABLE_FW_CACHE', False)
ecu_rx_addrs = set()
if not fixed_fingerprint and Params().get_bool("NAPForcePreAP"):
fixed_fingerprint = "TESLA_MODEL_S_PREAP"
skip_fw_query = True
carlog.warning("NAPForcePreAP enabled; forcing TESLA_MODEL_S_PREAP fingerprint")
start_time = time.monotonic()
if not skip_fw_query:
if cached_params is not None and cached_params.brand != "mock" and len(cached_params.carFw) > 0 and \
@@ -314,12 +334,14 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip
CP.carFw = car_fw
CP.fingerprintSource = source
CP.fuzzyFingerprint = not exact_match
post_fingerprint_params = getattr(CarInterface, "apply_post_fingerprint_params", None)
if post_fingerprint_params is not None:
post_fingerprint_params(CP, candidate, fingerprints, car_fw)
FPCP: StarPilotCarParams = CarInterface.get_starpilot_params(candidate, fingerprints, car_fw, CP, starpilot_toggles)
if not CP.alphaLongitudinalAvailable and starpilot_toggles.disable_openpilot_long:
CP.openpilotLongitudinalControl = False
FPCP.openpilotLongitudinalControlDisabled = True
_apply_disable_openpilot_long(CP, FPCP)
return interfaces[CP.carFingerprint](CP, FPCP)
@@ -2,9 +2,28 @@ from opendbc.can import CANPacker
from opendbc.car import Bus, DT_CTRL
from opendbc.car.lateral import apply_meas_steer_torque_limits
from opendbc.car.chrysler import chryslercan
from opendbc.car.chrysler.values import RAM_CARS, RAM_DT, CarControllerParams, ChryslerFlags
from opendbc.car.chrysler.values import JEEPS, RAM_CARS, RAM_DT, CarControllerParams, ChryslerFlags, ChryslerSafetyFlags, ChryslerStarPilotFlags
from opendbc.car.interfaces import CarControllerBase
JEEP_BRAKE_HOLD_DEFAULT_DECEL = -2.0
JEEP_BRAKE_HOLD_MIN_DECEL = -0.5
JEEP_BRAKE_HOLD_MAX_DECEL = -3.0
def clip_jeep_brake_hold_decel(decel: float) -> float:
return max(JEEP_BRAKE_HOLD_MAX_DECEL, min(JEEP_BRAKE_HOLD_MIN_DECEL, float(decel)))
def supports_jeep_brake_hold(CP, brake_hold_enabled: bool) -> bool:
safety_cfg = getattr(CP, "safetyConfigs", ())
safety_param = safety_cfg[0].safetyParam if safety_cfg else 0
return (
brake_hold_enabled and
getattr(CP, "pcmCruise", False) and
CP.carFingerprint in JEEPS and
bool(safety_param & ChryslerSafetyFlags.JEEP_BRAKE_HOLD.value)
)
class CarController(CarControllerBase):
def __init__(self, dbc_names, CP):
@@ -18,6 +37,8 @@ class CarController(CarControllerBase):
self.packer = CANPacker(dbc_names[Bus.pt])
self.params = CarControllerParams(CP)
self.jeep_brake_hold_decel = JEEP_BRAKE_HOLD_DEFAULT_DECEL
self.last_das_3_counter = -1
def update(self, CC, CS, now_nanos, starpilot_toggles):
can_sends = []
@@ -50,7 +71,9 @@ class CarController(CarControllerBase):
# TODO: can we make this more sane? why is it different for all the cars?
lkas_control_bit = self.lkas_control_bit_prev
if self.CP.carFingerprint in RAM_DT:
if self.FPCP is not None and self.FPCP.flags & ChryslerStarPilotFlags.NO_MIN_STEERING_SPEED:
lkas_control_bit = CC.latActive
elif self.CP.carFingerprint in RAM_DT:
if self.CP.minEnableSpeed <= CS.out.vEgo <= self.CP.minEnableSpeed + 0.5:
lkas_control_bit = True
if (self.CP.minEnableSpeed >= 14.5) and (CS.out.gearShifter != 2):
@@ -80,6 +103,11 @@ class CarController(CarControllerBase):
can_sends.append(chryslercan.create_lkas_command(self.packer, self.CP, int(apply_torque), lkas_control_bit))
if supports_jeep_brake_hold(self.CP, getattr(starpilot_toggles, "jeep_brake_hold", False)):
self.update_jeep_brake_hold(CC, CS, can_sends)
elif getattr(CS, "brake_hold", False):
CS.brake_hold = False
self.frame += 1
new_actuators = CC.actuators.as_builder()
@@ -87,3 +115,43 @@ class CarController(CarControllerBase):
new_actuators.torqueOutputCan = self.apply_torque_last
return new_actuators, can_sends
def update_jeep_brake_hold(self, CC, CS, can_sends):
if not getattr(CS, "das_3", None):
CS.brake_hold = False
return
counter_changed = CS.das_3.get("COUNTER") != self.last_das_3_counter
self.last_das_3_counter = CS.das_3.get("COUNTER")
if not CS.brake_hold and CS.cruise_active_actual and CS.acc_decelerating and CS.out.standstill:
CS.brake_hold = True
self.jeep_brake_hold_decel = JEEP_BRAKE_HOLD_DEFAULT_DECEL
driver_intervened = (
CC.cruiseControl.cancel or
CS.out.gasPressed or
CS.out.brakePressed or
not CS.forward_gear or
not CS.out.standstill
)
if CS.brake_hold and driver_intervened:
CS.brake_hold = False
return
if not CS.brake_hold:
return
if CS.cruise_active_actual:
self.jeep_brake_hold_decel = clip_jeep_brake_hold_decel(
min(self.jeep_brake_hold_decel, CS.das_3.get("ACC_DECEL", JEEP_BRAKE_HOLD_DEFAULT_DECEL))
)
return
counter_offset = 2 if counter_changed else 3
can_sends.append(chryslercan.create_das_3_command(self.packer, counter_offset, self.jeep_brake_hold_decel, CS.das_3))
if self.frame % 10 == 0:
can_sends.append(chryslercan.create_cruise_buttons(
self.packer, CS.button_counter + 1, 0, CS.button_message, resume=True
))
+13 -1
View File
@@ -1,7 +1,7 @@
from cereal import custom
from opendbc.can import CANDefine, CANParser
from opendbc.car import Bus, create_button_events, structs
from opendbc.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS, ChryslerStarPilotFlags
from opendbc.car.chrysler.values import DBC, JEEPS, STEER_THRESHOLD, RAM_CARS, ChryslerStarPilotFlags
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.interfaces import CarStateBase
@@ -29,6 +29,11 @@ class CarState(CarStateBase):
self.button_message = "CRUISE_BUTTONS_ALT" if FPCP.flags & ChryslerStarPilotFlags.RAM_HD_ALT_BUTTONS else "CRUISE_BUTTONS"
self.lkas_button = 0
self.brake_hold = False
self.cruise_active_actual = False
self.forward_gear = False
self.acc_decelerating = False
self.das_3 = {}
@staticmethod
def get_lkas_button(pt_signals, is_ram: bool) -> bool:
@@ -93,6 +98,13 @@ class CarState(CarStateBase):
ret.cruiseState.standstill = cp_cruise.vl["DAS_3"]["ACC_STANDSTILL"] == 1
ret.accFaulted = cp_cruise.vl["DAS_3"]["ACC_FAULTED"] != 0
if self.CP.carFingerprint in JEEPS:
self.forward_gear = ret.gearShifter == structs.CarState.GearShifter.drive
self.cruise_active_actual = ret.cruiseState.enabled
self.acc_decelerating = cp_cruise.vl["DAS_3"]["ACC_DECEL"] < -0.5
self.das_3 = dict(cp_cruise.vl["DAS_3"])
ret.brakeHoldActive = self.brake_hold
if self.CP.carFingerprint in RAM_CARS:
# Auto High Beam isn't Located in this message on chrysler or jeep currently located in 729 message
self.auto_high_beam = cp_cam.vl["DAS_6"]['AUTO_HIGH_BEAM_ON']
@@ -73,6 +73,21 @@ def create_cruise_buttons(packer, frame, bus, button_message, cancel=False, resu
return packer.make_can_msg(button_message, bus, values)
def create_das_3_command(packer, counter_offset, brake_decel, das_3):
values = das_3.copy()
values["ACC_AVAILABLE"] = 1
values["ACC_ACTIVE"] = 1
values["ACC_GO"] = 0
values["ACC_STANDSTILL"] = 0
values["ACC_DECEL_REQ"] = 1
values["ACC_DECEL"] = brake_decel
values["ACC_BRK_PREP"] = 0
values["ENGINE_TORQUE_REQUEST_MAX"] = 0
values["GR_MAX_REQ"] = 2
values["COUNTER"] = (das_3["COUNTER"] + counter_offset) % 0x10
return packer.make_can_msg("DAS_3", 0, values)
def chrysler_checksum(address: int, sig, d: bytearray) -> int:
checksum = 0xFF
for j in range(len(d) - 1):
@@ -3,7 +3,7 @@ from opendbc.car import get_safety_config, structs
from opendbc.car.chrysler.carcontroller import CarController
from opendbc.car.chrysler.carstate import CarState
from opendbc.car.chrysler.radar_interface import RadarInterface
from opendbc.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerSafetyFlags
from opendbc.car.chrysler.values import CAR, JEEPS, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerSafetyFlags
from opendbc.car.interfaces import CarInterfaceBase
@@ -28,6 +28,8 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[0].safetyParam |= ChryslerSafetyFlags.RAM_HD.value
elif candidate in RAM_DT:
ret.safetyConfigs[0].safetyParam |= ChryslerSafetyFlags.RAM_DT.value
elif candidate in JEEPS:
ret.safetyConfigs[0].safetyParam |= ChryslerSafetyFlags.JEEP_BRAKE_HOLD.value
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if candidate not in RAM_CARS:
@@ -12,6 +12,7 @@ Ecu = CarParams.Ecu
class ChryslerSafetyFlags(IntFlag):
RAM_DT = 1
RAM_HD = 2
JEEP_BRAKE_HOLD = 4
class ChryslerFlags(IntFlag):
@@ -21,6 +22,7 @@ class ChryslerFlags(IntFlag):
class ChryslerStarPilotFlags(IntFlag):
RAM_HD_ALT_BUTTONS = 1
NO_MIN_STEERING_SPEED = 2
@dataclass
@@ -97,6 +99,25 @@ class CAR(Platforms):
)
PACIFICA_HYBRID_AOL_CARS = frozenset({
CAR.CHRYSLER_PACIFICA_2019_HYBRID,
})
def pacifica_hybrid_aol_requires_set_press(car_fingerprint, pcm_cruise: bool) -> bool:
return car_fingerprint in PACIFICA_HYBRID_AOL_CARS and pcm_cruise
def pacifica_hybrid_aol_stock_acc_mode(car_fingerprint, pcm_cruise: bool,
controls_enabled: bool, always_on_lateral_enabled: bool) -> bool:
# Keep this narrow until we have logs proving other Chrysler platforms need the same exemption.
return (
pacifica_hybrid_aol_requires_set_press(car_fingerprint, pcm_cruise) and
always_on_lateral_enabled and
not controls_enabled
)
class CarControllerParams:
def __init__(self, CP):
self.STEER_STEP = 2 # 50 Hz
@@ -120,6 +141,7 @@ STEER_THRESHOLD = 120
RAM_DT = {CAR.RAM_1500_5TH_GEN, }
RAM_HD = {CAR.RAM_HD_5TH_GEN, }
RAM_CARS = RAM_DT | RAM_HD
JEEPS = {CAR.JEEP_GRAND_CHEROKEE, CAR.JEEP_GRAND_CHEROKEE_2019}
CHRYSLER_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
+18 -1
View File
@@ -5,6 +5,8 @@ from opendbc.car.isotp_parallel_query import IsoTpParallelQuery
EXT_DIAG_REQUEST = b'\x10\x03'
EXT_DIAG_RESPONSE = b'\x50\x03'
RESET_REQUEST = b'\x11\x01'
RESET_RESPONSE = b''
# File-based logging for debugging
ECU_LOG_FILE = "/data/ecu_disable.log"
@@ -21,7 +23,7 @@ def ecu_log(msg):
pass
def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_req=b'\x28\x83\x01', timeout=0.1, retry=10):
def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_req=b'\x28\x83\x01', timeout=0.1, retry=10, reset=False):
"""Silence an ECU by disabling sending and receiving messages using UDS 0x28.
The ECU will stay silent as long as openpilot keeps sending Tester Present.
@@ -29,6 +31,15 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
WARNING: THIS DISABLES AEB!"""
ecu_log(f"=== ECU DISABLE START === addr={hex(addr)}, bus={bus}")
if reset:
try:
ecu_log("sending ECU reset before communication control...")
reset_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [RESET_REQUEST], [RESET_RESPONSE])
reset_query.get_data(timeout=timeout)
time.sleep(0.2)
except Exception as e:
ecu_log(f"reset exception: {e}")
# Try multiple times with different approaches
for i in range(retry):
try:
@@ -50,6 +61,7 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
# Log what we got back
cc_success = False
cc_rejected = False
cc_nrc = None
for (rx_addr, _), data in cc_response.items():
ecu_log(f"CC response: {data.hex() if data else 'empty'}")
# Check for positive response (0x68 = 0x28 + 0x40)
@@ -59,6 +71,7 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
# Check for negative response
elif len(data) >= 3 and data[0] == 0x7F:
nrc = data[2]
cc_nrc = nrc
nrc_meanings = {
0x12: "subFunctionNotSupported",
0x13: "incorrectMessageLengthOrInvalidFormat",
@@ -73,6 +86,10 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
if cc_success:
return True
elif cc_rejected:
if reset and cc_nrc == 0x22 and i < retry - 1:
ecu_log("CC rejected with NRC 0x22 after reset; retrying...")
time.sleep(0.2)
continue
# ECU explicitly rejected - don't retry, it won't work
ecu_log("=== ECU DISABLE REJECTED ===")
return False
+3 -1
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import argparse
import os
from types import SimpleNamespace
from typing import get_args
from collections import defaultdict
@@ -32,7 +33,8 @@ def get_params_for_docs(platform) -> CarParams:
cp_platform = platform if platform in interfaces else MOCK.MOCK
CP: CarParams = interfaces[cp_platform].get_params(cp_platform, fingerprint=gen_empty_fingerprint(),
car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)],
alpha_long=True, is_release=False, docs=True)
alpha_long=True, is_release=False, docs=True,
starpilot_toggles=SimpleNamespace())
return CP
@@ -131,6 +131,7 @@ class CarHarness(EnumBase):
hyundai_p = BaseCarHarness("Hyundai P connector")
hyundai_q = BaseCarHarness("Hyundai Q connector")
hyundai_r = BaseCarHarness("Hyundai R connector")
hyundai_s = BaseCarHarness("Hyundai S connector")
custom = BaseCarHarness("Developer connector")
obd_ii = BaseCarHarness("OBD-II connector", parts=[Cable.long_obdc_cable, Cable.usbc_coupler], has_connector=False)
gm = BaseCarHarness("GM connector", parts=[Accessory.harness_box])
+25 -1
View File
@@ -72,6 +72,7 @@ MIGRATION = {
"HONDA CR-V 2016 TOURING": HONDA.HONDA_CRV,
"HONDA CR-V 2017 EX": HONDA.HONDA_CRV_5G,
"HONDA CR-V 2019 HYBRID": HONDA.HONDA_CRV_HYBRID,
"HONDA CLARITY 2018": HONDA.HONDA_CLARITY,
"HONDA FIT 2018 EX": HONDA.HONDA_FIT,
"HONDA HRV 2019 TOURING": HONDA.HONDA_HRV,
"HONDA INSIGHT 2019 TOURING": HONDA.HONDA_INSIGHT,
@@ -192,28 +193,43 @@ MIGRATION = {
"HYUNDAI IONIQ PLUG-IN HYBRID 2019": HYUNDAI.HYUNDAI_IONIQ_PHEV_2019,
"HYUNDAI IONIQ PHEV 2020": HYUNDAI.HYUNDAI_IONIQ_PHEV,
"HYUNDAI KONA 2020": HYUNDAI.HYUNDAI_KONA,
"HYUNDAI KONA 2ND GEN": HYUNDAI.HYUNDAI_KONA_2ND_GEN,
"HYUNDAI KONA ELECTRIC 2019": HYUNDAI.HYUNDAI_KONA_EV,
"HYUNDAI KONA ELECTRIC 2022": HYUNDAI.HYUNDAI_KONA_EV_2022,
"HYUNDAI KONA ELECTRIC 2ND GEN": HYUNDAI.HYUNDAI_KONA_EV_2ND_GEN,
"HYUNDAI KONA HYBRID 2020": HYUNDAI.HYUNDAI_KONA_HEV,
"HYUNDAI KONA HYBRID 2ND GEN": HYUNDAI.HYUNDAI_KONA_HEV_2ND_GEN,
"HYUNDAI SANTA FE 2019": HYUNDAI.HYUNDAI_SANTA_FE,
"HYUNDAI SANTA FE 2022": HYUNDAI.HYUNDAI_SANTA_FE_2022,
"HYUNDAI SANTA FE HYBRID 2022": HYUNDAI.HYUNDAI_SANTA_FE_HEV_2022,
"HYUNDAI SANTA FE HYBRID 5TH GEN": HYUNDAI.HYUNDAI_SANTA_FE_HEV_5TH_GEN,
"HYUNDAI SANTA FE PlUG-IN HYBRID 2022": HYUNDAI.HYUNDAI_SANTA_FE_PHEV_2022,
"HYUNDAI SONATA 2020": HYUNDAI.HYUNDAI_SONATA,
"HYUNDAI SONATA 2024": HYUNDAI.HYUNDAI_SONATA_2024,
"HYUNDAI SONATA 2019": HYUNDAI.HYUNDAI_SONATA_LF,
"HYUNDAI STARIA 4TH GEN": HYUNDAI.HYUNDAI_STARIA_4TH_GEN,
"HYUNDAI TUCSON 2019": HYUNDAI.HYUNDAI_TUCSON,
"HYUNDAI TUCSON 2025": HYUNDAI.HYUNDAI_TUCSON_2025,
"HYUNDAI TUCSON HYBRID 2025": HYUNDAI.HYUNDAI_TUCSON_HEV_2025,
"HYUNDAI TUCSON PLUG-IN HYBRID 2025": HYUNDAI.HYUNDAI_TUCSON_PHEV_2025,
"HYUNDAI PALISADE 2020": HYUNDAI.HYUNDAI_PALISADE,
"HYUNDAI PALISADE 2023": HYUNDAI.HYUNDAI_PALISADE_2023,
"HYUNDAI VELOSTER 2019": HYUNDAI.HYUNDAI_VELOSTER,
"HYUNDAI SONATA HYBRID 2021": HYUNDAI.HYUNDAI_SONATA_HYBRID,
"HYUNDAI SONATA HYBRID 2024": HYUNDAI.HYUNDAI_SONATA_HEV_2024,
"HYUNDAI IONIQ 5 2022": HYUNDAI.HYUNDAI_IONIQ_5,
"HYUNDAI IONIQ 5 2025": HYUNDAI.HYUNDAI_IONIQ_5_PE,
"HYUNDAI IONIQ 5 N 2024": HYUNDAI.HYUNDAI_IONIQ_5_N,
"HYUNDAI IONIQ 6 2023": HYUNDAI.HYUNDAI_IONIQ_6,
"HYUNDAI IONIQ 9 2025": HYUNDAI.HYUNDAI_IONIQ_9,
"HYUNDAI TUCSON 4TH GEN": HYUNDAI.HYUNDAI_TUCSON_4TH_GEN,
"HYUNDAI SANTA CRUZ 1ST GEN": HYUNDAI.HYUNDAI_SANTA_CRUZ_1ST_GEN,
"HYUNDAI SANTA CRUZ 2025": HYUNDAI.HYUNDAI_SANTA_CRUZ_2025,
"HYUNDAI CUSTIN 1ST GEN": HYUNDAI.HYUNDAI_CUSTIN_1ST_GEN,
"KIA FORTE E 2018 & GT 2021": HYUNDAI.KIA_FORTE,
"KIA K4 2025": HYUNDAI.KIA_K4_2025,
"KIA K5 2021": HYUNDAI.KIA_K5_2021,
"KIA K5 2025": HYUNDAI.KIA_K5_2025,
"KIA K5 HYBRID 2020": HYUNDAI.KIA_K5_HEV_2020,
"KIA K8 HYBRID 1ST GEN": HYUNDAI.KIA_K8_HEV_1ST_GEN,
"KIA NIRO EV 2020": HYUNDAI.KIA_NIRO_EV,
@@ -228,22 +244,30 @@ MIGRATION = {
"KIA OPTIMA HYBRID 4TH GEN FACELIFT": HYUNDAI.KIA_OPTIMA_H_G4_FL,
"KIA SELTOS 2021": HYUNDAI.KIA_SELTOS,
"KIA SPORTAGE 5TH GEN": HYUNDAI.KIA_SPORTAGE_5TH_GEN,
"KIA SPORTAGE HYBRID 2026": HYUNDAI.KIA_SPORTAGE_HEV_2026,
"KIA SPORTAGE 2026": HYUNDAI.KIA_SPORTAGE_2026,
"KIA SORENTO GT LINE 2018": HYUNDAI.KIA_SORENTO,
"KIA SORENTO 4TH GEN": HYUNDAI.KIA_SORENTO_4TH_GEN,
"KIA SORENTO 2024": HYUNDAI.KIA_SORENTO_2024,
"KIA SORENTO HYBRID 4TH GEN": HYUNDAI.KIA_SORENTO_HEV_4TH_GEN,
"KIA SORENTO HYBRID 4TH GEN LFA2": HYUNDAI.KIA_SORENTO_HEV_4TH_GEN_LFA2,
"KIA STINGER GT2 2018": HYUNDAI.KIA_STINGER,
"KIA STINGER 2022": HYUNDAI.KIA_STINGER_2022,
"KIA CEED INTRO ED 2019": HYUNDAI.KIA_CEED,
"KIA EV6 2022": HYUNDAI.KIA_EV6,
"KIA EV6 2025": HYUNDAI.KIA_EV6_2025,
"KIA EV9 2025": HYUNDAI.KIA_EV9,
"KIA CARNIVAL 4TH GEN": HYUNDAI.KIA_CARNIVAL_4TH_GEN,
"KIA CARNIVAL 2025": HYUNDAI.KIA_CARNIVAL_2025,
"KIA CARNIVAL HYBRID 4TH GEN": HYUNDAI.KIA_CARNIVAL_HEV_4TH_GEN,
"GENESIS GV60 ELECTRIC 1ST GEN": HYUNDAI.GENESIS_GV60_EV_1ST_GEN,
"GENESIS G70 2018": HYUNDAI.GENESIS_G70,
"GENESIS G70 2020": HYUNDAI.GENESIS_G70_2020,
"GENESIS GV70 1ST GEN": HYUNDAI.GENESIS_GV70_1ST_GEN,
"GENESIS GV70 ELECTRIFIED 2026": HYUNDAI.GENESIS_GV70_ELECTRIFIED_2ND_GEN,
"GENESIS G80 2017": HYUNDAI.GENESIS_G80,
"GENESIS G90 2017": HYUNDAI.GENESIS_G90,
"GENESIS GV80 2023": HYUNDAI.GENESIS_GV80,
"GENESIS GV80 2025": HYUNDAI.GENESIS_GV80_2025,
"MAZDA CX-5": MAZDA.MAZDA_CX5,
"MAZDA CX-9": MAZDA.MAZDA_CX9,
"MAZDA 3": MAZDA.MAZDA_3,
+59 -27
View File
@@ -16,6 +16,11 @@ AVERAGE_ROAD_ROLL = 0.06 # ~3.4 degrees, 6% superelevation. higher actual roll
MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL - (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL) # ~2.4 m/s^2
def apply_ford_angle(desired_angle_deg: float, current_angle_deg: float) -> float:
relative_angle = desired_angle_deg - current_angle_deg
return float(np.clip(relative_angle, -5.8, 5.8))
def anti_overshoot(apply_curvature, apply_curvature_last, v_ego):
diff = 0.1
tau = 5 # 5s smooths over the overshoot
@@ -65,6 +70,7 @@ class CarController(CarControllerBase):
self.CAN = fordcan.CanBus(CP)
self.apply_curvature_last = 0
self.apply_angle_last = 0
self.anti_overshoot_curvature_last = 0
self.accel = 0.0
self.gas = 0.0
@@ -98,38 +104,62 @@ class CarController(CarControllerBase):
can_sends.append(fordcan.create_button_msg(self.packer, self.CAN.camera, CS.buttons_stock_values, tja_toggle=True))
### lateral control ###
# send steer msg at 20Hz
if (self.frame % CarControllerParams.STEER_STEP) == 0:
# Bronco and some other cars consistently overshoot curv requests
# Apply some deadzone + smoothing convergence to avoid oscillations
if self.CP.carFingerprint in (CAR.FORD_BRONCO_SPORT_MK1, CAR.FORD_F_150_MK14):
self.anti_overshoot_curvature_last = anti_overshoot(actuators.curvature, self.anti_overshoot_curvature_last, CS.out.vEgoRaw)
apply_curvature = self.anti_overshoot_curvature_last
if self.CP.flags & FordFlags.LKA_STEERING:
lka_active = CC.latActive and CS.lkas_available
if lka_active:
self.apply_angle_last = apply_ford_angle(actuators.steeringAngleDeg, CS.out.steeringAngleDeg)
current_curvature = -CS.out.yawRate / max(CS.out.vEgoRaw, 0.1)
self.apply_curvature_last = apply_ford_curvature_limits(actuators.curvature, self.apply_curvature_last, current_curvature,
CS.out.vEgoRaw, 0., True, self.CP)
else:
apply_curvature = actuators.curvature
self.apply_angle_last = 0.
self.apply_curvature_last = 0.
# apply rate limits, curvature error limit, and clip to signal range
current_curvature = -CS.out.yawRate / max(CS.out.vEgoRaw, 0.1)
# Keep the stock LMC heartbeat present while steering through Lane_Assist_Data1.
if (self.frame % CarControllerParams.STEER_STEP) == 0:
can_sends.append(fordcan.create_lat_ctl_msg(self.packer, self.CAN, False, 0., 0., 0., 0.,
stock_lmc=CS.lateral_motion_control))
self.apply_curvature_last = apply_ford_curvature_limits(apply_curvature, self.apply_curvature_last, current_curvature,
CS.out.vEgoRaw, 0., CC.latActive, self.CP)
if (self.frame % CarControllerParams.LKA_STEP) == 0:
direction = 0
if lka_active:
direction = 2 if CS.out.steeringAngleDeg > 0 else 4
ramp_type = 1 if abs(self.apply_angle_last) >= 5 else 0
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN, active=lka_active, apply_angle=self.apply_angle_last,
direction=direction, ramp_type=ramp_type, curvature=-self.apply_curvature_last))
else:
# send steer msg at 20Hz
if (self.frame % CarControllerParams.STEER_STEP) == 0:
# Bronco and some other cars consistently overshoot curv requests
# Apply some deadzone + smoothing convergence to avoid oscillations
if self.CP.carFingerprint in (CAR.FORD_BRONCO_SPORT_MK1, CAR.FORD_F_150_MK14):
self.anti_overshoot_curvature_last = anti_overshoot(actuators.curvature, self.anti_overshoot_curvature_last, CS.out.vEgoRaw)
apply_curvature = self.anti_overshoot_curvature_last
else:
apply_curvature = actuators.curvature
if self.CP.flags & FordFlags.CANFD:
# TODO: extended mode
# Ford uses four individual signals to dictate how to drive to the car. Curvature alone (limited to 0.02m/s^2)
# can actuate the steering for a large portion of any lateral movements. However, in order to get further control on
# steer actuation, the other three signals are necessary. Ford controls vehicles differently than most other makes.
# A detailed explanation on ford control can be found here:
# https://www.f150gen14.com/forum/threads/introducing-bluepilot-a-ford-specific-fork-for-comma3x-openpilot.24241/#post-457706
mode = 1 if CC.latActive else 0
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
can_sends.append(fordcan.create_lat_ctl2_msg(self.packer, self.CAN, mode, 0., 0., -self.apply_curvature_last, 0., counter))
else:
can_sends.append(fordcan.create_lat_ctl_msg(self.packer, self.CAN, CC.latActive, 0., 0., -self.apply_curvature_last, 0.))
# apply rate limits, curvature error limit, and clip to signal range
current_curvature = -CS.out.yawRate / max(CS.out.vEgoRaw, 0.1)
# send lka msg at 33Hz
if (self.frame % CarControllerParams.LKA_STEP) == 0:
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN))
self.apply_curvature_last = apply_ford_curvature_limits(apply_curvature, self.apply_curvature_last, current_curvature,
CS.out.vEgoRaw, 0., CC.latActive, self.CP)
if self.CP.flags & FordFlags.CANFD:
# TODO: extended mode
# Ford uses four individual signals to dictate how to drive to the car. Curvature alone (limited to 0.02m/s^2)
# can actuate the steering for a large portion of any lateral movements. However, in order to get further control on
# steer actuation, the other three signals are necessary. Ford controls vehicles differently than most other makes.
# A detailed explanation on ford control can be found here:
# https://www.f150gen14.com/forum/threads/introducing-bluepilot-a-ford-specific-fork-for-comma3x-openpilot.24241/#post-457706
mode = 1 if CC.latActive else 0
counter = (self.frame // CarControllerParams.STEER_STEP) % 0x10
can_sends.append(fordcan.create_lat_ctl2_msg(self.packer, self.CAN, mode, 0., 0., -self.apply_curvature_last, 0., counter))
else:
can_sends.append(fordcan.create_lat_ctl_msg(self.packer, self.CAN, CC.latActive, 0., 0., -self.apply_curvature_last, 0.))
# send lka msg at 33Hz
if (self.frame % CarControllerParams.LKA_STEP) == 0:
can_sends.append(fordcan.create_lka_msg(self.packer, self.CAN))
### longitudinal control ###
# send acc msg at 50Hz
@@ -195,6 +225,8 @@ class CarController(CarControllerBase):
self.lead_distance_bars_last = hud_control.leadDistanceBars
new_actuators = actuators.as_builder()
if self.CP.flags & FordFlags.LKA_STEERING:
new_actuators.steeringAngleDeg = self.apply_angle_last + CS.out.steeringAngleDeg
new_actuators.curvature = self.apply_curvature_last
new_actuators.accel = self.accel
new_actuators.gas = self.gas
+11
View File
@@ -20,6 +20,8 @@ class CarState(CarStateBase):
self.distance_button = 0
self.lc_button = 0
self.lkas_available = False
self.lateral_motion_control = None
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
cp = can_parsers[Bus.pt]
@@ -108,6 +110,15 @@ class CarState(CarStateBase):
# Stock values from IPMA so that we can retain some stock functionality
self.acc_tja_status_stock_values = cp_cam.vl["ACCDATA_3"]
self.lkas_status_stock_values = cp_cam.vl["IPMA_Data"]
if self.CP.flags & FordFlags.LKA_STEERING:
try:
self.lkas_available = cp.vl["Lane_Assist_Data3_FD1"]["LaActAvail_D_Actl"] == 3
except KeyError:
self.lkas_available = False
try:
self.lateral_motion_control = cp_cam.vl["LateralMotionControl"]
except KeyError:
self.lateral_motion_control = None
ret.buttonEvents = [
*create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}),
@@ -106,10 +106,12 @@ FW_VERSIONS = {
},
CAR.FORD_F_150_MK14: {
(Ecu.eps, 0x730, None): [
b'ML3V-14D003-BA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3V-14D003-BC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3V-14D003-BD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.abs, 0x760, None): [
b'ML34-2D053-AJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'NL34-2D053-CA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PL34-2D053-CA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PL34-2D053-CC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -117,6 +119,7 @@ FW_VERSIONS = {
b'PL3V-2D053-BB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x764, None): [
b'ML3T-14D049-AH\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14D049-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
@@ -124,6 +127,7 @@ FW_VERSIONS = {
b'ML3T-14H102-ABR\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14H102-ABS\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14H102-ABT\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'ML3T-14H102-ACA\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PJ6T-14H102-ABJ\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PJ6T-14H102-ABS\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RJ6T-14H102-ACJ\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -211,6 +215,7 @@ FW_VERSIONS = {
b'PB3C-2D053-ZD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB3C-2D053-ZG\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'PB3C-2D053-ZJ\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
b'RB3C-2D053-AK\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x764, None): [
b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
@@ -220,4 +225,18 @@ FW_VERSIONS = {
b'RJ6T-14H102-BBB\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
},
CAR.FORD_TRANSIT_MK5: {
(Ecu.eps, 0x730, None): [
b'KK21-14D003-AM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.abs, 0x760, None): [
b'NK41-2D053-DF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x764, None): [
b'PC4T-14D049-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x706, None): [
b'NK3T-14F397-AB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
],
},
}
+54 -19
View File
@@ -1,3 +1,5 @@
import math
from opendbc.car import CanBusBase, structs
HUDControl = structs.CarControl.HUDControl
@@ -33,20 +35,40 @@ def calculate_lat_ctl2_checksum(mode: int, counter: int, dat: bytearray) -> int:
return 0xFF - (checksum & 0xFF)
def create_lka_msg(packer, CAN: CanBus):
def create_lka_msg(packer, CAN: CanBus, active: bool = False, apply_angle: float = 0.0,
direction: int = 0, ramp_type: int = 0, curvature: float = 0.0):
"""
Creates an empty CAN message for the Ford LKA Command.
Creates a CAN message for the Ford LKA Command.
This command can apply "Lane Keeping Aid" maneuvers, which are subject to the PSCM lockout.
On LKA-steering platforms, this command applies Lane Keeping Aid maneuvers through the PSCM.
Frequency is 33Hz.
"""
return packer.make_can_msg("Lane_Assist_Data1", CAN.main, {})
if active:
mrad = math.radians(max(-5.8, min(5.8, apply_angle))) * 1000.0
mrad = max(-102.4, min(102.3, mrad))
curvature = max(-0.01023, min(0.01023, curvature))
else:
mrad = 0.0
direction = 0
ramp_type = 0
curvature = 0.0
values = {
"LkaDrvOvrrd_D_Rq": 0,
"LkaActvStats_D2_Req": direction if active else 0,
"LaRefAng_No_Req": mrad,
"LaRampType_B_Req": ramp_type,
"LaCurvature_No_Calc": curvature,
"LdwActvStats_D_Req": 0,
"LdwActvIntns_D_Req": 3,
}
return packer.make_can_msg("Lane_Assist_Data1", CAN.main, values)
def create_lat_ctl_msg(packer, CAN: CanBus, lat_active: bool, path_offset: float, path_angle: float, curvature: float,
curvature_rate: float):
curvature_rate: float, stock_lmc=None):
"""
Creates a CAN message for the Ford TJA/LCA Command.
@@ -68,20 +90,33 @@ def create_lat_ctl_msg(packer, CAN: CanBus, lat_active: bool, path_offset: float
Frequency is 20Hz.
"""
values = {
"LatCtlRng_L_Max": 0, # Unknown [0|126] meter
"HandsOffCnfm_B_Rq": 0, # Unknown: 0=Inactive, 1=Active [0|1]
"LatCtl_D_Rq": 1 if lat_active else 0, # Mode: 0=None, 1=ContinuousPathFollowing, 2=InterventionLeft,
# 3=InterventionRight, 4-7=NotUsed [0|7]
"LatCtlRampType_D_Rq": 0, # Ramp speed: 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3]
# Makes no difference with curvature control
"LatCtlPrecision_D_Rq": 1, # Precision: 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3]
# The stock system always uses comfortable
"LatCtlPathOffst_L_Actl": path_offset, # Path offset [-5.12|5.11] meter
"LatCtlPath_An_Actl": path_angle, # Path angle [-0.5|0.5235] radians
"LatCtlCurv_NoRate_Actl": curvature_rate, # Curvature rate [-0.001024|0.00102375] 1/meter^2
"LatCtlCurv_No_Actl": curvature, # Curvature [-0.02|0.02094] 1/meter
}
if stock_lmc is not None:
values = {
"LatCtlRng_L_Max": stock_lmc["LatCtlRng_L_Max"],
"HandsOffCnfm_B_Rq": stock_lmc["HandsOffCnfm_B_Rq"],
"LatCtl_D_Rq": 0,
"LatCtlRampType_D_Rq": stock_lmc["LatCtlRampType_D_Rq"],
"LatCtlPrecision_D_Rq": stock_lmc["LatCtlPrecision_D_Rq"],
"LatCtlPathOffst_L_Actl": stock_lmc["LatCtlPathOffst_L_Actl"],
"LatCtlPath_An_Actl": stock_lmc["LatCtlPath_An_Actl"],
"LatCtlCurv_NoRate_Actl": stock_lmc["LatCtlCurv_NoRate_Actl"],
"LatCtlCurv_No_Actl": stock_lmc["LatCtlCurv_No_Actl"],
}
else:
values = {
"LatCtlRng_L_Max": 0, # Unknown [0|126] meter
"HandsOffCnfm_B_Rq": 0, # Unknown: 0=Inactive, 1=Active [0|1]
"LatCtl_D_Rq": 1 if lat_active else 0, # Mode: 0=None, 1=ContinuousPathFollowing, 2=InterventionLeft,
# 3=InterventionRight, 4-7=NotUsed [0|7]
"LatCtlRampType_D_Rq": 0, # Ramp speed: 0=Slow, 1=Medium, 2=Fast, 3=Immediate [0|3]
# Makes no difference with curvature control
"LatCtlPrecision_D_Rq": 1, # Precision: 0=Comfortable, 1=Precise, 2/3=NotUsed [0|3]
# The stock system always uses comfortable
"LatCtlPathOffst_L_Actl": path_offset, # Path offset [-5.12|5.11] meter
"LatCtlPath_An_Actl": path_angle, # Path angle [-0.5|0.5235] radians
"LatCtlCurv_NoRate_Actl": curvature_rate, # Curvature rate [-0.001024|0.00102375] 1/meter^2
"LatCtlCurv_No_Actl": curvature, # Curvature [-0.02|0.02094] 1/meter
}
return packer.make_can_msg("LateralMotionControl", CAN.main, values)
+3 -1
View File
@@ -31,7 +31,7 @@ class CarInterface(CarInterfaceBase):
ret.radarUnavailable = Bus.radar not in DBC[candidate]
ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.steerActuatorDelay = 0.2
ret.steerActuatorDelay = 0.05 if ret.flags & FordFlags.LKA_STEERING else 0.2
ret.steerLimitTimer = 1.0
ret.steerAtStandstill = True
@@ -63,6 +63,8 @@ class CarInterface(CarInterfaceBase):
if fingerprint[CAN.camera].get(0x3d6) != 8 or fingerprint[CAN.camera].get(0x186) != 8:
carlog.error('dashcamOnly: SecOC is unsupported')
ret.dashcamOnly = True
elif ret.flags & FordFlags.LKA_STEERING:
ret.safetyConfigs[-1].safetyParam |= FordSafetyFlags.LKA_STEERING.value
else:
# Lock out if the car does not have needed lateral and longitudinal control APIs.
# Note that we also check CAN for adaptive cruise, but no known signal for LCA exists
+13
View File
@@ -46,11 +46,13 @@ class CarControllerParams:
class FordSafetyFlags(IntFlag):
LONG_CONTROL = 1
CANFD = 2
LKA_STEERING = 4
class FordFlags(IntFlag):
# Static flags
CANFD = 1
LKA_STEERING = 2
class RADAR:
@@ -111,6 +113,13 @@ class FordCANFDPlatformConfig(FordPlatformConfig):
self.flags |= FordFlags.CANFD
@dataclass
class FordLKASteeringPlatformConfig(FordPlatformConfig):
def init(self):
super().init()
self.flags |= FordFlags.LKA_STEERING
@dataclass
class FordF150LightningPlatform(FordCANFDPlatformConfig):
def init(self):
@@ -178,6 +187,10 @@ class CAR(Platforms):
[FordCarDocs("Ford Ranger 2024", "Adaptive Cruise Control with Lane Centering", setup_video="https://www.youtube.com/watch?v=2oJlXCKYOy0")],
CarSpecs(mass=2000, wheelbase=3.27, steerRatio=17.0),
)
FORD_TRANSIT_MK5 = FordLKASteeringPlatformConfig(
[FordCarDocs("Ford Transit 2025", "Co-Pilot360 Assist+")],
CarSpecs(mass=2068, wheelbase=3.302, steerRatio=16.7),
)
# FW response contains a combined software and part number
@@ -0,0 +1,8 @@
from opendbc.car.gm.values import AccState, CAR
def get_stock_cc_active_for_cancel(CP, CS):
stock_cc_active = CS.out.cruiseState.enabled or CS.pcm_acc_status != AccState.OFF
if CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL:
return CS.out.cruiseState.enabled
return stock_cc_active
+711 -57
View File
@@ -6,21 +6,76 @@ from opendbc.car.lateral import apply_driver_steer_torque_limits
from opendbc.car.gm import gmcan
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.gm.values import (
ASCM_INT, CAR, CC_ONLY_CAR, CC_REGEN_PADDLE_CAR, DBC, EV_CAR, SDGM_CAR, AccState, CanBus, CarControllerParams,
CruiseButtons, GMFlags,
ASCM_INT, CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, CC_REGEN_PADDLE_CAR, DBC, EV_CAR, SDGM_CAR, AccState, CanBus, CarControllerParams,
CruiseButtons, GMFlags, GMSafetyFlags,
)
from opendbc.car.interfaces import CarControllerBase
from openpilot.common.pid import PIDController
from openpilot.common.params import Params, UnknownKeyName
from openpilot.starpilot.common.testing_grounds import testing_ground
VisualAlert = structs.CarControl.HUDControl.VisualAlert
NetworkLocation = structs.CarParams.NetworkLocation
TransmissionType = structs.CarParams.TransmissionType
LongCtrlState = structs.CarControl.Actuators.LongControlState
GearShifter = structs.CarState.GearShifter
# Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s
CAMERA_CANCEL_DELAY_FRAMES = 10
# Enforce a minimum interval between steering messages to avoid a fault
MIN_STEER_MSG_INTERVAL_MS = 15
AUTO_HOLD_VOLT_CARS = {
CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_2019,
CAR.CHEVROLET_VOLT_ASCM,
CAR.CHEVROLET_VOLT_CAMERA,
}
AUTO_HOLD_DRIVE_GEARS = (
GearShifter.drive,
GearShifter.low,
GearShifter.manumatic,
)
AUTO_HOLD_MIN_BRAKE = 80
AUTO_HOLD_MAX_BRAKE = 240
AUTO_HOLD_MIN_DRIVE_TIME_S = 3.0
AUTO_HOLD_STOPPED_SPEED = 0.02
AUTO_HOLD_2019_MIN_BRAKE = 100
BOLT_ACC_PEDAL_FRICTION_RELEASE_FRAMES = 5
BOLT_PEDAL_LONG_ACCEL_LIMIT_BP = [0.0, 1.5, 4.0, 8.0, 15.0, 30.0]
BOLT_PEDAL_LONG_ACCEL_LIMIT_V = [-0.93, -1.28, -1.98, -2.58, -2.86, -2.95]
VOLT_ONE_PEDAL_DECEL_BP = [0.5 * CV.MPH_TO_MS, 6.0 * CV.MPH_TO_MS]
VOLT_ONE_PEDAL_DECEL_V = [-1.0, -1.1]
VOLT_ONE_PEDAL_REGEN_PADDLE_DECEL_V = [-1.5, -1.6]
VOLT_ONE_PEDAL_MAX_DECEL = min((*VOLT_ONE_PEDAL_DECEL_V, *VOLT_ONE_PEDAL_REGEN_PADDLE_DECEL_V)) - 0.5
VOLT_ONE_PEDAL_PID_NEG_LIMIT = -3.5
VOLT_ONE_PEDAL_SPEED_ERROR_FACTOR_BP = [1.5, 20.0]
VOLT_ONE_PEDAL_SPEED_ERROR_FACTOR_V = [0.4, 0.2]
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_SPEED_FACTOR_BP = [0.0, 10.0 * CV.MPH_TO_MS]
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_SPEED_FACTOR_V = [0.2, 1.0]
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_STEER_FACTOR_BP = [20.0, 120.0]
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_STEER_FACTOR_V = [1.0, 0.2]
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_UP = 0.8 * DT_CTRL * 4
VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_DOWN = 0.8 * DT_CTRL * 4
VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_BP = [4.0, 8.0]
VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_V = [0.4, 1.0]
VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_INCLINE_V = [0.2, 1.0]
VOLT_ONE_PEDAL_LIFT_BRAKE_BP = [0.0, CarControllerParams.NEAR_STOP_BRAKE_PHASE, 2.0 * CV.MPH_TO_MS]
VOLT_ONE_PEDAL_LIFT_BRAKE_V = [AUTO_HOLD_MIN_BRAKE, AUTO_HOLD_MIN_BRAKE, 20.0]
VOLT_ONE_PEDAL_LIFT_BRAKE_FRAMES = 8
TRUCK_LONG_SMOOTH_CARS = {
CAR.CHEVROLET_SILVERADO,
CAR.CHEVROLET_SILVERADO_CC,
}
TRUCK_FRICTION_BRAKE_ENGAGE = 40
TRUCK_FRICTION_BRAKE_RELEASE = 8
TRUCK_FRICTION_BRAKE_IMMEDIATE_ACCEL = -0.85
ACC_DASHBOARD_ZERO_RESERVED_CARS = {
CAR.CHEVROLET_BLAZER,
CAR.CHEVROLET_EQUINOX,
CAR.CHEVROLET_SILVERADO,
CAR.CHEVROLET_TRAILBLAZER,
CAR.CHEVROLET_TRAX,
}
def get_stock_cc_active_for_cancel(CP, CS):
@@ -36,7 +91,13 @@ def use_interceptor_sng_launch(CP, CS, maneuver_mode=False):
launch_speed = max(CP.vEgoStarting, 0.3)
if maneuver_mode:
launch_speed = max(launch_speed, 2.0)
return CS.out.cruiseState.standstill and (CS.out.standstill or CS.out.vEgo < launch_speed)
near_stop = CS.out.standstill or CS.out.vEgo < launch_speed
if (
getattr(CP, "carFingerprint", None) == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL and
getattr(CP, "enableGasInterceptorDEPRECATED", False)
):
return near_stop
return CS.out.cruiseState.standstill and near_stop
def should_spoof_dash_speed(CP, starpilot_toggles):
@@ -62,6 +123,32 @@ def should_send_acc_dashboard_status(CP, dash_speed_spoof_active):
return status_car and (dash_speed_spoof_active or volt_camera_no_camera)
def get_acc_dashboard_status_active(CP, CC):
if CC.enabled:
return True
return CP.carFingerprint == CAR.BUICK_LACROSSE_ASCM and CC.latActive
def get_acc_dashboard_always_one(CP):
return 0 if CP.carFingerprint in ACC_DASHBOARD_ZERO_RESERVED_CARS else 1
def get_acc_dashboard_fcw_alert(hud_alert, CS):
if hud_alert == VisualAlert.fcw:
return 0x3
stock_fcw_alert = int(getattr(CS, "stock_fcw_alert", 0)) & 0x3
if stock_fcw_alert != 0:
return stock_fcw_alert
cs_out = getattr(CS, "out", None)
if cs_out is not None and (getattr(cs_out, "stockAeb", False) or getattr(cs_out, "stockFcw", False)):
return 0x3
return 0
ECM_CRUISE_SPOOF_CARS = {
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
@@ -97,10 +184,299 @@ def get_adas_keepalive_step(CP, is_kaofui_car):
return None
def should_send_adas_status(CP, is_kaofui_car):
if CP.radarUnavailable:
return False
if not is_kaofui_car:
return True
if CP.carFingerprint in ASCM_INT:
return False
return CP.networkLocation != NetworkLocation.fwdCamera and CP.carFingerprint not in SDGM_CAR
def should_send_acc_2cd(CP):
return (
CP.networkLocation == NetworkLocation.fwdCamera and
CP.carFingerprint in CAMERA_ACC_CAR and
CP.carFingerprint not in (CC_ONLY_CAR | SDGM_CAR) and
not bool(getattr(CP, "flags", 0) & GMFlags.NO_CAMERA.value)
)
def get_testing_ground_1_brake_switch_bias(v_ego: float) -> int:
return int(round(np.interp(v_ego, [0.0, 6.0, 15.0, 30.0], [40.0, 85.0, 130.0, 170.0])))
def shape_truck_positive_accel(accel: float, v_ego: float, enabled: bool,
lead_visible: bool = False, set_speed_error: float = 0.0) -> float:
if not enabled or accel <= 0.0 or v_ego < 12.0:
return accel
low_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.93, 0.84, 0.76, 0.70]))
mid_scale = float(np.interp(v_ego, [12.0, 18.0, 25.0, 35.0], [0.97, 0.91, 0.85, 0.79]))
if lead_visible and set_speed_error > 0.0:
follow_relief = float(np.interp(set_speed_error, [0.0, 1.0, 2.5, 4.0, 6.0], [0.0, 0.04, 0.10, 0.18, 0.30]))
low_scale += (1.0 - low_scale) * follow_relief
mid_scale += (1.0 - mid_scale) * follow_relief
if accel <= 0.12:
return accel * low_scale
if accel <= 0.35:
return float(np.interp(accel, [0.12, 0.35], [0.12 * low_scale, 0.35 * mid_scale]))
if accel <= 0.65:
return float(np.interp(accel, [0.35, 0.65], [0.35 * mid_scale, 0.65]))
return accel
def shape_truck_pitch_accel(pitch_accel: float, v_ego: float, enabled: bool) -> float:
if not enabled:
return pitch_accel
scale = float(np.interp(v_ego, [8.0, 15.0, 25.0, 35.0], [0.60, 0.45, 0.30, 0.25]))
return pitch_accel * scale
def shape_truck_friction_brake(apply_brake: int, accel_cmd: float, stopping: bool, active: bool) -> tuple[int, bool]:
if apply_brake <= 0:
return 0, False
# Preserve full brake response for stop control and meaningful deceleration.
if stopping or accel_cmd <= TRUCK_FRICTION_BRAKE_IMMEDIATE_ACCEL:
return apply_brake, True
if active:
if apply_brake <= TRUCK_FRICTION_BRAKE_RELEASE:
return 0, False
return apply_brake, True
if apply_brake >= TRUCK_FRICTION_BRAKE_ENGAGE:
return apply_brake, True
# Keep tiny corrections in the continuous gas/regen torque path. Switching
# to friction also forces max regen, which makes a small request perceptible.
return 0, False
def get_lka_steering_cmd_counter(next_counter: int, CS) -> int:
if getattr(CS, "loopback_lka_steering_cmd_updated", False):
return (getattr(CS, "loopback_lka_steering_cmd_counter", next_counter) + 1) % 4
if next_counter < 0 and getattr(CS, "loopback_lka_steering_cmd_ts_nanos", 0) == 0:
return (getattr(CS, "pt_lka_steering_cmd_counter", next_counter) + 1) % 4
return next_counter
def should_send_stock_long_cancel(cancel_counter: int, CS) -> bool:
cs_out = getattr(CS, "out", None)
return cancel_counter > CAMERA_CANCEL_DELAY_FRAMES and not bool(getattr(cs_out, "accFaulted", False))
def supports_volt_auto_hold(CP, auto_hold_enabled: bool):
safety_cfg = getattr(CP, "safetyConfigs", ())
safety_param = safety_cfg[0].safetyParam if safety_cfg else 0
stock_hold_safety_ready = bool(safety_param & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value)
return (
auto_hold_enabled and
getattr(CP, "openpilotLongitudinalControl", False) and
stock_hold_safety_ready and
CP.carFingerprint in AUTO_HOLD_VOLT_CARS
)
def supports_volt_one_pedal(CP, one_pedal_enabled: bool):
safety_cfg = getattr(CP, "safetyConfigs", ())
safety_param = safety_cfg[0].safetyParam if safety_cfg else 0
stock_hold_safety_ready = bool(safety_param & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value)
return (
one_pedal_enabled and
getattr(CP, "openpilotLongitudinalControl", False) and
stock_hold_safety_ready and
getattr(CP, "transmissionType", None) == TransmissionType.direct and
CP.carFingerprint in AUTO_HOLD_VOLT_CARS
)
def estimate_auto_hold_brake(driver_brake: float, op_brake: float, CP=None) -> int:
driver_hold = np.interp(float(driver_brake), [8.0, 20.0, 40.0, 80.0], [80.0, 110.0, 150.0, 220.0])
hold_brake = max(float(op_brake), float(driver_hold))
min_brake = AUTO_HOLD_2019_MIN_BRAKE if getattr(CP, "carFingerprint", None) == CAR.CHEVROLET_VOLT_2019 else AUTO_HOLD_MIN_BRAKE
return int(round(np.clip(hold_brake, min_brake, AUTO_HOLD_MAX_BRAKE)))
def get_auto_hold_stop_threshold(CP, auto_hold_engaged: bool) -> float:
if auto_hold_engaged and getattr(CP, "carFingerprint", None) == CAR.CHEVROLET_VOLT_2019:
return CarControllerParams.NEAR_STOP_BRAKE_PHASE
return AUTO_HOLD_STOPPED_SPEED
def get_volt_one_pedal_target_decel(v_ego: float) -> float:
return float(np.interp(v_ego, VOLT_ONE_PEDAL_DECEL_BP, VOLT_ONE_PEDAL_DECEL_V))
def get_volt_one_pedal_lift_brake(v_ego: float) -> int:
if v_ego > VOLT_ONE_PEDAL_LIFT_BRAKE_BP[-1]:
return 0
return int(round(np.interp(v_ego, VOLT_ONE_PEDAL_LIFT_BRAKE_BP, VOLT_ONE_PEDAL_LIFT_BRAKE_V)))
def should_activate_volt_one_pedal(one_pedal_ready: bool, cruise_main: bool, long_active: bool,
gas_pressed: bool, brake_pressed: bool, regen_braking: bool,
single_pedal_mode: bool, gear_shifter, drive_time_s: float) -> bool:
# Volt rear wheel direction bits can falsely report reverse while stopping in L.
return (
one_pedal_ready and
cruise_main and
single_pedal_mode and
gear_shifter in AUTO_HOLD_DRIVE_GEARS and
drive_time_s >= AUTO_HOLD_MIN_DRIVE_TIME_S and
not long_active and
not gas_pressed and
not brake_pressed and
not regen_braking
)
def should_activate_auto_hold(hold_ready: bool, auto_hold_armed: bool, auto_hold_engaged: bool,
brake_pressed: bool, gas_pressed: bool, standstill: bool, long_active: bool,
regen_braking: bool, v_ego: float, stop_speed_threshold: float=AUTO_HOLD_STOPPED_SPEED) -> bool:
stopped = standstill or v_ego < stop_speed_threshold
return (
hold_ready and
(auto_hold_armed or auto_hold_engaged or brake_pressed) and
not gas_pressed and
stopped and
not long_active and
not regen_braking
)
def get_friction_brake_bus(CP):
volt_gateway_alt_brake = (
CP.carFingerprint == CAR.CHEVROLET_VOLT and
CP.networkLocation == NetworkLocation.gateway and
bool(CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value)
)
if volt_gateway_alt_brake:
return CanBus.POWERTRAIN
if CP.networkLocation == NetworkLocation.fwdCamera:
if CP.carFingerprint in SDGM_CAR:
# cam-long: 0x315 goes where the panda whitelist allows it and the EBCM hears it
safety_cfg = getattr(CP, "safetyConfigs", ())
safety_param = safety_cfg[0].safetyParam if safety_cfg else 0
if safety_param & GMSafetyFlags.HW_CAM_LONG.value:
# SASCM relays 0x315 to the EBCM off its camera-bus (bus2) leg; bare SDGM uses the pt bus
if CP.flags & GMFlags.SASCM.value:
return CanBus.CAMERA
return CanBus.POWERTRAIN
return CanBus.CAMERA
return CanBus.POWERTRAIN
return CanBus.CHASSIS
def supports_bolt_acc_pedal_friction_experiment(CP) -> bool:
return (
CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL and
CP.openpilotLongitudinalControl and
CP.enableGasInterceptorDEPRECATED and
bool(CP.flags & GMFlags.PEDAL_LONG.value)
)
def get_bolt_acc_pedal_friction_brake(apply_brake, full_brake_accel, v_ego, params) -> int:
if apply_brake <= 0:
return 0
full_brake_accel = min(full_brake_accel, -0.1)
legacy_full_scale = max(-params.ACCEL_MIN, 0.1)
corrected_scale = legacy_full_scale / max(-full_brake_accel, 0.1)
speed_gain = float(np.interp(v_ego, [0.0, 8.0, 15.0, 25.0], [1.0, 1.08, 1.2, 1.35]))
onset_gain = float(np.interp(
apply_brake,
[0.0, 5.0, 20.0, 60.0, 120.0, 240.0, params.MAX_BRAKE],
[0.0, 1.8, 1.65, 1.4, 1.22, 1.08, 1.0],
))
shaped_brake = apply_brake * corrected_scale * speed_gain * onset_gain
minimum_brake = float(np.interp(v_ego, [0.0, 6.0, 8.0, 12.0, 18.0, 25.0], [0.0, 0.0, 4.0, 10.0, 20.0, 28.0]))
shaped_brake = max(shaped_brake, minimum_brake)
return int(round(np.clip(shaped_brake, 0, params.MAX_BRAKE)))
def shape_bolt_acc_pedal_low_speed_friction(apply_brake: int, v_ego: float, stopping: bool, active: bool):
if apply_brake <= 0:
return 0, False
engage_threshold = float(np.interp(v_ego, [0.0, 1.5, 3.0, 5.0, 8.0], [40.0, 20.0, 12.0, 10.0, 0.0]))
release_threshold = float(np.interp(v_ego, [0.0, 1.5, 3.0, 5.0, 8.0], [0.0, 8.0, 6.0, 4.0, 0.0]))
if not active:
if apply_brake < engage_threshold:
return 0, False
active = True
elif apply_brake < release_threshold:
return 0, False
if stopping:
stop_fade = float(np.interp(v_ego, [0.0, 0.6, 0.9, 1.2, 1.8, 2.8], [0.0, 0.0, 0.05, 0.12, 0.32, 0.78]))
apply_brake = int(round(apply_brake * stop_fade))
if apply_brake <= 0 or apply_brake < release_threshold:
return 0, False
return apply_brake, active
def get_bolt_pedal_long_accel_limit(v_ego: float) -> float:
return float(np.interp(v_ego, BOLT_PEDAL_LONG_ACCEL_LIMIT_BP, BOLT_PEDAL_LONG_ACCEL_LIMIT_V))
def get_bolt_acc_pedal_planner_brake_switch(v_ego: float, params, tire_radius: float, mass: float,
coeff_drag: float, frontal_area: float, air_density: float) -> int:
planner_accel_limit = get_bolt_pedal_long_accel_limit(v_ego)
aero_drag_force = 0.5 * coeff_drag * frontal_area * air_density * v_ego ** 2
planner_torque = tire_radius * ((mass * planner_accel_limit) + aero_drag_force)
return int(round(planner_torque + params.ZERO_GAS))
def get_bolt_acc_pedal_effective_brake_switch(stock_switch: int, planner_switch: int) -> int:
return max(stock_switch, planner_switch)
def get_bolt_acc_pedal_friction_command_state(apply_brake: int, cruise_main_on: bool, release_frames: int):
command_brake = apply_brake if cruise_main_on else 0
if command_brake > 0:
release_frames = BOLT_ACC_PEDAL_FRICTION_RELEASE_FRAMES
elif release_frames > 0:
release_frames -= 1
should_send = cruise_main_on or release_frames > 0
return command_brake, release_frames, should_send
def get_interceptor_sng_gas_cmd(CP, interceptor_gas_cmd: float, accel: float, params, maneuver_mode: bool) -> float:
if maneuver_mode:
return max(interceptor_gas_cmd, float(np.interp(accel, [0.0, 1.0, 2.0], [params.SNG_INTERCEPTOR_GAS, 0.11, 0.16])))
if supports_bolt_acc_pedal_friction_experiment(CP):
return max(interceptor_gas_cmd, params.SNG_INTERCEPTOR_GAS)
return params.SNG_INTERCEPTOR_GAS
def should_use_fixed_stopping_brake(CP, near_stop: bool, stopping: bool, resume: bool) -> bool:
if not (near_stop and stopping and not resume):
return False
return not supports_bolt_acc_pedal_friction_experiment(CP)
class CarController(CarControllerBase):
def __init__(self, dbc_names, CP):
super().__init__(dbc_names, CP)
@@ -111,6 +487,15 @@ class CarController(CarControllerBase):
self.last_steer_frame = 0
self.last_button_frame = 0
self.cancel_counter = 0
self.xt4_cc_button_burst_remaining = 0
self.xt4_cc_button_burst_button = CruiseButtons.INIT
self.xt4_cc_button_burst_last_counter = -1
self.xt4_cc_button_observed_counter = -1
self.xt4_cc_button_counter_frame = 0
self.gm_cc_last_direction_button = CruiseButtons.INIT
self.gm_cc_last_direction_frame = 0
self.gm_cc_pending_reverse_button = CruiseButtons.INIT
self.gm_cc_pending_reverse_frame = 0
self.lka_steering_cmd_counter = 0
self.lka_icon_status_last = (False, False)
@@ -153,6 +538,61 @@ class CarController(CarControllerBase):
self.malibu_cancel_phase = 0
self.malibu_button_phase = 0
self.malibu_last_button_ts_nanos = 0
self.auto_hold_brake = 0
self.volt_one_pedal_pid = PIDController(
(CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
rate=1 / (DT_CTRL * 4),
pos_limit=0.0,
neg_limit=VOLT_ONE_PEDAL_PID_NEG_LIMIT,
)
self.volt_one_pedal_decel = 0.0
self.volt_one_pedal_brake = 0
self.volt_one_pedal_lift_frames = 0
self.volt_one_pedal_gas_pressed_last = False
try:
self.gm_auto_hold_enabled = self.params_.get_bool("GMAutoHold")
except UnknownKeyName:
self.gm_auto_hold_enabled = False
self.bolt_acc_pedal_friction_release_frames = 0
self.bolt_acc_pedal_friction_low_speed_active = False
self.truck_friction_brake_active = False
def _reset_volt_one_pedal(self):
self.volt_one_pedal_pid.reset()
self.volt_one_pedal_decel = min(0.0, float(self.aego))
self.volt_one_pedal_brake = 0
self.volt_one_pedal_lift_frames = 0
def _update_volt_one_pedal_brake(self, CC, CS):
pitch_accel = 0.0
if len(CC.orientationNED) == 3 and CS.out.vEgo > self.CP.vEgoStopping:
pitch_accel = math.sin(CC.orientationNED[1]) * ACCELERATION_DUE_TO_GRAVITY
pitch_factor_values = VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_V if pitch_accel <= 0.0 else VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_INCLINE_V
pitch_accel *= float(np.interp(CS.out.vEgo, VOLT_ONE_PEDAL_ACCEL_PITCH_FACTOR_BP, pitch_factor_values))
target_decel = get_volt_one_pedal_target_decel(CS.out.vEgo)
measured_decel = min(0.0, CS.out.aEgo + pitch_accel)
error_factor = float(np.interp(CS.out.vEgo, VOLT_ONE_PEDAL_SPEED_ERROR_FACTOR_BP, VOLT_ONE_PEDAL_SPEED_ERROR_FACTOR_V))
error = (target_decel - measured_decel) * error_factor
raw_decel = float(self.volt_one_pedal_pid.update(error, speed=CS.out.vEgo, feedforward=target_decel))
rate_limit_factor = min(
float(np.interp(CS.out.vEgo, VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_SPEED_FACTOR_BP, VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_SPEED_FACTOR_V)),
float(np.interp(abs(CS.out.steeringAngleDeg), VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_STEER_FACTOR_BP, VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_STEER_FACTOR_V)),
)
lower = min(self.volt_one_pedal_decel, measured_decel) - VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_UP * rate_limit_factor
upper = max(self.volt_one_pedal_decel, measured_decel) + VOLT_ONE_PEDAL_DECEL_RATE_LIMIT_DOWN + rate_limit_factor
self.volt_one_pedal_decel = float(np.clip(raw_decel, lower, upper))
self.volt_one_pedal_decel = max(self.volt_one_pedal_decel, VOLT_ONE_PEDAL_MAX_DECEL)
self.volt_one_pedal_brake = int(round(np.clip(
np.interp(self.volt_one_pedal_decel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V),
0,
self.params.MAX_BRAKE,
)))
if self.volt_one_pedal_lift_frames > 0:
self.volt_one_pedal_brake = max(self.volt_one_pedal_brake, get_volt_one_pedal_lift_brake(CS.out.vEgo))
self.volt_one_pedal_lift_frames -= 1
def calc_pedal_command(self, accel: float, long_active: bool, v_ego: float):
if not long_active:
@@ -275,6 +715,9 @@ class CarController(CarControllerBase):
else:
urgency = float(np.clip(abs(accel) / 2.0, 0.0, 1.0))
rate_up = np.interp(v_ego, [0.0, 3.0, 8.0, 20.0], [0.007, 0.012, 0.022, 0.036]) + 0.011 * urgency
if accel > 0.0 and v_ego > 6.0:
comfort_factor = np.interp(abs(accel), [0.0, 0.12, 0.25, 0.45, 0.8], [0.55, 0.58, 0.68, 0.82, 1.0])
rate_up *= comfort_factor
if accel > 1.2:
rate_up += np.interp(v_ego, [0.0, 4.0, 12.0, 25.0], [0.006, 0.005, 0.003, 0.002])
rate_down = np.interp(v_ego, [0.0, 3.0, 8.0, 20.0], [0.008, 0.014, 0.026, 0.045]) + 0.015 * urgency
@@ -302,8 +745,64 @@ class CarController(CarControllerBase):
self.aego = CS.out.aEgo
accel = actuators.accel
press_regen_paddle = False
auto_hold_enabled = supports_volt_auto_hold(self.CP, self.gm_auto_hold_enabled)
volt_one_pedal_supported = supports_volt_one_pedal(
self.CP, bool(getattr(starpilot_toggles, "volt_one_pedal_mode", False))
)
volt_one_pedal_active = should_activate_volt_one_pedal(
volt_one_pedal_supported,
CS.out.cruiseState.available,
CC.longActive,
CS.out.gasPressed,
CS.out.brakePressed,
CS.out.regenBraking,
bool(getattr(CS, "single_pedal_mode", False)),
CS.out.gearShifter,
float(getattr(CS, "one_pedal_drive_time", 0.0)),
)
if volt_one_pedal_active and self.volt_one_pedal_gas_pressed_last and not CS.out.gasPressed:
if CS.out.vEgo < VOLT_ONE_PEDAL_LIFT_BRAKE_BP[-1]:
self.volt_one_pedal_lift_frames = VOLT_ONE_PEDAL_LIFT_BRAKE_FRAMES
elif CS.out.gasPressed or not volt_one_pedal_active:
self.volt_one_pedal_lift_frames = 0
if self.frame % 4 == 0:
if volt_one_pedal_active:
self._update_volt_one_pedal_brake(CC, CS)
else:
self._reset_volt_one_pedal()
if not self.CP.openpilotLongitudinalControl:
self.apply_gas = 0
self.apply_brake = self.volt_one_pedal_brake if volt_one_pedal_active else 0
self.volt_one_pedal_gas_pressed_last = CS.out.gasPressed
stock_hold_apply_brake = max(self.apply_brake if self.CP.openpilotLongitudinalControl else 0, self.volt_one_pedal_brake)
hold_ready = (
auto_hold_enabled and
CS.out.cruiseState.available and
CS.out.gearShifter in AUTO_HOLD_DRIVE_GEARS and
CS.auto_hold_drive_time >= AUTO_HOLD_MIN_DRIVE_TIME_S
)
if not hold_ready or CS.out.gasPressed:
CS.auto_hold_armed = False
if CS.out.gasPressed:
CS.auto_hold_engaged = False
elif CS.regen_release_timer > 0.0:
CS.auto_hold_armed = False
elif not CS.auto_hold_armed and (CS.out.vEgo > 0.03 or ((CS.out.standstill or CS.out.vEgo < 0.02) and CS.out.brakePressed)):
CS.auto_hold_armed = True
if CS.out.vEgo > 0.1 or CS.out.gasPressed or CS.out.gearShifter not in AUTO_HOLD_DRIVE_GEARS:
self.auto_hold_brake = 0
elif CS.out.brakePressed or stock_hold_apply_brake > 0:
self.auto_hold_brake = estimate_auto_hold_brake(CS.out.brake, stock_hold_apply_brake, self.CP)
if self.frame % 25 == 0:
try:
self.gm_auto_hold_enabled = self.params_.get_bool("GMAutoHold")
except UnknownKeyName:
self.gm_auto_hold_enabled = False
try:
mode = self.params_.get("LongitudinalManeuverPaddleMode")
except UnknownKeyName:
@@ -383,6 +882,29 @@ class CarController(CarControllerBase):
paddle_sched_feed_active = False
paddle_spoof_pressed = raw_regen_active and (CS.out.vEgo > 2.68)
auto_hold_active = should_activate_auto_hold(
hold_ready,
CS.auto_hold_armed,
CS.auto_hold_engaged,
CS.out.brakePressed,
CS.out.gasPressed,
CS.out.standstill,
CC.longActive,
CS.out.regenBraking,
CS.out.vEgo,
get_auto_hold_stop_threshold(self.CP, CS.auto_hold_engaged),
)
bolt_acc_pedal_friction_experiment = supports_bolt_acc_pedal_friction_experiment(self.CP)
bolt_acc_pedal_friction_main_on = bolt_acc_pedal_friction_experiment and CS.out.cruiseState.available
if not bolt_acc_pedal_friction_main_on:
self.bolt_acc_pedal_friction_low_speed_active = False
volt_one_pedal_braking = volt_one_pedal_active and self.volt_one_pedal_brake > 0
volt_one_pedal_hold_active = (
volt_one_pedal_braking and
not auto_hold_active and
CS.one_pedal_drive_time >= AUTO_HOLD_MIN_DRIVE_TIME_S and
(CS.out.standstill or CS.out.vEgo < 0.02)
)
# Steering (Active: 50Hz, inactive: 10Hz)
steer_step = self.params.STEER_STEP if CC.latActive else self.params.INACTIVE_STEER_STEP
@@ -425,6 +947,18 @@ class CarController(CarControllerBase):
can_sends.append(gmcan.create_ecm_cruise_control_command(
self.packer_pt, CanBus.POWERTRAIN, True, hud_v_cruise * CV.MS_TO_KPH))
xt4_cc_button_spam = (
self.CP.carFingerprint == CAR.CADILLAC_XT4_CC and
should_send_cc_button_spam(self.CP, CC, CS)
)
if xt4_cc_button_spam:
can_sends.extend(gmcan.create_gm_cc_spam_command(self.packer_pt, self, CS, actuators, starpilot_toggles))
elif self.CP.carFingerprint == CAR.CADILLAC_XT4_CC:
self.xt4_cc_button_burst_remaining = 0
self.xt4_cc_button_burst_button = CruiseButtons.INIT
self.xt4_cc_button_burst_last_counter = -1
self.xt4_cc_button_observed_counter = -1
if self.CP.openpilotLongitudinalControl:
# Gas/regen, brakes, and UI commands - all at 25Hz
if self.frame % 4 == 0:
@@ -436,6 +970,7 @@ class CarController(CarControllerBase):
# ASCM sends max regen when not enabled
self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = 0
self.bolt_acc_pedal_friction_low_speed_active = False
self.planner_regen_hold = False
self.regen_paddle_pressed = False
self.regen_paddle_timer = 0
@@ -443,7 +978,7 @@ class CarController(CarControllerBase):
self.regen_release_counter = 0
self.regen_min_on_frames = 0
self.regen_min_off_frames = 0
elif near_stop and stopping and not CC.cruiseControl.resume:
elif should_use_fixed_stopping_brake(self.CP, near_stop, stopping, CC.cruiseControl.resume):
stop_accel = getattr(starpilot_toggles, "stopAccel", self.CP.stopAccel)
self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = int(min(-100 * stop_accel, self.params.MAX_BRAKE))
@@ -487,7 +1022,24 @@ class CarController(CarControllerBase):
if testing_ground.use_1:
accel_max = min(accel_max, np.interp(CS.out.vEgo, [0.0, 4.0, 12.0], [1.25, 1.6, self.params.ACCEL_MAX]))
accel_cmd = float(np.clip(actuators.accel + accel_due_to_pitch, self.params.ACCEL_MIN, accel_max))
truck_long_smoothing = (
getattr(starpilot_toggles, "truck_tuning", False) and
self.CP.carFingerprint in TRUCK_LONG_SMOOTH_CARS and
getattr(self.CP, "transmissionType", None) == TransmissionType.automatic and
not self.CP.enableGasInterceptorDEPRECATED
)
accel_due_to_pitch = shape_truck_pitch_accel(accel_due_to_pitch, CS.out.vEgo, truck_long_smoothing)
accel_input = actuators.accel + accel_due_to_pitch
if truck_long_smoothing:
accel_input = shape_truck_positive_accel(
accel_input,
CS.out.vEgo,
True,
lead_visible=CC.hudControl.leadVisible,
set_speed_error=max(CC.hudControl.setSpeed - CS.out.vEgo, 0.0),
)
accel_cmd = float(np.clip(accel_input, self.params.ACCEL_MIN, accel_max))
torque = self.tireRadius * ((self.mass * accel_cmd) + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2))
scaled_torque = torque + self.params.ZERO_GAS
apply_gas_torque = np.clip(scaled_torque, self.params.MAX_ACC_REGEN, gas_max)
@@ -495,9 +1047,33 @@ class CarController(CarControllerBase):
if testing_ground.use_1:
brake_switch_bias = get_testing_ground_1_brake_switch_bias(CS.out.vEgo)
brake_switch = min(self.params.ZERO_GAS, brake_switch + brake_switch_bias)
if bolt_acc_pedal_friction_main_on:
planner_brake_switch = get_bolt_acc_pedal_planner_brake_switch(
CS.out.vEgo, self.params, self.tireRadius, self.mass, self.coeffDrag, self.frontalArea, self.airDensity,
)
brake_switch = get_bolt_acc_pedal_effective_brake_switch(brake_switch, planner_brake_switch)
brake_accel = min((scaled_torque - brake_switch) / (self.tireRadius * self.mass), 0)
self.apply_gas = int(round(apply_gas_torque))
self.apply_brake = int(round(np.interp(brake_accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
if truck_long_smoothing:
self.apply_brake, self.truck_friction_brake_active = shape_truck_friction_brake(
self.apply_brake, accel_cmd, stopping, self.truck_friction_brake_active,
)
else:
self.truck_friction_brake_active = False
if bolt_acc_pedal_friction_main_on:
if self.apply_brake > 0:
full_brake_accel = min(
self.params.ACCEL_MIN + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2) / self.mass +
(self.params.ZERO_GAS - brake_switch) / (self.tireRadius * self.mass),
-0.1,
)
self.apply_brake = get_bolt_acc_pedal_friction_brake(
self.apply_brake, full_brake_accel, CS.out.vEgo, self.params,
)
self.apply_brake, self.bolt_acc_pedal_friction_low_speed_active = shape_bolt_acc_pedal_low_speed_friction(
self.apply_brake, CS.out.vEgo, stopping, self.bolt_acc_pedal_friction_low_speed_active,
)
if self.apply_brake > 0:
self.apply_gas = self.params.INACTIVE_REGEN
@@ -508,15 +1084,19 @@ class CarController(CarControllerBase):
# gas interceptor only used for full long control on cars without ACC
interceptor_gas_cmd, press_regen_paddle = self.calc_pedal_command(actuators.accel, CC.longActive, CS.out.vEgo)
if volt_one_pedal_braking:
self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = max(self.apply_brake, self.volt_one_pedal_brake)
maneuver_sng_launch = self.longitudinal_maneuver_mode and self.is_volt
if (
self.CP.enableGasInterceptorDEPRECATED and
self.apply_gas > self.params.INACTIVE_REGEN and
use_interceptor_sng_launch(self.CP, CS, maneuver_sng_launch)
):
interceptor_gas_cmd = self.params.SNG_INTERCEPTOR_GAS
if maneuver_sng_launch:
interceptor_gas_cmd = max(interceptor_gas_cmd, float(np.interp(actuators.accel, [0.0, 1.0, 2.0], [self.params.SNG_INTERCEPTOR_GAS, 0.11, 0.16])))
interceptor_gas_cmd = get_interceptor_sng_gas_cmd(
self.CP, interceptor_gas_cmd, actuators.accel, self.params, maneuver_sng_launch,
)
self.apply_brake = 0
self.apply_gas = self.params.INACTIVE_REGEN
@@ -537,28 +1117,50 @@ class CarController(CarControllerBase):
if self.CP.flags & GMFlags.CC_LONG.value:
if should_send_cc_button_spam(self.CP, CC, CS):
# Using extend instead of append since the message is only sent intermittently
can_sends.extend(gmcan.create_gm_cc_spam_command(self.packer_pt, self, CS, actuators, starpilot_toggles))
elif (CS.out.cruiseState.enabled and CC.enabled and self.frame % 52 == 0 and
if self.CP.carFingerprint != CAR.CADILLAC_XT4_CC:
# Using extend instead of append since the message is only sent intermittently
can_sends.extend(gmcan.create_gm_cc_spam_command(self.packer_pt, self, CS, actuators, starpilot_toggles))
else:
if (CS.out.cruiseState.enabled and CC.enabled and self.frame % 52 == 0 and
CS.cruise_buttons == CruiseButtons.UNPRESS and CS.out.gasPressed and CS.out.cruiseState.speed < CS.out.vEgo < hud_v_cruise):
if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
can_sends.append(gmcan.create_buttons_malibu(
self.packer_pt, CanBus.POWERTRAIN, CruiseButtons.DECEL_SET,
self.malibu_button_phase, CS.steering_button_prefix))
self.malibu_button_phase = (self.malibu_button_phase + 1) % 4
else:
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.DECEL_SET))
if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
can_sends.append(gmcan.create_buttons_malibu(
self.packer_pt, CanBus.POWERTRAIN, CruiseButtons.DECEL_SET,
self.malibu_button_phase, CS.steering_button_prefix))
self.malibu_button_phase = (self.malibu_button_phase + 1) % 4
else:
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.DECEL_SET))
if self.CP.enableGasInterceptorDEPRECATED:
can_sends.append(create_gas_interceptor_command(self.packer_pt, interceptor_gas_cmd, idx))
if bolt_acc_pedal_friction_experiment:
friction_brake_bus = get_friction_brake_bus(self.CP)
if self.CP.networkLocation == NetworkLocation.fwdCamera:
at_full_stop = at_full_stop and stopping
experiment_brake, self.bolt_acc_pedal_friction_release_frames, should_send_bolt_acc_pedal_friction = \
get_bolt_acc_pedal_friction_command_state(
self.apply_brake,
bolt_acc_pedal_friction_main_on,
self.bolt_acc_pedal_friction_release_frames,
)
# This fingerprint is routed through the CC-only pedal path, so it
# does not fall through to the normal friction-brake sender below.
# Never apply stock friction with cruise main off, but do send a short
# explicit zero-brake unwind so the last nonzero stock-EBCM command
# cannot linger after a disengage or main-off event.
if should_send_bolt_acc_pedal_friction:
can_sends.append(gmcan.create_friction_brake_command(
self.packer_ch, friction_brake_bus, experiment_brake, idx, bolt_acc_pedal_friction_main_on,
near_stop, at_full_stop, self.CP))
if self.CP.carFingerprint not in CC_ONLY_CAR:
friction_brake_bus = CanBus.CHASSIS
friction_brake_bus = get_friction_brake_bus(self.CP)
# GM Camera exceptions
# TODO: can we always check the longControlState?
if self.CP.networkLocation == NetworkLocation.fwdCamera:
at_full_stop = at_full_stop and stopping
friction_brake_bus = CanBus.POWERTRAIN
if self.CP.carFingerprint in SDGM_CAR:
friction_brake_bus = CanBus.CAMERA
if should_send_acc_2cd(self.CP):
can_sends.append(gmcan.create_acc_2cd_command(CanBus.POWERTRAIN, idx))
if self.CP.autoResumeSng:
resume = actuators.longControlState != LongCtrlState.starting or CC.cruiseControl.resume
@@ -569,47 +1171,68 @@ class CarController(CarControllerBase):
else:
acc_engaged = CC.enabled
# GasRegenCmdActive needs to be 1 to avoid cruise faults. It describes the ACC state, not actuation
can_sends.append(gmcan.create_gas_regen_command(
self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, acc_engaged, at_full_stop,
include_always_one3=self.CP.carFingerprint in kaofui_cars, use_volt_layout=self.is_volt))
can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, friction_brake_bus, self.apply_brake,
idx, CC.enabled, near_stop, at_full_stop, self.CP))
if auto_hold_active:
hold_brake = max(self.volt_one_pedal_brake, self.auto_hold_brake or estimate_auto_hold_brake(CS.out.brake, self.apply_brake, self.CP))
hold_standstill = CS.pcm_acc_status == AccState.STANDSTILL
hold_near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
can_sends.append(gmcan.create_friction_brake_command(
self.packer_ch, friction_brake_bus, hold_brake, idx, False, hold_near_stop, hold_standstill,
self.CP, allow_near_stop_mode=True))
CS.auto_hold_engaged = True
CS.auto_hold_fault_suppression_timer = 1.0
elif volt_one_pedal_hold_active:
hold_brake = max(self.volt_one_pedal_brake, self.auto_hold_brake or estimate_auto_hold_brake(0.0, self.volt_one_pedal_brake, self.CP))
hold_standstill = CS.pcm_acc_status == AccState.STANDSTILL
hold_near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
can_sends.append(gmcan.create_friction_brake_command(
self.packer_ch, friction_brake_bus, hold_brake, idx, False, hold_near_stop, hold_standstill,
self.CP, allow_near_stop_mode=True))
CS.auto_hold_engaged = True
CS.auto_hold_fault_suppression_timer = 1.0
else:
if volt_one_pedal_braking:
at_full_stop = at_full_stop or CS.pcm_acc_status == AccState.STANDSTILL
near_stop = near_stop or (CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE)
# GasRegenCmdActive needs to be 1 to avoid cruise faults. It describes the ACC state, not actuation
can_sends.append(gmcan.create_gas_regen_command(
self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, acc_engaged, at_full_stop,
include_always_one3=self.CP.carFingerprint in kaofui_cars, use_volt_layout=self.is_volt))
can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, friction_brake_bus, self.apply_brake,
idx, CC.enabled, near_stop, at_full_stop, self.CP,
allow_near_stop_mode=volt_one_pedal_braking))
CS.auto_hold_engaged = False
if should_send_acc_dashboard_status(self.CP, dash_speed_spoof_active):
send_fcw = hud_alert == VisualAlert.fcw
can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, CC.enabled,
hud_v_cruise * CV.MS_TO_KPH, hud_control, send_fcw))
fcw_alert = get_acc_dashboard_fcw_alert(hud_alert, CS)
acc_dashboard_status_active = get_acc_dashboard_status_active(self.CP, CC)
acc_dashboard_always_one = get_acc_dashboard_always_one(self.CP)
can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, acc_dashboard_status_active,
hud_v_cruise * CV.MS_TO_KPH, hud_control, fcw_alert,
acc_dashboard_always_one))
# Radar needs to know current speed and yaw rate (50hz),
# and that ADAS is alive (10hz)
if not self.CP.radarUnavailable:
send_adas = True
if should_send_adas_status(self.CP, self.CP.carFingerprint in kaofui_cars):
tt = self.frame * DT_CTRL
if self.CP.carFingerprint in kaofui_cars:
if self.CP.carFingerprint not in ASCM_INT:
send_adas = (self.CP.networkLocation != NetworkLocation.fwdCamera) and (self.CP.carFingerprint not in SDGM_CAR)
if send_adas:
tt = self.frame * DT_CTRL
if self.CP.carFingerprint in kaofui_cars:
time_and_headlights_step = 10
speed_and_accelerometer_step = 2
if self.frame % time_and_headlights_step == 0:
idx = (self.frame // time_and_headlights_step) % 4
can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx))
can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE))
if self.frame % speed_and_accelerometer_step == 0:
idx = (self.frame // speed_and_accelerometer_step) % 4
can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx))
can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx))
else:
time_and_headlights_step = 20
if self.frame % time_and_headlights_step == 0:
idx = (self.frame // time_and_headlights_step) % 4
can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx))
can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE))
can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx))
can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx))
time_and_headlights_step = 10
speed_and_accelerometer_step = 2
if self.frame % time_and_headlights_step == 0:
idx = (self.frame // time_and_headlights_step) % 4
can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx))
can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE))
if self.frame % speed_and_accelerometer_step == 0:
idx = (self.frame // speed_and_accelerometer_step) % 4
can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx))
can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx))
else:
time_and_headlights_step = 20
if self.frame % time_and_headlights_step == 0:
idx = (self.frame // time_and_headlights_step) % 4
can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx))
can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE))
can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx))
can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx))
keepalive_step = get_adas_keepalive_step(self.CP, self.CP.carFingerprint in kaofui_cars)
if keepalive_step is not None and self.frame % keepalive_step == 0:
@@ -633,6 +1256,37 @@ class CarController(CarControllerBase):
can_sends.append(gmcan.create_buttons(self.packer_pt, cancel_bus, (CS.buttons_counter + 1) % 4, CruiseButtons.CANCEL))
else:
if self.frame % 4 == 0 and auto_hold_active:
idx = (self.frame // 4) % 4
hold_brake = max(self.volt_one_pedal_brake, self.auto_hold_brake or estimate_auto_hold_brake(CS.out.brake, stock_hold_apply_brake, self.CP))
hold_standstill = CS.pcm_acc_status == AccState.STANDSTILL
hold_near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
can_sends.append(gmcan.create_friction_brake_command(
self.packer_ch, get_friction_brake_bus(self.CP), hold_brake, idx, False, hold_near_stop, hold_standstill,
self.CP, allow_near_stop_mode=True))
CS.auto_hold_engaged = True
CS.auto_hold_fault_suppression_timer = 1.0
elif self.frame % 4 == 0 and volt_one_pedal_hold_active:
idx = (self.frame // 4) % 4
hold_brake = max(self.volt_one_pedal_brake, self.auto_hold_brake or estimate_auto_hold_brake(0.0, self.volt_one_pedal_brake, self.CP))
hold_standstill = CS.pcm_acc_status == AccState.STANDSTILL
hold_near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
can_sends.append(gmcan.create_friction_brake_command(
self.packer_ch, get_friction_brake_bus(self.CP), hold_brake, idx, False, hold_near_stop, hold_standstill,
self.CP, allow_near_stop_mode=True))
CS.auto_hold_engaged = True
CS.auto_hold_fault_suppression_timer = 1.0
elif self.frame % 4 == 0 and volt_one_pedal_braking:
idx = (self.frame // 4) % 4
near_stop = CS.out.vEgo < self.params.NEAR_STOP_BRAKE_PHASE
can_sends.append(gmcan.create_friction_brake_command(
self.packer_ch, get_friction_brake_bus(self.CP), self.volt_one_pedal_brake, idx, False, near_stop, False,
self.CP, allow_near_stop_mode=True))
CS.auto_hold_engaged = False
elif self.frame % 4 == 0:
self.apply_brake = 0
CS.auto_hold_engaged = False
# While car is braking, cancel button causes ECM to enter a soft disable state with a fault status.
# A delayed cancellation allows camera to cancel and avoids a fault when user depresses brake quickly
self.cancel_counter = self.cancel_counter + 1 if CC.cruiseControl.cancel else 0
+124 -40
View File
@@ -2,6 +2,7 @@ import copy
from cereal import custom
from opendbc.can import CANDefine, CANParser
from opendbc.car import Bus, create_button_events, structs
from opendbc.car import DT_CTRL
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.interfaces import CarStateBase
from opendbc.car.gm.values import (
@@ -26,15 +27,42 @@ TransmissionType = structs.CarParams.TransmissionType
NetworkLocation = structs.CarParams.NetworkLocation
STANDSTILL_THRESHOLD = 10 * 0.0311
VOLT_EBCM_BRAKE_PRESSED_THRESHOLD = 6 / 0xd0
AUTO_HOLD_MIN_DRIVE_TIME_S = 3.0
AUTO_HOLD_REGEN_RELEASE_COOLDOWN_S = 1.0
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
CruiseButtons.MAIN: ButtonType.mainCruise, CruiseButtons.CANCEL: ButtonType.cancel}
HARD_BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise}
NORMAL_CRUISE_BUTTONS = (CruiseButtons.RES_ACCEL, CruiseButtons.DECEL_SET)
def get_hard_cruise_buttons(steering_button_msg: dict) -> int:
return steering_button_msg.get("ACCButtonsHard", CruiseButtons.INIT)
GearShifter = structs.CarState.GearShifter
BOLT_GEN1_CANCEL_PERSONALITY_CARS = {
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
}
BOLT_CANCEL_BUTTON_CARS = BOLT_GEN1_CANCEL_PERSONALITY_CARS | {
CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
CAR.CHEVROLET_BOLT_CC_2022_2023,
}
def update_auto_hold_drive_timers(in_drive_for_hold: bool, moving_for_hold: bool,
auto_hold_drive_time: float, one_pedal_drive_time: float) -> tuple[float, float]:
if in_drive_for_hold:
if moving_for_hold:
auto_hold_drive_time = min(auto_hold_drive_time + DT_CTRL, AUTO_HOLD_MIN_DRIVE_TIME_S)
one_pedal_drive_time = min(one_pedal_drive_time + DT_CTRL, AUTO_HOLD_MIN_DRIVE_TIME_S)
else:
auto_hold_drive_time = 0.0
one_pedal_drive_time = 0.0
return auto_hold_drive_time, one_pedal_drive_time
class CarState(CarStateBase):
@@ -56,8 +84,17 @@ class CarState(CarStateBase):
self.prev_distance_button = 0
self.distance_button = 0
self.hard_cruise_buttons = CruiseButtons.INIT
self.force_reset_cruise_buttons = False
self.single_pedal_mode = False
self.auto_hold_armed = False
self.auto_hold_engaged = False
self.auto_hold_drive_time = 0.0
self.one_pedal_drive_time = 0.0
self.auto_hold_fault_suppression_timer = 0.0
self.regen_release_timer = 0.0
self.user_regen_paddle_pressed = False
self.pedal_steady = 0
self.ecm_cruise_control_ts_nanos = 0
@@ -66,6 +103,7 @@ class CarState(CarStateBase):
self.lkas_previously_enabled = 0
self.lkas_enabled = 0
self.pcm_acc_status = AccState.OFF
self.stock_fcw_alert = 0
def update_button_enable(self, buttonEvents: list[structs.CarState.ButtonEvent]):
if not self.CP.pcmCruise:
@@ -98,21 +136,36 @@ class CarState(CarStateBase):
sdgm_non_volt = self.CP.carFingerprint in SDGM_CAR and self.CP.carFingerprint not in kaofui_state_cars
prev_cruise_buttons = self.cruise_buttons
prev_hard_cruise_buttons = self.hard_cruise_buttons
prev_distance_button = self.distance_button
if not sdgm_non_volt:
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"]
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
self.steering_button_checksum = pt_cp.vl["ASCMSteeringButton"]["SteeringButtonChecksum"]
steering_button_msg = pt_cp.vl["ASCMSteeringButton"]
self.cruise_buttons = steering_button_msg["ACCButtons"]
self.hard_cruise_buttons = get_hard_cruise_buttons(steering_button_msg)
self.distance_button = steering_button_msg["DistanceButton"]
self.buttons_counter = steering_button_msg["RollingCounter"]
self.steering_button_checksum = steering_button_msg["SteeringButtonChecksum"]
self.steering_button_ts_nanos = pt_cp.ts_nanos["ASCMSteeringButton"]["ACCButtons"]
acc_always_one = pt_cp.vl["ASCMSteeringButton"]["ACCAlwaysOne"]
acc_hidden_bit = pt_cp.vl["ASCMSteeringButton"].get("ACCHiddenBit", 0)
acc_always_one = steering_button_msg["ACCAlwaysOne"]
acc_hidden_bit = steering_button_msg.get("ACCHiddenBit", 0)
self.steering_button_prefix = (int(acc_always_one) & 1) | ((int(acc_hidden_bit) & 1) << 6)
else:
self.cruise_buttons = cam_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.distance_button = cam_cp.vl["ASCMSteeringButton"]["DistanceButton"]
self.buttons_counter = cam_cp.vl["ASCMSteeringButton"]["RollingCounter"]
steering_button_msg = cam_cp.vl["ASCMSteeringButton"]
self.cruise_buttons = steering_button_msg["ACCButtons"]
self.hard_cruise_buttons = get_hard_cruise_buttons(steering_button_msg)
self.distance_button = steering_button_msg["DistanceButton"]
self.buttons_counter = steering_button_msg["RollingCounter"]
self.steering_button_ts_nanos = cam_cp.ts_nanos["ASCMSteeringButton"]["ACCButtons"]
# A GM hard press keeps the normal cruise button signal active too. Suppress
# the normal button until the wheel reports a different normal state.
if self.hard_cruise_buttons != CruiseButtons.INIT and self.cruise_buttons in NORMAL_CRUISE_BUTTONS:
self.force_reset_cruise_buttons = True
if self.force_reset_cruise_buttons and self.cruise_buttons in NORMAL_CRUISE_BUTTONS:
self.cruise_buttons = CruiseButtons.UNPRESS
elif self.force_reset_cruise_buttons and self.cruise_buttons not in NORMAL_CRUISE_BUTTONS:
self.force_reset_cruise_buttons = False
self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"])
self.moving_backward = (pt_cp.vl["EBCMWheelSpdRear"]["RLWheelDir"] == 2) or (pt_cp.vl["EBCMWheelSpdRear"]["RRWheelDir"] == 2)
@@ -153,9 +206,14 @@ class CarState(CarStateBase):
else:
ret.brake = pt_cp.vl["ECMAcceleratorPos"]["BrakePedalPos"]
if self.CP.carFingerprint in {CAR.CHEVROLET_MALIBU_CC} or (self.CP.carFingerprint == CAR.CHEVROLET_BLAZER and not no_accel_pos):
if self.CP.carFingerprint == CAR.CHEVROLET_VOLT and no_accel_pos:
ret.brakePressed = ret.brake >= VOLT_EBCM_BRAKE_PRESSED_THRESHOLD
elif self.CP.carFingerprint in {CAR.CHEVROLET_MALIBU_CC} or (self.CP.carFingerprint == CAR.CHEVROLET_BLAZER and not no_accel_pos):
ret.brakePressed = ret.brake >= 8
elif (self.CP.flags & GMFlags.FORCE_BRAKE_C9.value) or ((self.CP.networkLocation == NetworkLocation.fwdCamera) and (self.CP.carFingerprint != CAR.CHEVROLET_BLAZER)):
elif (self.CP.flags & GMFlags.FORCE_BRAKE_C9.value) or (
self.CP.networkLocation == NetworkLocation.fwdCamera and
self.CP.carFingerprint not in (SDGM_CAR | ASCM_INT | {CAR.CHEVROLET_BLAZER})
):
ret.brakePressed = pt_cp.vl["ECMEngineStatus"]["BrakePressed"] != 0
else:
# Some Volt 2016-17 have loose brake pedal push rod retainers which causes the ECM to believe
@@ -165,9 +223,19 @@ class CarState(CarStateBase):
analog_thresh = 0.10 if no_accel_pos else 8
ret.brakePressed = ret.brake >= analog_thresh
in_drive_for_hold = ret.gearShifter in (GearShifter.drive, GearShifter.low, GearShifter.manumatic)
self.auto_hold_drive_time, self.one_pedal_drive_time = update_auto_hold_drive_timers(
in_drive_for_hold, ret.vEgo > 0.1, self.auto_hold_drive_time, self.one_pedal_drive_time
)
if not in_drive_for_hold:
self.auto_hold_armed = False
self.auto_hold_engaged = False
# Regen braking is braking
if self.CP.transmissionType == TransmissionType.direct:
ret.regenBraking = pt_cp.vl["EBCMRegenPaddle"]["RegenPaddle"] != 0
if not ret.regenBraking and self.user_regen_paddle_pressed:
self.regen_release_timer = AUTO_HOLD_REGEN_RELEASE_COOLDOWN_S
self.single_pedal_mode = (ret.gearShifter == GearShifter.low or
pt_cp.vl["EVDriveMode"]["SinglePedalModeActive"] == 1 or
(ret.regenBraking and ret.gearShifter == GearShifter.manumatic) or
@@ -176,6 +244,10 @@ class CarState(CarStateBase):
CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
CAR.CHEVROLET_BOLT_CC_2022_2023,
} and self.CP.enableGasInterceptorDEPRECATED))
self.user_regen_paddle_pressed = ret.regenBraking
if self.regen_release_timer > 0.0:
self.regen_release_timer = max(self.regen_release_timer - DT_CTRL, 0.0)
if self.CP.enableGasInterceptorDEPRECATED:
gas = (pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2.
@@ -232,11 +304,20 @@ class CarState(CarStateBase):
ret.cruiseState.enabled = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] != AccState.OFF
ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL
self.stock_fcw_alert = 0
ret.stockFcw = False
if self.CP.networkLocation == NetworkLocation.fwdCamera and not self.CP.flags & GMFlags.NO_CAMERA.value:
if self.CP.carFingerprint not in CC_ONLY_CAR:
ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS
has_acc_dashboard_status = self.CP.carFingerprint not in CC_ONLY_CAR or self.CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL
if has_acc_dashboard_status:
acc_dashboard_status = cam_cp.vl["ASCMActiveCruiseControlStatus"]
if self.CP.carFingerprint not in CC_ONLY_CAR:
ret.cruiseState.speed = acc_dashboard_status["ACCSpeedSetpoint"] * CV.KPH_TO_MS
# Preserve the stock camera FCW level from 0x370 so the controller can
# replay it when that message is blocked and spoofed by openpilot long.
self.stock_fcw_alert = int(acc_dashboard_status["FCWAlert"])
ret.stockFcw = self.stock_fcw_alert != 0
if self.CP.carFingerprint not in (SDGM_CAR | ASCM_INT):
if self.CP.carFingerprint not in SDGM_CAR:
ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0
else:
ret.stockAeb = False
@@ -264,6 +345,10 @@ class CarState(CarStateBase):
self.ecm_cruise_control_ts_nanos = 0
self.accelerator_pedal2_ts_nanos = 0
if self.auto_hold_fault_suppression_timer > 0.0:
self.auto_hold_fault_suppression_timer = max(self.auto_hold_fault_suppression_timer - DT_CTRL, 0.0)
ret.accFaulted = False
if self.CP.enableBsm and not sdgm_non_volt:
ret.leftBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["LeftBSM"] == 1
ret.rightBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["RightBSM"] == 1
@@ -278,46 +363,34 @@ class CarState(CarStateBase):
self.lkas_enabled = pt_cp.vl["ASCMSteeringButton"]["LKAButton"]
self.pcm_acc_status = pt_cp.vl["AcceleratorPedal2"]["CruiseState"]
# Only activate cancel remap when panda safety was configured for it at startup.
remap_cancel_to_distance = bool(self.CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE)
if not remap_cancel_to_distance:
remap_cancel_to_distance = (
getattr(starpilot_toggles, "remap_cancel_to_distance", False) and
self.CP.openpilotLongitudinalControl and
bool(self.CP.flags & GMFlags.PEDAL_LONG.value) and
self.CP.carFingerprint in (BOLT_GEN1_CANCEL_PERSONALITY_CARS | {CAR.CHEVROLET_MALIBU_HYBRID_CC})
)
malibu_cancel_passthrough = (
remap_cancel_to_distance and
self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC and
self.CP.openpilotLongitudinalControl and
bool(self.CP.flags & GMFlags.PEDAL_LONG.value)
)
bolt_cancel_personality = (
bolt_cancel_button = (
remap_cancel_to_distance and
self.CP.carFingerprint in BOLT_GEN1_CANCEL_PERSONALITY_CARS and
self.CP.carFingerprint in BOLT_CANCEL_BUTTON_CARS and
self.CP.openpilotLongitudinalControl and
bool(self.CP.flags & GMFlags.PEDAL_LONG.value)
)
bolt_cancel_lkas_conflict = bolt_cancel_button and self.CP.carFingerprint in BOLT_GEN1_CANCEL_PERSONALITY_CARS
cruise_button_map = BUTTONS_DICT
if malibu_cancel_passthrough or bolt_cancel_personality:
if malibu_cancel_passthrough or bolt_cancel_button:
cruise_button_map = {k: v for k, v in BUTTONS_DICT.items() if k != CruiseButtons.CANCEL}
cruise_events = create_button_events(
self.cruise_buttons, prev_cruise_buttons, cruise_button_map, unpressed_btn=CruiseButtons.UNPRESS
)
cancel_gap_events = []
if bolt_cancel_personality and self.cruise_buttons != prev_cruise_buttons:
if prev_cruise_buttons == CruiseButtons.CANCEL:
cancel_gap_events.append(structs.CarState.ButtonEvent(pressed=False, type=ButtonType.gapAdjustCruise))
if self.cruise_buttons == CruiseButtons.CANCEL:
cancel_gap_events.append(structs.CarState.ButtonEvent(pressed=True, type=ButtonType.gapAdjustCruise))
suppress_malibu_side_buttons = malibu_cancel_passthrough and (
self.cruise_buttons in (CruiseButtons.CANCEL, CruiseButtons.MAIN) or
prev_cruise_buttons in (CruiseButtons.CANCEL, CruiseButtons.MAIN)
)
suppress_bolt_cancel_lkas = bolt_cancel_personality and (
suppress_bolt_cancel_lkas = bolt_cancel_lkas_conflict and (
self.cruise_buttons == CruiseButtons.CANCEL or
prev_cruise_buttons == CruiseButtons.CANCEL
)
@@ -327,23 +400,28 @@ class CarState(CarStateBase):
lkas_events = [] if (suppress_malibu_side_buttons or suppress_bolt_cancel_lkas) else create_button_events(
self.lkas_enabled, self.lkas_previously_enabled, {1: ButtonType.lkas}
)
hard_cruise_events = create_button_events(
self.hard_cruise_buttons, prev_hard_cruise_buttons, HARD_BUTTONS_DICT, unpressed_btn=CruiseButtons.INIT
)
# Don't add events if transitioning from INIT, unless it's to an actual button.
if self.cruise_buttons != CruiseButtons.UNPRESS or prev_cruise_buttons != CruiseButtons.INIT:
if (self.cruise_buttons != CruiseButtons.UNPRESS or prev_cruise_buttons != CruiseButtons.INIT or
self.hard_cruise_buttons != CruiseButtons.INIT or prev_hard_cruise_buttons != CruiseButtons.INIT):
ret.buttonEvents = [
*cruise_events,
*cancel_gap_events,
*distance_events,
*lkas_events,
*hard_cruise_events,
]
if ret.vEgo < self.CP.minSteerSpeed:
ret.lowSpeedAlert = True
fp_ret = custom.StarPilotCarState.new_message()
if bolt_cancel_personality and self.cruise_buttons == CruiseButtons.CANCEL:
# Feed long-press personality logic as if distance is held while CANCEL is held.
fp_ret.distancePressed = True
fp_ret.accelHardCruise = self.hard_cruise_buttons == CruiseButtons.RES_ACCEL or prev_hard_cruise_buttons == CruiseButtons.RES_ACCEL
fp_ret.decelHardCruise = self.hard_cruise_buttons == CruiseButtons.DECEL_SET or prev_hard_cruise_buttons == CruiseButtons.DECEL_SET
if bolt_cancel_button and self.cruise_buttons == CruiseButtons.CANCEL:
fp_ret.cancelPressed = True
fp_ret.sportGear = pt_cp.vl["SportMode"]["SportMode"] == 1
return ret, fp_ret
@@ -393,7 +471,7 @@ class CarState(CarStateBase):
("ASCMSteeringButton", 33),
]
if CP.enableBsm:
pt_messages.append(("BCMBlindSpotMonitor", 10))
pt_messages.append(("BCMBlindSpotMonitor", 0))
if CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value:
if ("ECMAcceleratorPos", 80) in pt_messages:
@@ -435,8 +513,14 @@ class CarState(CarStateBase):
("ASCMSteeringButton", 33),
]
if CP.enableBsm:
cam_messages.append(("BCMBlindSpotMonitor", 10))
elif CP.carFingerprint not in (SDGM_CAR | ASCM_INT):
cam_messages.append(("BCMBlindSpotMonitor", 0))
elif CP.carFingerprint in ASCM_INT:
# Volt/ASCM-int variants don't reliably have AEBCmd present at startup,
# but when it appears we still want to surface OEM AEB state.
cam_messages += [
("AEBCmd", 0),
]
elif CP.carFingerprint not in SDGM_CAR:
cam_messages += [
("AEBCmd", 10),
]
@@ -7,6 +7,7 @@ from opendbc.car.gm.values import CAR
CAMERA_DIAGNOSTIC_ADDRESS = 0x24b
CAMERA_DIAGNOSTIC_RX_ADDRESS = 0x64b
SASCM_ADDRESS = 0x2FF
FINGERPRINTS = {
@@ -210,12 +211,17 @@ FINGERPRINTS.update({
CAR.GMC_ACADIA_ASCM: FINGERPRINTS[CAR.GMC_ACADIA],
CAR.CHEVROLET_MALIBU_ASCM: FINGERPRINTS[CAR.CHEVROLET_MALIBU],
CAR.CADILLAC_ESCALADE_ASCM: FINGERPRINTS[CAR.CADILLAC_ESCALADE],
CAR.CADILLAC_ESCALADE_ESV_2019_ASCM: [{**fp, SASCM_ADDRESS: 8} for fp in FINGERPRINTS[CAR.CADILLAC_ESCALADE_ESV_2019]],
CAR.CHEVROLET_SUBURBAN: FINGERPRINTS[CAR.CHEVROLET_SUBURBAN_CC],
CAR.GMC_YUKON_CC: FINGERPRINTS[CAR.GMC_YUKON],
CAR.CADILLAC_XT6: FINGERPRINTS[CAR.CHEVROLET_TRAVERSE],
CAR.CADILLAC_XT5: FINGERPRINTS[CAR.CHEVROLET_TRAVERSE],
CAR.CHEVROLET_BLAZER: FINGERPRINTS[CAR.CHEVROLET_TRAVERSE],
CAR.CHEVROLET_MALIBU_SDGM: FINGERPRINTS[CAR.CHEVROLET_MALIBU_CC],
CAR.BUICK_BABYENCLAVE: FINGERPRINTS[CAR.CHEVROLET_TRAVERSE],
CAR.CHEVROLET_SILVERADO_CC: FINGERPRINTS[CAR.CHEVROLET_SILVERADO],
CAR.CADILLAC_XT4_CC: FINGERPRINTS[CAR.CADILLAC_XT4],
CAR.BUICK_LACROSSE_ASCM: FINGERPRINTS[CAR.BUICK_LACROSSE],
})
FW_VERSIONS: dict[str, dict[tuple, list[bytes]]] = {
+121 -17
View File
@@ -17,6 +17,18 @@ MALIBU_BUTTON_MAP = {
CruiseButtons.CANCEL: 5,
}
ACC_CRUISE_STATE_ADAPTIVE = 2
XT4_CC_BUTTON_BURST_FRAMES = 6
XT4_CC_BUTTON_COUNTER_DELAY_FRAMES = 1
BOLT_CC_BUTTON_CARS = {
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
CAR.CHEVROLET_BOLT_CC_2022_2023,
}
BOLT_CC_TARGET_DEADBAND_MPH = 0.75
BOLT_CC_REVERSE_CONFIRM_S = 0.6
BOLT_CC_DIRECTION_MEMORY_S = 1.5
def malibu_phase_map_for_button(button):
key = MALIBU_BUTTON_MAP.get(button)
@@ -179,22 +191,28 @@ def create_ecm_cruise_control_command(packer, bus, enabled, target_speed_kph):
return CanData(0x3D1, bytes(dat), bus)
def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_stop, at_full_stop, CP):
def get_friction_brake_mode(apply_brake, enabled, near_stop, at_full_stop, CP, allow_near_stop_mode=False):
mode = 0x1
# TODO: Understand this better. Volts and ICE Camera ACC cars are 0x1 when enabled with no brake
if enabled and CP.carFingerprint in (CAR.CHEVROLET_BOLT_ACC_2022_2023,):
if enabled and CP.carFingerprint in (CAR.CHEVROLET_BOLT_ACC_2022_2023, CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL):
mode = 0x9
if apply_brake > 0:
mode = 0xa
if at_full_stop:
mode = 0xd
elif allow_near_stop_mode and near_stop:
# Stock Volt auto hold can run with cruise main on but ACC inactive, so
# there is no stock STANDSTILL state to promote 0xa -> 0xd. Restore the
# older near-stop hold mode only for that path.
mode = 0xb
# TODO: this is to have GM bringing the car to complete stop,
# but currently it conflicts with OP controls, so turned off. Not set by all cars
#elif near_stop:
# mode = 0xb
return mode
def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_stop, at_full_stop, CP, allow_near_stop_mode=False):
mode = get_friction_brake_mode(apply_brake, enabled, near_stop, at_full_stop, CP, allow_near_stop_mode)
brake = (0x1000 - apply_brake) & 0xfff
checksum = (0x10000 - (mode << 12) - brake - idx) & 0xffff
@@ -209,18 +227,26 @@ def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_s
return packer.make_can_msg("EBCMFrictionBrakeCmd", bus, values)
def create_acc_dashboard_command(packer, bus, enabled, target_speed_kph, hud_control, fcw):
def create_acc_2cd_command(bus, idx):
dat = bytearray([0x00, 0x2c, 0x03, 0xd3, 0x00])
dat[0] = (idx & 0x3) << 6
dat[4] = (0xfd - (idx & 0x3)) & 0xff
return CanData(0x2CD, bytes(dat), bus)
def create_acc_dashboard_command(packer, bus, enabled, target_speed_kph, hud_control, fcw_alert, acc_always_one=1):
target_speed = min(target_speed_kph, 255)
values = {
"ACCAlwaysOne": 1,
"ACCAlwaysOne": acc_always_one,
"ACCCruiseState": ACC_CRUISE_STATE_ADAPTIVE,
"ACCResumeButton": 0,
"ACCSpeedSetpoint": target_speed,
"ACCGapLevel": hud_control.leadDistanceBars * enabled, # 3 "far", 0 "inactive"
"ACCCmdActive": enabled,
"ACCAlwaysOne2": 1,
"ACCAlwaysOne2": acc_always_one,
"ACCLeadCar": hud_control.leadVisible,
"FCWAlert": 0x3 if fcw else 0
"FCWAlert": int(fcw_alert) & 0x3,
}
return packer.make_can_msg("ASCMActiveCruiseControlStatus", bus, values)
@@ -280,32 +306,110 @@ def create_lka_icon_command(bus, active, critical, steer):
return CanData(0x104c006c, dat, bus)
def stabilize_bolt_cc_button(controller, CP, requested_button):
if CP.carFingerprint not in BOLT_CC_BUTTON_CARS:
return requested_button
direction_buttons = (CruiseButtons.RES_ACCEL, CruiseButtons.DECEL_SET)
if requested_button not in direction_buttons:
controller.gm_cc_pending_reverse_button = CruiseButtons.INIT
return requested_button
last_button = getattr(controller, "gm_cc_last_direction_button", CruiseButtons.INIT)
last_frame = getattr(controller, "gm_cc_last_direction_frame", -int(BOLT_CC_DIRECTION_MEMORY_S / DT_CTRL) - 1)
recently_sent = (controller.frame - last_frame) * DT_CTRL <= BOLT_CC_DIRECTION_MEMORY_S
reversing_to_accel = (last_button == CruiseButtons.DECEL_SET and
requested_button == CruiseButtons.RES_ACCEL and recently_sent)
if reversing_to_accel:
pending_button = getattr(controller, "gm_cc_pending_reverse_button", CruiseButtons.INIT)
if pending_button != requested_button:
controller.gm_cc_pending_reverse_button = requested_button
controller.gm_cc_pending_reverse_frame = controller.frame
return CruiseButtons.INIT
pending_frame = getattr(controller, "gm_cc_pending_reverse_frame", controller.frame)
if (controller.frame - pending_frame) * DT_CTRL < BOLT_CC_REVERSE_CONFIRM_S:
return CruiseButtons.INIT
controller.gm_cc_pending_reverse_button = CruiseButtons.INIT
return requested_button
def create_gm_cc_spam_command(packer, controller, CS, actuators, starpilot_toggles):
accel = actuators.accel
v_ego = CS.out.vEgo
cruise_btn = CruiseButtons.INIT
rate = 1 if abs(accel) <= 0.15 else 0.2
ms_convert = CV.MS_TO_KPH if getattr(starpilot_toggles, "is_metric", False) else CV.MS_TO_MPH
is_metric = getattr(starpilot_toggles, "is_metric", False)
ms_convert = CV.MS_TO_KPH if is_metric else CV.MS_TO_MPH
speed_setpoint = int(round(CS.out.cruiseState.speed * ms_convert))
desired_setpoint = int(round((v_ego * 1.01 + 3 * accel) * ms_convert))
projected_setpoint = (v_ego * 1.01 + 3 * accel) * ms_convert
desired_setpoint = int(round(projected_setpoint))
bolt_cc = CS.CP.carFingerprint in BOLT_CC_BUTTON_CARS
target_deadband = BOLT_CC_TARGET_DEADBAND_MPH * (CV.MPH_TO_KPH if is_metric else 1.0) if bolt_cc else 0.0
comparison_setpoint = projected_setpoint if bolt_cc else desired_setpoint
if CS.CP.minEnableSpeed - (desired_setpoint / ms_convert) > 3.25:
cruise_btn = CruiseButtons.CANCEL
controller.apply_speed = 0
elif desired_setpoint < speed_setpoint and speed_setpoint > CS.CP.minEnableSpeed * ms_convert + 1:
elif comparison_setpoint < speed_setpoint - target_deadband and speed_setpoint > CS.CP.minEnableSpeed * ms_convert + 1:
cruise_btn = CruiseButtons.DECEL_SET
controller.apply_speed = speed_setpoint - 1
elif desired_setpoint > speed_setpoint:
elif comparison_setpoint > speed_setpoint + target_deadband:
cruise_btn = CruiseButtons.RES_ACCEL
cruise_btn = stabilize_bolt_cc_button(controller, CS.CP, cruise_btn)
if cruise_btn == CruiseButtons.CANCEL:
controller.apply_speed = 0
elif cruise_btn == CruiseButtons.DECEL_SET:
controller.apply_speed = speed_setpoint - 1
elif cruise_btn == CruiseButtons.RES_ACCEL:
controller.apply_speed = speed_setpoint + 1
else:
cruise_btn = CruiseButtons.INIT
controller.apply_speed = speed_setpoint
if CS.CP.carFingerprint == CAR.CADILLAC_XT4_CC:
if controller.xt4_cc_button_observed_counter != CS.buttons_counter:
controller.xt4_cc_button_observed_counter = CS.buttons_counter
controller.xt4_cc_button_counter_frame = controller.frame
if cruise_btn == CruiseButtons.INIT:
controller.xt4_cc_button_burst_remaining = 0
controller.xt4_cc_button_burst_button = CruiseButtons.INIT
return []
if (controller.xt4_cc_button_burst_remaining > 0 and
controller.xt4_cc_button_burst_button != cruise_btn):
controller.xt4_cc_button_burst_remaining = 0
if controller.xt4_cc_button_burst_remaining == 0:
if (controller.frame - controller.last_button_frame) * DT_CTRL <= rate:
return []
controller.last_button_frame = controller.frame
controller.xt4_cc_button_burst_button = cruise_btn
controller.xt4_cc_button_burst_remaining = XT4_CC_BUTTON_BURST_FRAMES
controller.xt4_cc_button_burst_last_counter = -1
# XT4 physical taps hold the button for 5-7 consecutive 33 Hz frames.
# Sending immediately after the stock frame is too early for the receiving ECU.
if controller.frame - controller.xt4_cc_button_counter_frame < XT4_CC_BUTTON_COUNTER_DELAY_FRAMES:
return []
# Send once per observed stock counter so the injected sequence has the same cadence.
if controller.xt4_cc_button_burst_last_counter == CS.buttons_counter:
return []
controller.xt4_cc_button_burst_last_counter = CS.buttons_counter
controller.xt4_cc_button_burst_remaining -= 1
idx = (CS.buttons_counter + 1) % 4
return [create_buttons(packer, CanBus.POWERTRAIN, idx, controller.xt4_cc_button_burst_button)]
# Check rlogs closely - our message shouldn't show up on the pt bus for us
# Or bus 2, since we're forwarding... but I think it does
if (cruise_btn != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate):
controller.last_button_frame = controller.frame
if bolt_cc and cruise_btn in (CruiseButtons.RES_ACCEL, CruiseButtons.DECEL_SET):
controller.gm_cc_last_direction_button = cruise_btn
controller.gm_cc_last_direction_frame = controller.frame
if CS.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
phase_map = malibu_phase_map_for_button(cruise_btn)
if phase_map:
+127 -15
View File
@@ -58,8 +58,32 @@ NON_LINEAR_TORQUE_PARAMS = {
"left": [3.8, 0.81, 0.24, 0.0465122],
"right": [3.8, 0.81, 0.24, 0.0465122],
},
CAR.CHEVROLET_SILVERADO_CC: {
"left": [3.8, 0.81, 0.24, 0.0465122],
"right": [3.8, 0.81, 0.24, 0.0465122],
},
CAR.CADILLAC_XT4: {
"left": [2.4, 0.95, 0.28, 0.0],
"right": [2.4, 0.95, 0.28, 0.0],
},
CAR.CHEVROLET_VOLT: {
"left": [1.525, 1.05, 0.155, 0.0],
"right": [1.525, 0.95, 0.150, 0.0],
},
}
NON_LINEAR_TORQUE_PARAM_ALIASES = {
CAR.CHEVROLET_VOLT_ASCM: CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_CAMERA: CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_CC: CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_2019: CAR.CHEVROLET_VOLT,
}
def get_nonlinear_torque_params(car_fingerprint):
source_fingerprint = NON_LINEAR_TORQUE_PARAM_ALIASES.get(car_fingerprint, car_fingerprint)
return NON_LINEAR_TORQUE_PARAMS.get(source_fingerprint)
PEDAL_MSG = 0x201
CAM_MSG = 0x320
ACCELERATOR_POS_MSG = 0xBE
@@ -85,6 +109,14 @@ VOLT_LONG_TEST_TUNE_CARS = {
CAR.CHEVROLET_VOLT_CC,
}
VOLT_BSM_CARS = {
CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_2019,
CAR.CHEVROLET_VOLT_ASCM,
CAR.CHEVROLET_VOLT_CAMERA,
CAR.CHEVROLET_VOLT_CC,
}
BOLT_PEDAL_LONG_CARS = {
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
@@ -93,12 +125,16 @@ BOLT_PEDAL_LONG_CARS = {
CAR.CHEVROLET_MALIBU_HYBRID_CC,
}
# Cancel-to-personality mapping target: gen1 Bolt pedal-long paths only.
# Cancel-button remap support uses the same safety path on all pedal-long Bolts,
# but only gen1 needs extra LKAS suppression in CarState.
BOLT_GEN1_CANCEL_PERSONALITY_CARS = {
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
}
CANCEL_REMAP_DISTANCE_CARS = BOLT_GEN1_CANCEL_PERSONALITY_CARS
CANCEL_REMAP_DISTANCE_CARS = BOLT_GEN1_CANCEL_PERSONALITY_CARS | {
CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
CAR.CHEVROLET_BOLT_CC_2022_2023,
}
class CarInterface(CarInterfaceBase):
@@ -109,7 +145,11 @@ class CarInterface(CarInterfaceBase):
@staticmethod
def get_pid_accel_limits(CP, current_speed, cruise_speed):
if CP.enableGasInterceptorDEPRECATED and bool(CP.flags & GMFlags.PEDAL_LONG.value):
if CP.carFingerprint in BOLT_PEDAL_LONG_CARS:
if CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL:
accel_min = CarControllerParams.ACCEL_MIN
accel_max = np.interp(current_speed, [0.0, 1.5, 4.0, 8.0, 15.0],
[0.54, 0.74, 1.03, 1.46, CarControllerParams.ACCEL_MAX])
elif CP.carFingerprint in BOLT_PEDAL_LONG_CARS:
accel_min = np.interp(current_speed, [0.0, 1.5, 4.0, 8.0, 15.0, 30.0],
[-0.93, -1.28, -1.98, -2.58, -2.86, -2.95])
accel_max = np.interp(current_speed, [0.0, 1.5, 4.0, 8.0, 15.0],
@@ -141,7 +181,7 @@ class CarInterface(CarInterfaceBase):
# The "lat_accel vs torque" relationship is assumed to be the sum of "sigmoid + linear" curves
# An important thing to consider is that the slope at 0 should be > 0 (ideally >1)
# This has big effect on the stability about 0 (noise when going straight)
non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint)
non_linear_torque_params = get_nonlinear_torque_params(self.CP.carFingerprint)
assert non_linear_torque_params, "The params are not defined"
if isinstance(non_linear_torque_params, dict):
side_key = "left" if lateral_acceleration >= 0 else "right"
@@ -159,7 +199,7 @@ class CarInterface(CarInterfaceBase):
return torque_values, lataccel_values
def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType:
if self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS:
if get_nonlinear_torque_params(self.CP.carFingerprint) is not None:
torque_values, lataccel_values = self.get_lataccel_torque_siglin()
def torque_from_lateral_accel_siglin(lateral_acceleration: float, torque_params: structs.CarParams.LateralTorqueTuning):
@@ -169,7 +209,7 @@ class CarInterface(CarInterfaceBase):
return self.torque_from_lateral_accel_linear
def lateral_accel_from_torque(self) -> LateralAccelFromTorqueCallbackType:
if self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS:
if get_nonlinear_torque_params(self.CP.carFingerprint) is not None:
torque_values, lataccel_values = self.get_lataccel_torque_siglin()
def lateral_accel_from_torque_siglin(torque: float, torque_params: structs.CarParams.LateralTorqueTuning):
@@ -189,11 +229,20 @@ class CarInterface(CarInterfaceBase):
disable_openpilot_long = params.get_bool("DisableOpenpilotLongitudinal")
except UnknownKeyName:
disable_openpilot_long = False
try:
gm_auto_hold = params.get_bool("GMAutoHold")
except UnknownKeyName:
gm_auto_hold = False
try:
volt_one_pedal_mode = params.get_bool("VoltOnePedalMode")
except UnknownKeyName:
volt_one_pedal_mode = False
ret.brand = "gm"
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.gm)]
ret.autoResumeSng = False
ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN]
# Some Volt installs don't expose the BSM frame during startup fingerprinting.
ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN] or candidate in VOLT_BSM_CARS
has_sascm = 0x2FF in fingerprint[CanBus.POWERTRAIN]
if has_sascm:
ret.flags |= GMFlags.SASCM.value
@@ -385,8 +434,10 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.BUICK_LACROSSE:
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate in (CAR.BUICK_LACROSSE, CAR.BUICK_LACROSSE_ASCM, CAR.BUICK_LACROSSE_ASCM_19US):
CarInterfaceBase.configure_torque_tune(CAR.BUICK_LACROSSE, ret.lateralTuning)
if candidate == CAR.BUICK_LACROSSE_ASCM_19US:
ret.minSteerSpeed = 27 * CV.MPH_TO_MS
elif candidate == CAR.CADILLAC_ESCALADE:
ret.minEnableSpeed = -1. # engage speed is decided by pcm
@@ -395,7 +446,7 @@ class CarInterface(CarInterfaceBase):
elif candidate == CAR.CADILLAC_ESCALADE_ASCM:
CarInterfaceBase.configure_torque_tune(CAR.CADILLAC_ESCALADE, ret.lateralTuning)
elif candidate in (CAR.CADILLAC_ESCALADE_ESV, CAR.CADILLAC_ESCALADE_ESV_2019):
elif candidate in (CAR.CADILLAC_ESCALADE_ESV, CAR.CADILLAC_ESCALADE_ESV_2019, CAR.CADILLAC_ESCALADE_ESV_2019_ASCM):
ret.minEnableSpeed = -1. # engage speed is decided by pcm
if candidate == CAR.CADILLAC_ESCALADE_ESV:
@@ -404,7 +455,8 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kf = 0.000045
else:
ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
torque_candidate = CAR.CADILLAC_ESCALADE_ESV_2019 if candidate == CAR.CADILLAC_ESCALADE_ESV_2019_ASCM else candidate
CarInterfaceBase.configure_torque_tune(torque_candidate, ret.lateralTuning)
elif candidate in (
CAR.CHEVROLET_BOLT_ACC_2022_2023,
@@ -444,7 +496,7 @@ class CarInterface(CarInterfaceBase):
# ACC Bolts use pedal for full longitudinal control, not just SNG.
ret.flags |= GMFlags.PEDAL_LONG.value
elif candidate == CAR.CHEVROLET_SILVERADO:
elif candidate in (CAR.CHEVROLET_SILVERADO, CAR.CHEVROLET_SILVERADO_CC):
# On the Bolt, the ECM and camera independently check that you are either above 5 kph or at a stop
# with foot on brake to allow engagement, but this platform only has that check in the camera.
# TODO: check if this is split by EV/ICE with more platforms in the future
@@ -457,7 +509,7 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.CADILLAC_XT4:
elif candidate in (CAR.CADILLAC_XT4, CAR.CADILLAC_XT4_CC):
ret.steerActuatorDelay = 0.2
if not ret.openpilotLongitudinalControl:
ret.minEnableSpeed = -1.
@@ -481,7 +533,7 @@ class CarInterface(CarInterfaceBase):
ret.minSteerSpeed = 7 * CV.MPH_TO_MS
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.CADILLAC_XT5_CC:
elif candidate in (CAR.CADILLAC_XT5, CAR.CADILLAC_XT5_CC):
ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
@@ -490,7 +542,19 @@ class CarInterface(CarInterfaceBase):
if not ret.openpilotLongitudinalControl:
ret.minEnableSpeed = -1.
if candidate == CAR.CHEVROLET_BLAZER:
# The Blazer builds brake torque noticeably later than the rest of the GM set.
# A slightly larger planner delay estimate starts the request earlier and keeps
# stopped-lead approaches from turning into a late, harsh max-brake catch-up.
ret.longitudinalActuatorDelay = 0.7
ret.longitudinalTuning.kpBP = [0.0, 4.0, 12.0, 35.0]
ret.longitudinalTuning.kpV = [0.09, 0.075, 0.055, 0.040]
ret.longitudinalTuning.kiBP = [0.0, 4.0, 12.0, 35.0]
ret.longitudinalTuning.kiV = [0.03, 0.04, 0.055, 0.07]
ret.minEnableSpeed = 5 * CV.KPH_TO_MS
ret.stoppingDecelRate = 1.0
ret.vEgoStopping = 0.35
ret.vEgoStarting = 0.35
ret.stopAccel = -0.30
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.BUICK_BABYENCLAVE:
@@ -539,12 +603,16 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kpV = [0.095, 0.085, 0.065, 0.050]
ret.longitudinalTuning.kiV = [0.07, 0.10, 0.15, 0.24]
ret.longitudinalTuning.kfDEPRECATED = 0.20
ret.longitudinalActuatorDelay = 0.6
else:
ret.longitudinalTuning.kfDEPRECATED = 0.25
if is_bolt_2022_2023_pedal:
# Gen2 Bolt pedal-long should follow the no-ACC panda path.
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_ACC.value
ret.startingState = True
ret.startAccel = 0.55
ret.vEgoStarting = max(ret.vEgoStarting, 0.35)
if candidate in (CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL, CAR.CHEVROLET_MALIBU_HYBRID_CC):
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_BOLT_2022_PEDAL.value
@@ -584,6 +652,12 @@ class CarInterface(CarInterfaceBase):
ret.startAccel = 1.15
ret.vEgoStarting = max(ret.vEgoStarting, 0.35)
if ret.openpilotLongitudinalControl and candidate in (CAR.CHEVROLET_SILVERADO, CAR.CHEVROLET_SILVERADO_CC) and not ret.enableGasInterceptorDEPRECATED:
ret.longitudinalTuning.kpBP = [0.0, 5.0, 15.0, 35.0]
ret.longitudinalTuning.kpV = [0.02, 0.03, 0.028, 0.022]
ret.longitudinalTuning.kiBP = [0.0, 5.0, 15.0, 35.0]
ret.longitudinalTuning.kiV = [0.20, 0.18, 0.13, 0.08]
elif candidate in CC_ONLY_CAR and not ret.enableGasInterceptorDEPRECATED:
ret.flags |= GMFlags.CC_LONG.value
ret.alphaLongitudinalAvailable = False
@@ -614,12 +688,15 @@ class CarInterface(CarInterfaceBase):
# Exception for flashed cars, or cars whose camera was removed.
missing_camera_msg = CAM_MSG not in fingerprint.get(CanBus.CAMERA, {})
if (ret.networkLocation == NetworkLocation.fwdCamera or candidate in CC_ONLY_CAR) and missing_camera_msg and candidate not in SDGM_CAR:
if (ret.networkLocation == NetworkLocation.fwdCamera or candidate in CC_ONLY_CAR) and missing_camera_msg and candidate not in (ASCM_INT | SDGM_CAR):
ret.flags |= GMFlags.NO_CAMERA.value
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_CAMERA.value
if ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]:
ret.flags |= GMFlags.NO_ACCELERATOR_POS_MSG.value
if candidate == CAR.CHEVROLET_VOLT and ret.networkLocation == NetworkLocation.gateway:
# Reuse the no-camera safety bit as an ASCM Volt selector for the alternate EBCM brake path.
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_CAMERA.value
try:
remote_start_boots_comma = params.get_bool("RemoteStartBootsComma")
@@ -629,6 +706,41 @@ class CarInterface(CarInterfaceBase):
if remote_start_boots_comma:
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_REMOTE_START_BOOTS_COMMA.value
volt_stock_friction_brake_safety = (
ret.openpilotLongitudinalControl and
(gm_auto_hold or volt_one_pedal_mode) and
candidate in {
CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_2019,
CAR.CHEVROLET_VOLT_ASCM,
CAR.CHEVROLET_VOLT_CAMERA,
}
)
if volt_stock_friction_brake_safety:
# Reuse the paddle-scheduler safety bit as a Volt stock friction-brake
# marker on non-pedal paths. Auto hold and one-pedal can run while OP
# longitudinal is configured but not currently active, so the bit must
# be present regardless of the current long-control mode. Do not expose
# the path at all when OP long is disabled in CarParams.
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value
volt_stock_one_pedal_safety = (
ret.openpilotLongitudinalControl and
volt_one_pedal_mode and
candidate in {
CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_2019,
CAR.CHEVROLET_VOLT_ASCM,
CAR.CHEVROLET_VOLT_CAMERA,
}
)
if volt_stock_one_pedal_safety:
# Reuse the 3D1 scheduler bit as a Volt one-pedal marker on non-pedal
# ACC paths. The bit is ignored by the actual 3D1 scheduler unless the
# car is on a pedal-long CC-only path, so this stays isolated from Bolt.
# Do not expose the path at all when OP long is disabled in CarParams.
ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_PANDA_3D1_SCHED.value
use_panda_3d1_sched = (
ret.openpilotLongitudinalControl and
ret.enableGasInterceptorDEPRECATED and
@@ -0,0 +1,993 @@
import sys
import types
from types import SimpleNamespace
import numpy as np
import pytest
from opendbc.car import structs
fake_interfaces = types.ModuleType("opendbc.car.interfaces")
class _FakeCarControllerBase:
def __init__(self, dbc_names=None, CP=None):
self.CP = CP
fake_interfaces.CarControllerBase = _FakeCarControllerBase
sys.modules.setdefault("opendbc.car.interfaces", fake_interfaces)
fake_params = types.ModuleType("openpilot.common.params")
class _FakeParams:
pass
class _FakeUnknownKeyName(Exception):
pass
fake_params.Params = _FakeParams
fake_params.UnknownKeyName = _FakeUnknownKeyName
sys.modules.setdefault("openpilot.common.params", fake_params)
fake_testing_grounds = types.ModuleType("openpilot.starpilot.common.testing_grounds")
fake_testing_grounds.testing_ground = SimpleNamespace(use_1=False)
sys.modules.setdefault("openpilot.starpilot.common.testing_grounds", fake_testing_grounds)
from opendbc.car.gm.carcontroller import (
AUTO_HOLD_DRIVE_GEARS,
CarController,
estimate_auto_hold_brake,
get_adas_keepalive_step,
get_auto_hold_stop_threshold,
get_bolt_acc_pedal_friction_brake,
get_bolt_acc_pedal_friction_command_state,
get_bolt_acc_pedal_effective_brake_switch,
get_bolt_acc_pedal_planner_brake_switch,
get_bolt_pedal_long_accel_limit,
get_interceptor_sng_gas_cmd,
get_lka_steering_cmd_counter,
get_volt_one_pedal_target_decel,
get_testing_ground_1_brake_switch_bias,
get_acc_dashboard_status_active,
get_stock_cc_active_for_cancel,
shape_bolt_acc_pedal_low_speed_friction,
shape_truck_friction_brake,
shape_truck_pitch_accel,
shape_truck_positive_accel,
should_use_fixed_stopping_brake,
should_activate_auto_hold,
should_activate_volt_one_pedal,
should_send_acc_2cd,
should_send_adas_status,
should_send_stock_long_cancel,
should_spoof_dash_speed,
should_spoof_ecm_cruise_status,
supports_bolt_acc_pedal_friction_experiment,
supports_volt_auto_hold,
supports_volt_one_pedal,
use_interceptor_sng_launch,
)
from opendbc.car.gm.gmcan import get_friction_brake_mode
from opendbc.car.gm.values import AccState, CAR, CarControllerParams, GMFlags
from opendbc.car.structs import CarParams
from opendbc.car.common.conversions import Conversions as CV
def _cs(enabled, pcm_acc_status):
return SimpleNamespace(
out=SimpleNamespace(cruiseState=SimpleNamespace(enabled=enabled), accFaulted=False),
pcm_acc_status=pcm_acc_status,
)
def _sng_cs(v_ego, standstill, cruise_standstill):
return SimpleNamespace(
out=SimpleNamespace(
vEgo=v_ego,
standstill=standstill,
cruiseState=SimpleNamespace(standstill=cruise_standstill),
),
)
def _controller(car_fingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021):
controller = CarController.__new__(CarController)
controller.CP = SimpleNamespace(carFingerprint=car_fingerprint)
controller.planner_regen_hold = False
controller.regen_paddle_pressed = False
controller.regen_paddle_timer = 0
controller.regen_press_counter = 0
controller.regen_release_counter = 0
controller.regen_min_on_frames = 0
controller.regen_min_off_frames = 0
controller.pedal_active_last = False
controller.pedal_steady = 0.0
controller.aego = 0.0
controller.maneuver_paddle_mode = "auto"
controller.bolt_acc_pedal_friction_low_speed_active = False
return controller
def test_gen1_bolt_pedal_cancel_uses_pcm_acc_status():
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021)
assert get_stock_cc_active_for_cancel(CP, _cs(False, AccState.ACTIVE))
def test_gen2_bolt_acc_pedal_cancel_uses_enabled_only():
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL)
assert not get_stock_cc_active_for_cancel(CP, _cs(False, AccState.ACTIVE))
def test_bolt_acc_pedal_friction_experiment_is_single_fingerprint_only():
assert supports_bolt_acc_pedal_friction_experiment(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
openpilotLongitudinalControl=True,
enableGasInterceptorDEPRECATED=True,
flags=GMFlags.PEDAL_LONG.value,
))
assert not supports_bolt_acc_pedal_friction_experiment(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_MALIBU_HYBRID_CC,
openpilotLongitudinalControl=True,
enableGasInterceptorDEPRECATED=True,
flags=GMFlags.PEDAL_LONG.value,
))
assert not supports_bolt_acc_pedal_friction_experiment(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
openpilotLongitudinalControl=False,
enableGasInterceptorDEPRECATED=True,
flags=GMFlags.PEDAL_LONG.value,
))
def test_bolt_acc_pedal_friction_blend_preserves_zero_before_crossover():
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
assert get_bolt_acc_pedal_friction_brake(0, -2.8, 20.0, params) == 0
def test_bolt_acc_pedal_friction_blend_uses_full_brake_range_after_regen():
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
# Legacy mapping tops out early once regen has already consumed part of the
# decel request. The experiment remaps that reduced span back to full scale.
assert get_bolt_acc_pedal_friction_brake(286, -2.86, 20.0, params) == 400
def test_bolt_acc_pedal_friction_blend_biases_small_commands_upward_at_speed():
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
low_speed = get_bolt_acc_pedal_friction_brake(31, -2.86, 0.0, params)
high_speed = get_bolt_acc_pedal_friction_brake(31, -2.86, 20.0, params)
assert low_speed > 31
assert high_speed > low_speed
def test_bolt_acc_pedal_friction_blend_applies_a_minimum_pre_stop_command_at_speed():
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
assert get_bolt_acc_pedal_friction_brake(2, -2.86, 17.0, params) >= 18
def test_bolt_acc_pedal_friction_blend_boosts_midrange_commands_before_stopping_phase():
params = SimpleNamespace(ACCEL_MIN=-4.0, MAX_BRAKE=400)
assert get_bolt_acc_pedal_friction_brake(40, -2.86, 15.0, params) >= 80
def test_bolt_acc_pedal_low_speed_friction_ignores_tiny_inactive_brake_requests():
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(9, 5.0, False, False)
assert apply_brake == 0
assert not active
def test_bolt_acc_pedal_low_speed_friction_uses_hysteresis_once_active():
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(24, 3.0, False, False)
assert apply_brake == 24
assert active
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(5, 3.0, False, active)
assert apply_brake == 0
assert not active
def test_bolt_acc_pedal_low_speed_friction_fades_out_at_standstill():
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(80, 0.2, True, True)
assert apply_brake == 0
assert not active
def test_bolt_acc_pedal_low_speed_friction_preserves_rolling_stop_authority():
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(80, 1.2, True, True)
assert 0 < apply_brake < 80
assert active
def test_bolt_acc_pedal_low_speed_friction_drops_out_before_two_clamp():
apply_brake, active = shape_bolt_acc_pedal_low_speed_friction(80, 0.9, True, True)
assert apply_brake == 0
assert not active
def test_bolt_pedal_long_accel_limit_matches_planner_regen_envelope():
assert get_bolt_pedal_long_accel_limit(6.66) == pytest.approx(-2.379, abs=1e-3)
assert get_bolt_pedal_long_accel_limit(3.0) == pytest.approx(-1.70, abs=1e-3)
def test_bolt_acc_pedal_planner_brake_switch_is_lower_than_stock_switch():
params = SimpleNamespace(ZERO_GAS=6150, BRAKE_SWITCH_LOOKUP_BP=[0.5, 10.0], BRAKE_SWITCH_LOOKUP_V=[6150, 5500])
v_ego = 6.66
stock_switch = int(round(np.interp(v_ego, params.BRAKE_SWITCH_LOOKUP_BP, params.BRAKE_SWITCH_LOOKUP_V)))
planner_switch = get_bolt_acc_pedal_planner_brake_switch(
v_ego, params, tire_radius=0.336, mass=1832.0, coeff_drag=0.30, frontal_area=2.35, air_density=1.225,
)
assert planner_switch < stock_switch
def test_bolt_acc_pedal_effective_brake_switch_never_suppresses_stock_friction():
params = SimpleNamespace(ZERO_GAS=6150, BRAKE_SWITCH_LOOKUP_BP=[0.5, 10.0], BRAKE_SWITCH_LOOKUP_V=[6150, 5500])
v_ego = 5.434
mass = 1805.0
tire_radius = 0.075 * 2.63779 + 0.1453
frontal_area = 1.05 * 2.63779 + 0.0679
coeff_drag = 0.30
air_density = 1.225
accel_cmd = -1.399
aero_drag_force = 0.5 * coeff_drag * frontal_area * air_density * v_ego ** 2
torque = tire_radius * ((mass * accel_cmd) + aero_drag_force)
scaled_torque = torque + params.ZERO_GAS
stock_switch = int(round(np.interp(v_ego, params.BRAKE_SWITCH_LOOKUP_BP, params.BRAKE_SWITCH_LOOKUP_V)))
planner_switch = get_bolt_acc_pedal_planner_brake_switch(
v_ego, params, tire_radius=tire_radius, mass=mass,
coeff_drag=coeff_drag, frontal_area=frontal_area, air_density=air_density,
)
effective_switch = get_bolt_acc_pedal_effective_brake_switch(stock_switch, planner_switch)
stock_brake_accel = min((scaled_torque - stock_switch) / (tire_radius * mass), 0)
effective_brake_accel = min((scaled_torque - effective_switch) / (tire_radius * mass), 0)
assert planner_switch < stock_switch
assert effective_switch == stock_switch
assert stock_brake_accel < 0
assert effective_brake_accel == stock_brake_accel
def test_bolt_acc_pedal_friction_command_state_requires_cruise_main_for_positive_brake():
command_brake, release_frames, should_send = get_bolt_acc_pedal_friction_command_state(120, False, 0)
assert command_brake == 0
assert release_frames == 0
assert not should_send
def test_bolt_acc_pedal_friction_command_state_sends_zero_unwind_after_main_off():
command_brake, release_frames, should_send = get_bolt_acc_pedal_friction_command_state(120, True, 0)
assert command_brake == 120
assert release_frames > 0
assert should_send
command_brake, release_frames, should_send = get_bolt_acc_pedal_friction_command_state(0, False, release_frames)
assert command_brake == 0
assert release_frames >= 0
assert should_send
def test_fixed_stopping_brake_is_disabled_for_bolt_acc_pedal_experiment():
CP = SimpleNamespace(
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
openpilotLongitudinalControl=True,
enableGasInterceptorDEPRECATED=True,
flags=GMFlags.PEDAL_LONG.value,
)
assert not should_use_fixed_stopping_brake(CP, True, True, False)
def test_fixed_stopping_brake_stays_enabled_for_normal_acc_path():
CP = SimpleNamespace(
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023,
openpilotLongitudinalControl=True,
enableGasInterceptorDEPRECATED=False,
flags=0,
)
assert should_use_fixed_stopping_brake(CP, True, True, False)
assert not should_use_fixed_stopping_brake(CP, False, True, False)
assert not should_use_fixed_stopping_brake(CP, True, False, False)
assert not should_use_fixed_stopping_brake(CP, True, True, True)
def test_stock_cancel_is_suppressed_when_acc_is_faulted():
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_CAMERA)
cs = _cs(True, AccState.FAULTED)
cs.out.accFaulted = True
assert get_stock_cc_active_for_cancel(CP, cs)
assert not should_send_stock_long_cancel(11, cs)
def test_stock_cancel_requires_delay_and_no_acc_fault():
cs = _cs(True, AccState.ACTIVE)
assert not should_send_stock_long_cancel(10, cs)
assert should_send_stock_long_cancel(11, cs)
def test_gen1_bolt_pedal_ecm_cruise_spoof_is_not_gated_by_dash_speed_toggle():
CP = SimpleNamespace(
carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021,
enableGasInterceptorDEPRECATED=True,
flags=GMFlags.PEDAL_LONG.value,
openpilotLongitudinalControl=True,
)
assert not should_spoof_dash_speed(CP, SimpleNamespace(disable_openpilot_long=True, gm_pedal_longitudinal=True))
assert should_spoof_ecm_cruise_status(CP)
def test_gateway_keepalive_uses_gateway_cadence():
cp = SimpleNamespace(networkLocation=CarParams.NetworkLocation.gateway, flags=0)
assert get_adas_keepalive_step(cp, is_kaofui_car=True) == 100
assert get_adas_keepalive_step(cp, is_kaofui_car=False) == 200
def test_removed_camera_keepalive_uses_camera_cadence():
cp = SimpleNamespace(networkLocation=CarParams.NetworkLocation.fwdCamera, flags=GMFlags.NO_CAMERA.value)
assert get_adas_keepalive_step(cp, is_kaofui_car=True) == 100
def test_live_camera_path_does_not_send_pt_keepalive():
cp = SimpleNamespace(networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0)
assert get_adas_keepalive_step(cp, is_kaofui_car=True) is None
def test_acc_2cd_replacement_only_used_with_live_camera_path():
assert should_send_acc_2cd(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0))
assert not should_send_acc_2cd(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=GMFlags.NO_CAMERA.value))
assert not should_send_acc_2cd(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_TRAILBLAZER, networkLocation=CarParams.NetworkLocation.gateway, flags=0))
assert not should_send_acc_2cd(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_TRAILBLAZER_CC, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0))
assert not should_send_acc_2cd(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_BLAZER, networkLocation=CarParams.NetworkLocation.fwdCamera, flags=0))
def test_ascm_int_cars_do_not_send_radar_status():
common = {
"networkLocation": CarParams.NetworkLocation.fwdCamera,
"radarUnavailable": False,
}
assert not should_send_adas_status(SimpleNamespace(carFingerprint=CAR.BUICK_LACROSSE_ASCM, **common), is_kaofui_car=True)
assert not should_send_adas_status(SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM, **common), is_kaofui_car=True)
def test_lacrosse_ascm_marks_acc_dashboard_active_for_aol_only():
cc = SimpleNamespace(enabled=False, latActive=True)
assert get_acc_dashboard_status_active(SimpleNamespace(carFingerprint=CAR.BUICK_LACROSSE_ASCM), cc)
assert not get_acc_dashboard_status_active(SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM), cc)
assert not get_acc_dashboard_status_active(SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023), cc)
def test_acc_dashboard_status_active_for_normal_enabled_cars():
cc = SimpleNamespace(enabled=True, latActive=False)
assert get_acc_dashboard_status_active(SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM), cc)
def test_volt_auto_hold_requires_toggle_supported_non_cc_only_volt_and_stock_safety():
stock_safety = [SimpleNamespace(safetyParam=0x8000)]
no_safety = [SimpleNamespace(safetyParam=0)]
assert not supports_volt_auto_hold(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
openpilotLongitudinalControl=True,
networkLocation=CarParams.NetworkLocation.fwdCamera,
safetyConfigs=no_safety,
),
True,
)
assert not supports_volt_auto_hold(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CC,
openpilotLongitudinalControl=True,
networkLocation=CarParams.NetworkLocation.fwdCamera,
safetyConfigs=no_safety,
),
True,
)
assert supports_volt_auto_hold(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
openpilotLongitudinalControl=True,
networkLocation=CarParams.NetworkLocation.fwdCamera,
safetyConfigs=stock_safety,
),
True,
)
assert not supports_volt_auto_hold(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT,
openpilotLongitudinalControl=False,
networkLocation=CarParams.NetworkLocation.gateway,
safetyConfigs=stock_safety,
),
True,
)
assert not supports_volt_auto_hold(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_2019,
openpilotLongitudinalControl=False,
networkLocation=CarParams.NetworkLocation.fwdCamera,
safetyConfigs=stock_safety,
),
True,
)
assert not supports_volt_auto_hold(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_2019,
openpilotLongitudinalControl=False,
networkLocation=CarParams.NetworkLocation.fwdCamera,
safetyConfigs=no_safety,
),
True,
)
assert not supports_volt_auto_hold(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
openpilotLongitudinalControl=True,
networkLocation=CarParams.NetworkLocation.fwdCamera,
safetyConfigs=no_safety,
),
False,
)
def test_auto_hold_brake_estimate_uses_driver_or_op_brake_and_clamps():
assert estimate_auto_hold_brake(0.0, 20.0) == 80
assert estimate_auto_hold_brake(20.0, 40.0) == 110
assert estimate_auto_hold_brake(20.0, 160.0) == 160
assert estimate_auto_hold_brake(100.0, 400.0) == 240
assert estimate_auto_hold_brake(7.0, 0.0, SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_2019)) == 100
def test_volt_one_pedal_requires_toggle_supported_volt_stock_safety_and_ev_transmission():
stock_safety = [SimpleNamespace(safetyParam=0x8000)]
no_safety = [SimpleNamespace(safetyParam=0)]
assert supports_volt_one_pedal(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
openpilotLongitudinalControl=True,
safetyConfigs=stock_safety,
transmissionType=structs.CarParams.TransmissionType.direct,
),
True,
)
assert not supports_volt_one_pedal(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
openpilotLongitudinalControl=True,
safetyConfigs=no_safety,
transmissionType=structs.CarParams.TransmissionType.direct,
),
True,
)
assert not supports_volt_one_pedal(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CC,
openpilotLongitudinalControl=True,
safetyConfigs=stock_safety,
transmissionType=structs.CarParams.TransmissionType.direct,
),
True,
)
assert not supports_volt_one_pedal(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
openpilotLongitudinalControl=True,
safetyConfigs=stock_safety,
transmissionType=structs.CarParams.TransmissionType.automatic,
),
True,
)
assert not supports_volt_one_pedal(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
openpilotLongitudinalControl=False,
safetyConfigs=stock_safety,
transmissionType=structs.CarParams.TransmissionType.direct,
),
True,
)
assert not supports_volt_one_pedal(
SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_CAMERA,
openpilotLongitudinalControl=True,
safetyConfigs=stock_safety,
transmissionType=structs.CarParams.TransmissionType.direct,
),
False,
)
def test_auto_hold_drive_gears_accept_capnp_dynamic_enum_membership():
msg = structs.CarState.new_message()
msg.gearShifter = structs.CarState.GearShifter.drive
assert msg.gearShifter in AUTO_HOLD_DRIVE_GEARS
def test_auto_hold_activation_allows_direct_entry_from_stopped_brake_press():
assert should_activate_auto_hold(
True,
False,
False,
True,
False,
True,
False,
False,
0.01,
)
def test_auto_hold_activation_stays_latched_after_brake_release():
assert should_activate_auto_hold(
True,
False,
True,
False,
False,
True,
False,
False,
0.0,
)
def test_volt_2019_auto_hold_engaged_uses_near_stop_creep_hysteresis():
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_2019)
assert get_auto_hold_stop_threshold(CP, True) == CarControllerParams.NEAR_STOP_BRAKE_PHASE
assert should_activate_auto_hold(
True,
True,
True,
False,
False,
False,
False,
False,
0.05,
get_auto_hold_stop_threshold(CP, True),
)
assert not should_activate_auto_hold(
True,
True,
True,
False,
False,
False,
False,
False,
0.05,
)
def test_auto_hold_activation_blocks_when_long_is_active_or_motion_is_above_threshold():
assert not should_activate_auto_hold(
True,
True,
False,
True,
False,
True,
True,
False,
0.0,
)
assert not should_activate_auto_hold(
True,
True,
False,
False,
False,
False,
False,
False,
0.03,
)
def test_auto_hold_activation_allows_standstill_even_if_speed_filter_is_slightly_above_threshold():
assert should_activate_auto_hold(
True,
True,
False,
False,
False,
True,
False,
False,
0.05,
)
def test_auto_hold_activation_releases_immediately_on_gas_press():
assert not should_activate_auto_hold(
True,
True,
True,
False,
True,
True,
False,
False,
0.0,
)
def test_volt_one_pedal_activation_requires_main_l_mode_and_no_driver_input():
assert should_activate_volt_one_pedal(
True,
True,
False,
False,
False,
False,
True,
structs.CarState.GearShifter.low,
3.0,
)
assert not should_activate_volt_one_pedal(
True,
False,
False,
False,
False,
False,
True,
structs.CarState.GearShifter.low,
3.0,
)
assert not should_activate_volt_one_pedal(
True,
True,
True,
False,
False,
False,
True,
structs.CarState.GearShifter.low,
3.0,
)
assert not should_activate_volt_one_pedal(
True,
True,
False,
True,
False,
False,
True,
structs.CarState.GearShifter.low,
3.0,
)
assert not should_activate_volt_one_pedal(
True,
True,
False,
False,
False,
True,
True,
structs.CarState.GearShifter.low,
3.0,
)
assert not should_activate_volt_one_pedal(
True,
True,
False,
False,
False,
False,
False,
structs.CarState.GearShifter.drive,
3.0,
)
def test_volt_one_pedal_target_decel_stays_active_above_low_speed_band():
assert get_volt_one_pedal_target_decel(0.5 * CV.MPH_TO_MS) == -1.0
assert get_volt_one_pedal_target_decel(6.0 * CV.MPH_TO_MS) == -1.1
assert get_volt_one_pedal_target_decel(20.0 * CV.MPH_TO_MS) == -1.1
def test_volt_one_pedal_regression_ignores_noisy_wheel_direction_bits():
assert should_activate_volt_one_pedal(
True,
True,
False,
False,
False,
False,
True,
structs.CarState.GearShifter.low,
3.0,
)
def test_volt_one_pedal_requires_time_in_drive_before_arming():
assert not should_activate_volt_one_pedal(
True,
True,
False,
False,
False,
False,
True,
structs.CarState.GearShifter.low,
2.5,
)
def test_friction_brake_mode_keeps_near_stop_disabled_for_regular_long_braking():
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM)
assert get_friction_brake_mode(120, False, True, False, CP) == 0xa
def test_friction_brake_mode_uses_near_stop_hold_mode_for_volt_auto_hold():
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM)
assert get_friction_brake_mode(120, False, True, False, CP, allow_near_stop_mode=True) == 0xb
assert get_friction_brake_mode(120, False, True, True, CP, allow_near_stop_mode=True) == 0xd
def test_friction_brake_mode_uses_stock_bolt_unwind_for_pedal_print_when_enabled():
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL)
assert get_friction_brake_mode(0, False, True, False, CP) == 0x1
assert get_friction_brake_mode(0, True, True, False, CP) == 0x9
def test_friction_brake_mode_keeps_bolt_pedal_braking_mode_unchanged():
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL)
assert get_friction_brake_mode(120, True, False, False, CP) == 0xa
assert get_friction_brake_mode(120, True, True, True, CP) == 0xd
def test_calc_pedal_command_small_accel_deadband_keeps_creep_target_stable():
pos_controller = _controller()
neg_controller = _controller()
pos_pedal, pos_regen = pos_controller.calc_pedal_command(0.02, True, 0.3)
neg_pedal, neg_regen = neg_controller.calc_pedal_command(-0.02, True, 0.3)
assert not pos_regen
assert not neg_regen
assert pos_pedal == neg_pedal
def test_calc_pedal_command_creep_switch_does_not_snap_to_target():
controller = _controller()
controller.pedal_active_last = True
controller.pedal_steady = 0.18
controller.regen_press_counter = 20
pedal_gas, press_regen = controller.calc_pedal_command(-1.0, True, 0.5)
assert press_regen
assert pedal_gas > 0.15
def test_calc_pedal_command_softens_small_positive_follow_ramp_at_road_speed():
controller = _controller()
controller.pedal_active_last = True
controller.pedal_steady = 0.18
pedal_gas, press_regen = controller.calc_pedal_command(0.2, True, 18.0)
assert not press_regen
assert pedal_gas - 0.18 < 0.026
def test_calc_pedal_command_keeps_strong_positive_requests_responsive():
controller = _controller()
controller.pedal_active_last = True
controller.pedal_steady = 0.18
pedal_gas, press_regen = controller.calc_pedal_command(1.4, True, 18.0)
assert not press_regen
assert pedal_gas - 0.18 > 0.04
def test_shape_truck_positive_accel_softens_small_highway_requests():
shaped = shape_truck_positive_accel(0.12, 26.0, True)
assert 0.08 < shaped < 0.095
def test_shape_truck_positive_accel_keeps_mid_follow_requests_available():
shaped = shape_truck_positive_accel(0.45, 13.5, True)
assert 0.43 < shaped < 0.45
def test_shape_truck_positive_accel_leaves_large_requests_alone():
assert shape_truck_positive_accel(1.0, 26.0, True) == 1.0
def test_shape_truck_positive_accel_is_inactive_when_disabled_or_low_speed():
assert shape_truck_positive_accel(0.12, 26.0, False) == 0.12
assert shape_truck_positive_accel(0.12, 6.0, True) == 0.12
def test_shape_truck_positive_accel_preserves_more_follow_authority_with_lead():
base = shape_truck_positive_accel(0.28, 26.0, True)
relieved = shape_truck_positive_accel(0.28, 26.0, True, lead_visible=True, set_speed_error=6.0)
assert relieved > base
assert relieved < 0.28
def test_shape_truck_positive_accel_does_not_relax_without_speed_error():
base = shape_truck_positive_accel(0.28, 26.0, True)
no_error = shape_truck_positive_accel(0.28, 26.0, True, lead_visible=True, set_speed_error=0.0)
assert no_error == base
def test_shape_truck_pitch_accel_attenuates_highway_grade_feedforward():
assert shape_truck_pitch_accel(-0.30, 30.0, True) == pytest.approx(-0.0825)
assert shape_truck_pitch_accel(0.30, 30.0, True) == pytest.approx(0.0825)
def test_shape_truck_pitch_accel_is_inactive_without_truck_tuning():
assert shape_truck_pitch_accel(-0.30, 30.0, False) == pytest.approx(-0.30)
def test_shape_truck_friction_brake_suppresses_boundary_chatter():
assert shape_truck_friction_brake(14, -0.3, False, False) == (0, False)
def test_shape_truck_friction_brake_uses_hysteresis_once_engaged():
assert shape_truck_friction_brake(39, -0.3, False, False) == (0, False)
assert shape_truck_friction_brake(40, -0.3, False, False) == (40, True)
assert shape_truck_friction_brake(14, -0.3, False, True) == (14, True)
assert shape_truck_friction_brake(8, -0.3, False, True) == (0, False)
def test_shape_truck_friction_brake_never_delays_meaningful_braking():
assert shape_truck_friction_brake(5, -0.85, False, False) == (5, True)
assert shape_truck_friction_brake(5, -0.2, True, False) == (5, True)
def test_use_interceptor_sng_launch_requires_actual_near_stop():
CP = SimpleNamespace(vEgoStarting=0.25)
assert use_interceptor_sng_launch(CP, _sng_cs(0.0, True, True))
assert use_interceptor_sng_launch(CP, _sng_cs(0.2, False, True))
assert not use_interceptor_sng_launch(CP, _sng_cs(1.2, False, True))
assert not use_interceptor_sng_launch(CP, _sng_cs(0.0, True, False))
def test_bolt_acc_pedal_sng_launch_uses_physical_standstill_without_stock_acc_bit():
CP = SimpleNamespace(
vEgoStarting=0.25,
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
enableGasInterceptorDEPRECATED=True,
)
assert use_interceptor_sng_launch(CP, _sng_cs(0.0, True, False))
assert use_interceptor_sng_launch(CP, _sng_cs(0.2, False, False))
assert not use_interceptor_sng_launch(CP, _sng_cs(1.2, False, False))
def test_bolt_acc_pedal_sng_launch_preserves_stronger_computed_pedal():
CP = SimpleNamespace(
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
openpilotLongitudinalControl=True,
enableGasInterceptorDEPRECATED=True,
flags=GMFlags.PEDAL_LONG.value,
)
params = SimpleNamespace(SNG_INTERCEPTOR_GAS=18. / 255.)
assert get_interceptor_sng_gas_cmd(CP, 0.2, 0.54, params, False) == pytest.approx(0.2)
def test_other_pedal_sng_launch_keeps_fixed_floor_behavior():
CP = SimpleNamespace(
carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021,
openpilotLongitudinalControl=True,
enableGasInterceptorDEPRECATED=True,
flags=GMFlags.PEDAL_LONG.value,
)
params = SimpleNamespace(SNG_INTERCEPTOR_GAS=18. / 255.)
assert get_interceptor_sng_gas_cmd(CP, 0.2, 0.54, params, False) == pytest.approx(18. / 255.)
def test_use_interceptor_sng_launch_extends_for_maneuver_mode():
CP = SimpleNamespace(vEgoStarting=0.25)
assert use_interceptor_sng_launch(CP, _sng_cs(1.2, False, True), maneuver_mode=True)
assert not use_interceptor_sng_launch(CP, _sng_cs(2.2, False, True), maneuver_mode=True)
def test_testing_ground_1_brake_switch_bias_is_softened_but_still_speed_scaled():
assert get_testing_ground_1_brake_switch_bias(0.0) == 40
assert get_testing_ground_1_brake_switch_bias(6.0) == 85
assert get_testing_ground_1_brake_switch_bias(15.0) == 130
assert get_testing_ground_1_brake_switch_bias(30.0) == 170
def test_lka_counter_uses_returned_loopback_counter():
cs = SimpleNamespace(
loopback_lka_steering_cmd_updated=True,
loopback_lka_steering_cmd_counter=2,
loopback_lka_steering_cmd_ts_nanos=1,
pt_lka_steering_cmd_counter=0,
)
assert get_lka_steering_cmd_counter(0, cs) == 3
def test_lka_counter_keeps_advancing_without_loopback_updates():
cs = SimpleNamespace(
loopback_lka_steering_cmd_updated=False,
loopback_lka_steering_cmd_counter=0,
loopback_lka_steering_cmd_ts_nanos=1,
pt_lka_steering_cmd_counter=0,
)
next_counter = 1
sent = []
for _ in range(6):
idx = get_lka_steering_cmd_counter(next_counter, cs)
sent.append(idx)
next_counter = (idx + 1) % 4
assert sent == [1, 2, 3, 0, 1, 2]
def test_lka_counter_only_seeds_from_pt_counter_once_without_loopback():
cs = SimpleNamespace(
loopback_lka_steering_cmd_updated=False,
loopback_lka_steering_cmd_counter=0,
loopback_lka_steering_cmd_ts_nanos=0,
pt_lka_steering_cmd_counter=0,
)
next_counter = -1
sent = []
for _ in range(6):
idx = get_lka_steering_cmd_counter(next_counter, cs)
sent.append(idx)
next_counter = (idx + 1) % 4
assert sent == [1, 2, 3, 0, 1, 2]
+610 -12
View File
@@ -1,16 +1,29 @@
import pytest
import numpy as np
from types import SimpleNamespace
from parameterized import parameterized
from opendbc.can import CANPacker
from opendbc.car import Bus, DT_CTRL
from cereal import custom
from opendbc.can import CANPacker, CANParser
from opendbc.car import Bus, DT_CTRL, structs
from opendbc.car.car_helpers import interfaces
from opendbc.car.gm import gmcan
from opendbc.car.gm.carcontroller import should_send_acc_dashboard_status, should_send_cc_button_spam, should_spoof_dash_speed
from opendbc.car.gm.carstate import CarState as GMCarState, get_hard_cruise_buttons, update_auto_hold_drive_timers
from opendbc.car.gm.carcontroller import (
VisualAlert,
get_acc_dashboard_always_one,
get_acc_dashboard_fcw_alert,
get_volt_one_pedal_lift_brake,
should_send_acc_dashboard_status,
should_send_cc_button_spam,
should_spoof_dash_speed,
)
import opendbc.car.gm.interface as gm_interface
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.gm.fingerprints import FINGERPRINTS
from opendbc.car.gm.values import CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, GMFlags, GMSafetyFlags
from opendbc.car.gm.values import ASCM_INT, CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, DBC, GM_RX_OFFSET, CarControllerParams, CruiseButtons, GMFlags, GMSafetyFlags
from opendbc.safety import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
CAMERA_DIAGNOSTIC_ADDRESS = 0x24b
VOLT_CARS = (
@@ -32,6 +45,7 @@ def _test_starpilot_toggles():
cluster_offset=1.0,
disable_openpilot_long=False,
force_fingerprint=False,
remap_cancel_to_distance=False,
vEgoStopping=0.5,
volt_sng=False,
)
@@ -52,6 +66,84 @@ class TestGMFingerprint:
class TestGMInterface:
@parameterized.expand([
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
CAR.CHEVROLET_BOLT_CC_2022_2023,
CAR.CHEVROLET_MALIBU_HYBRID_CC,
])
def test_bolt_pedal_long_uses_shared_planning_delay_without_retuning_pid(self, car_model):
CarInterface = interfaces[car_model]
fingerprint = _empty_fingerprint()
fingerprint[0][0x201] = 8
params = Params()
try:
params.put_bool("GMPedalLongitudinal", True)
car_params = CarInterface.get_params(
car_model,
fingerprint,
[],
alpha_long=False,
is_release=False,
docs=False,
starpilot_toggles=_test_starpilot_toggles(),
)
finally:
params.remove("GMPedalLongitudinal")
assert car_params.longitudinalActuatorDelay == pytest.approx(0.6)
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.095, 0.085, 0.065, 0.050])
assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.07, 0.10, 0.15, 0.24])
assert car_params.longitudinalTuning.kfDEPRECATED == pytest.approx(0.20)
def test_bolt_acc_pedal_pid_accel_limits_keep_full_negative_authority(self):
cp = SimpleNamespace(
enableGasInterceptorDEPRECATED=True,
flags=GMFlags.PEDAL_LONG.value,
carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL,
)
accel_min, accel_max = gm_interface.CarInterface.get_pid_accel_limits(cp, 4.73, 0.0)
assert accel_min == pytest.approx(CarControllerParams.ACCEL_MIN)
assert accel_max == pytest.approx(np.interp(4.73, [0.0, 1.5, 4.0, 8.0, 15.0],
[0.54, 0.74, 1.03, 1.46, CarControllerParams.ACCEL_MAX]))
def test_bolt_cc_pedal_pid_accel_limits_remain_regen_limited(self):
cp = SimpleNamespace(
enableGasInterceptorDEPRECATED=True,
flags=GMFlags.PEDAL_LONG.value,
carFingerprint=CAR.CHEVROLET_BOLT_CC_2022_2023,
)
accel_min, _ = gm_interface.CarInterface.get_pid_accel_limits(cp, 4.73, 0.0)
assert accel_min == pytest.approx(np.interp(4.73, [0.0, 1.5, 4.0, 8.0, 15.0, 30.0],
[-0.93, -1.28, -1.98, -2.58, -2.86, -2.95]))
def test_missing_hard_cruise_signal_defaults_to_init(self):
assert get_hard_cruise_buttons({"ACCButtons": CruiseButtons.RES_ACCEL}) == CruiseButtons.INIT
assert get_hard_cruise_buttons({"ACCButtonsHard": CruiseButtons.DECEL_SET}) == CruiseButtons.DECEL_SET
def test_volt_auto_hold_drive_timer_requires_motion_before_startup_arming(self):
auto_hold_time, one_pedal_time = update_auto_hold_drive_timers(True, False, 0.0, 0.0)
assert auto_hold_time == 0.0
assert one_pedal_time == 0.0
def test_volt_auto_hold_drive_timer_accumulates_only_while_moving(self):
auto_hold_time, one_pedal_time = update_auto_hold_drive_timers(True, True, 0.0, 0.0)
assert auto_hold_time == pytest.approx(DT_CTRL)
assert one_pedal_time == pytest.approx(DT_CTRL)
auto_hold_time, one_pedal_time = update_auto_hold_drive_timers(True, False, auto_hold_time, one_pedal_time)
assert auto_hold_time == pytest.approx(DT_CTRL)
assert one_pedal_time == pytest.approx(DT_CTRL)
@parameterized.expand(VOLT_CARS)
def test_volt_min_steer_speed_is_7_mph(self, car_model):
CarInterface = interfaces[car_model]
@@ -64,22 +156,37 @@ class TestGMInterface:
("interceptor", True),
("ascm_int", False),
])
def test_volt_testing_ground_tune_sets_nonzero_p_and_starting_state(self, _name, pedal_present, monkeypatch):
def test_volt_testing_ground_tune_sets_nonzero_p_and_starting_state(self, _name, pedal_present):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
fingerprint = _empty_fingerprint()
if pedal_present:
fingerprint[0][0x201] = 8 # pedal detected
fingerprint[0][0x2FF] = 8 # SASCM detected
monkeypatch.setattr(gm_interface.testing_ground, "use_2", True, raising=False)
old_testing_ground = gm_interface.testing_ground
gm_interface.testing_ground = SimpleNamespace(use_2=True)
params = Params()
params.put_bool("GMPedalLongitudinal", True)
car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=False, is_release=False, docs=False,
starpilot_toggles=_test_starpilot_toggles())
try:
car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=False, is_release=False, docs=False,
starpilot_toggles=_test_starpilot_toggles())
finally:
gm_interface.testing_ground = old_testing_ground
params.remove("GMPedalLongitudinal")
assert list(car_params.longitudinalTuning.kpV) == [0.10, 0.072, 0.05, 0.04]
assert list(car_params.longitudinalTuning.kiV) == [0.025, 0.03, 0.04, 0.055]
assert car_params.startingState
assert car_params.startAccel == pytest.approx(1.15)
if pedal_present:
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.10, 0.072, 0.05, 0.04])
assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.025, 0.03, 0.04, 0.055])
assert car_params.startingState
assert car_params.startAccel == pytest.approx(1.15)
else:
assert not car_params.openpilotLongitudinalControl
assert not car_params.enableGasInterceptorDEPRECATED
assert list(car_params.longitudinalTuning.kpV) == [0.0]
assert list(car_params.longitudinalTuning.kiV) == [0.5, 0.5]
assert not car_params.startingState
assert car_params.startAccel == pytest.approx(0.0)
def test_volt_cc_sparse_fingerprint_without_camera_sets_no_camera(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_CC]
@@ -94,6 +201,57 @@ class TestGMInterface:
assert car_params.flags & GMFlags.NO_CAMERA.value
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value
def test_volt_ascm_sparse_fingerprint_without_camera_does_not_set_no_camera(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
fingerprint = {
0: FINGERPRINTS[CAR.CHEVROLET_VOLT][0].copy(),
1: {},
}
fingerprint[0][0x2FF] = 8 # SASCM detected
car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=False, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
assert not (car_params.flags & GMFlags.NO_CAMERA.value)
assert not (car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value)
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_ASCM_INT.value
def test_silverado_alpha_long_uses_trimmed_longitudinal_tune(self):
CarInterface = interfaces[CAR.CHEVROLET_SILVERADO]
fingerprint = _empty_fingerprint()
fingerprint[0] = FINGERPRINTS[CAR.CHEVROLET_SILVERADO][0].copy()
car_params = CarInterface.get_params(CAR.CHEVROLET_SILVERADO, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
assert car_params.openpilotLongitudinalControl
assert not car_params.enableGasInterceptorDEPRECATED
assert list(car_params.longitudinalTuning.kpBP) == pytest.approx([0.0, 5.0, 15.0, 35.0])
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.02, 0.03, 0.028, 0.022])
assert list(car_params.longitudinalTuning.kiBP) == pytest.approx([0.0, 5.0, 15.0, 35.0])
assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.20, 0.18, 0.13, 0.08])
def test_blazer_uses_softer_low_speed_stop_hold_tune(self):
CarInterface = interfaces[CAR.CHEVROLET_BLAZER]
fingerprint = _empty_fingerprint()
fingerprint[0] = FINGERPRINTS[CAR.CHEVROLET_BLAZER][0].copy()
fingerprint[0][0x2FF] = 8 # SASCM present so alpha-long can enable on this platform
car_params = CarInterface.get_params(CAR.CHEVROLET_BLAZER, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
assert car_params.openpilotLongitudinalControl
assert list(car_params.longitudinalTuning.kpBP) == pytest.approx([0.0, 4.0, 12.0, 35.0])
assert list(car_params.longitudinalTuning.kpV) == pytest.approx([0.09, 0.075, 0.055, 0.04])
assert list(car_params.longitudinalTuning.kiBP) == pytest.approx([0.0, 4.0, 12.0, 35.0])
assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.03, 0.04, 0.055, 0.07])
assert car_params.longitudinalActuatorDelay == pytest.approx(0.7)
assert car_params.minEnableSpeed == pytest.approx(5 * CV.KPH_TO_MS)
assert car_params.stoppingDecelRate == pytest.approx(1.0)
assert car_params.vEgoStopping == pytest.approx(0.35)
assert car_params.vEgoStarting == pytest.approx(0.35)
assert car_params.stopAccel == pytest.approx(-0.30)
def test_volt_gateway_without_accel_pos_uses_brake_pedal_message(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT]
fingerprint = _empty_fingerprint()
@@ -103,11 +261,223 @@ class TestGMInterface:
starpilot_toggles=_test_starpilot_toggles())
assert car_params.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_CAMERA.value
pt_parser = CarInterface.CarState.get_can_parsers(car_params)[Bus.pt]
assert "ECMAcceleratorPos" not in pt_parser.vl
assert "EBCMBrakePedalPosition" in pt_parser.vl
def test_volt_auto_hold_sets_stock_hold_safety_bit_with_op_long_enabled(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
fingerprint = _empty_fingerprint()
fingerprint[0][0x2FF] = 8
params = Params()
try:
params.put_bool("GMAutoHold", True)
car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
finally:
params.remove("GMAutoHold")
assert car_params.openpilotLongitudinalControl
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value
def test_volt_auto_hold_does_not_set_stock_hold_safety_bit_with_op_long_disabled(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
fingerprint = _empty_fingerprint()
fingerprint[0][0x2FF] = 8
params = Params()
try:
params.put_bool("GMAutoHold", True)
car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=False, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
finally:
params.remove("GMAutoHold")
assert not car_params.openpilotLongitudinalControl
assert not (car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value)
def test_volt_one_pedal_sets_stock_hold_safety_bit_without_auto_hold(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
fingerprint = _empty_fingerprint()
fingerprint[0][0x2FF] = 8
params = Params()
try:
params.put_bool("GMAutoHold", False)
params.put_bool("VoltOnePedalMode", True)
car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
finally:
params.remove("GMAutoHold")
params.remove("VoltOnePedalMode")
assert car_params.openpilotLongitudinalControl
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_3D1_SCHED.value
def test_volt_one_pedal_does_not_set_stock_hold_safety_bits_with_op_long_disabled(self):
CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM]
fingerprint = _empty_fingerprint()
fingerprint[0][0x2FF] = 8
params = Params()
try:
params.put_bool("GMAutoHold", False)
params.put_bool("VoltOnePedalMode", True)
car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=False, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
finally:
params.remove("GMAutoHold")
params.remove("VoltOnePedalMode")
assert not car_params.openpilotLongitudinalControl
assert not (car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value)
assert not (car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_3D1_SCHED.value)
@parameterized.expand(VOLT_CARS)
def test_volt_bsm_is_enabled_without_fingerprint_match(self, car_model):
CarInterface = interfaces[car_model]
car_params = CarInterface.get_params(car_model, _empty_fingerprint(), [], alpha_long=False, is_release=False, docs=False,
starpilot_toggles=_test_starpilot_toggles())
assert car_params.enableBsm
def test_volt_bsm_parser_is_optional(self):
cp = SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_ASCM,
networkLocation=structs.CarParams.NetworkLocation.fwdCamera,
flags=0,
transmissionType=structs.CarParams.TransmissionType.direct,
enableGasInterceptorDEPRECATED=False,
enableBsm=True,
)
pt_parser = GMCarState.get_can_parsers(cp)[Bus.pt]
bsm_addr = pt_parser.dbc.name_to_msg["BCMBlindSpotMonitor"].address
assert "BCMBlindSpotMonitor" in pt_parser.vl
assert pt_parser.message_states[bsm_addr].ignore_alive
def test_volt_ascm_cam_parser_includes_optional_aeb_cmd(self):
cam_parser = GMCarState.get_can_parsers(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_ASCM,
networkLocation=structs.CarParams.NetworkLocation.fwdCamera,
flags=0,
transmissionType=structs.CarParams.TransmissionType.direct,
enableGasInterceptorDEPRECATED=False,
enableBsm=False,
))[Bus.cam]
aeb_addr = cam_parser.dbc.name_to_msg["AEBCmd"].address
assert "AEBCmd" in cam_parser.vl
assert cam_parser.message_states[aeb_addr].ignore_alive
def test_bolt_gen2_pedal_cancel_remap_sets_alt_exp(self):
CarInterface = interfaces[CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL]
fingerprint = _empty_fingerprint()
fingerprint[0][0x201] = 8
params = Params()
toggles = _test_starpilot_toggles()
try:
params.put_bool("GMPedalLongitudinal", True)
params.put_bool("RemapCancelToDistance", True)
car_params = CarInterface.get_params(CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL, fingerprint, [], alpha_long=False,
is_release=False, docs=False, starpilot_toggles=toggles)
finally:
params.remove("GMPedalLongitudinal")
params.remove("RemapCancelToDistance")
assert car_params.alternativeExperience & ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_BOLT_2022_PEDAL.value
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value
assert car_params.startingState
assert car_params.startAccel == pytest.approx(0.55)
assert car_params.vEgoStarting == pytest.approx(0.35)
def test_cadillac_xt5_sdgm_sascm_gates_alpha_long(self):
CarInterface = interfaces[CAR.CADILLAC_XT5]
fingerprint = _empty_fingerprint()
fingerprint[0][0xBE] = 6
stock_params = CarInterface.get_params(CAR.CADILLAC_XT5, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
assert stock_params.networkLocation == structs.CarParams.NetworkLocation.fwdCamera
assert stock_params.pcmCruise
assert stock_params.alphaLongitudinalAvailable is False
assert stock_params.openpilotLongitudinalControl is False
assert stock_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_SDGM.value
fingerprint[0][0x2FF] = 8
sascm_params = CarInterface.get_params(CAR.CADILLAC_XT5, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
assert sascm_params.flags & GMFlags.SASCM.value
assert sascm_params.alphaLongitudinalAvailable
assert sascm_params.openpilotLongitudinalControl
assert not sascm_params.pcmCruise
assert sascm_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_CAM_LONG.value
def test_cadillac_escalade_esv_2019_ascm_uses_sascm_and_2019_tune(self):
base_fingerprint = FINGERPRINTS[CAR.CADILLAC_ESCALADE_ESV_2019][0]
ascm_fingerprint = FINGERPRINTS[CAR.CADILLAC_ESCALADE_ESV_2019_ASCM][0]
assert CAR.CADILLAC_ESCALADE_ESV_2019_ASCM in ASCM_INT
assert ascm_fingerprint[0x2FF] == 8
assert {addr: length for addr, length in ascm_fingerprint.items() if addr != 0x2FF} == base_fingerprint
CarInterface = interfaces[CAR.CADILLAC_ESCALADE_ESV_2019_ASCM]
fingerprint = _empty_fingerprint()
fingerprint[0] = ascm_fingerprint.copy()
car_params = CarInterface.get_params(CAR.CADILLAC_ESCALADE_ESV_2019_ASCM, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
assert car_params.flags & GMFlags.SASCM.value
assert car_params.networkLocation == structs.CarParams.NetworkLocation.fwdCamera
assert car_params.openpilotLongitudinalControl
assert not car_params.pcmCruise
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_ASCM_INT.value
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_CAM_LONG.value
assert car_params.lateralTuning.torque.latAccelFactor == pytest.approx(1.15)
assert car_params.lateralTuning.torque.friction == pytest.approx(0.2)
def test_cadillac_xt4_uses_nonlinear_torque_curve_with_center_boost(self):
CarInterface = interfaces[CAR.CADILLAC_XT4]
car_params = CarInterface.get_non_essential_params(CAR.CADILLAC_XT4)
ci = CarInterface(car_params, custom.StarPilotCarParams.new_message())
torque_from_lataccel = ci.torque_from_lateral_accel()
low_lataccel = 0.2
high_lataccel = 1.0
low_torque = torque_from_lataccel(low_lataccel, car_params.lateralTuning.torque)
high_torque = torque_from_lataccel(high_lataccel, car_params.lateralTuning.torque)
linear_low_torque = low_lataccel / car_params.lateralTuning.torque.latAccelFactor
linear_high_torque = high_lataccel / car_params.lateralTuning.torque.latAccelFactor
assert low_torque > linear_low_torque * 1.15
assert low_torque < linear_low_torque * 1.30
assert high_torque == pytest.approx(linear_high_torque, rel=0.03)
assert torque_from_lataccel(-low_lataccel, car_params.lateralTuning.torque) == pytest.approx(-low_torque, rel=1e-6)
@parameterized.expand((CAR.CHEVROLET_VOLT_ASCM, CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_VOLT_2019))
def test_volt_integration_variants_share_nonlinear_torque_curve(self, candidate):
assert gm_interface.get_nonlinear_torque_params(candidate) == gm_interface.NON_LINEAR_TORQUE_PARAMS[CAR.CHEVROLET_VOLT]
CarInterface = interfaces[candidate]
car_params = CarInterface.get_non_essential_params(candidate)
ci = CarInterface(car_params, custom.StarPilotCarParams.new_message())
torque_from_lataccel = ci.torque_from_lateral_accel()
left_torque = torque_from_lataccel(0.5, car_params.lateralTuning.torque)
right_torque = torque_from_lataccel(-0.5, car_params.lateralTuning.torque)
assert left_torque > abs(right_torque)
class TestGMCarController:
def test_dash_speed_spoof_respects_live_stock_acc_toggles(self):
@@ -122,6 +492,11 @@ class TestGMCarController:
assert should_spoof_dash_speed(cp, SimpleNamespace(disable_openpilot_long=False))
def test_volt_one_pedal_lift_brake_seeds_low_speed_braking(self):
assert get_volt_one_pedal_lift_brake(2.1 * CV.MPH_TO_MS) == 0
assert get_volt_one_pedal_lift_brake(2.0 * CV.MPH_TO_MS) == 20
assert get_volt_one_pedal_lift_brake(0.10) == 80
def test_volt_camera_no_camera_sends_acc_dashboard_without_dash_spoof(self):
cp = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_CAMERA, flags=GMFlags.NO_CAMERA.value)
@@ -213,3 +588,226 @@ class TestGMCarController:
msgs = gmcan.create_gm_cc_spam_command(packer, controller, cs, actuators, SimpleNamespace(is_metric=False))
assert [msg[2] for msg in msgs] == [0]
@parameterized.expand([
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
CAR.CHEVROLET_BOLT_CC_2022_2023,
])
def test_bolt_cc_redneck_ignores_small_setpoint_error(self, car_model):
packer = CANPacker(DBC[car_model][Bus.pt])
controller = SimpleNamespace(frame=int(2.0 / DT_CTRL), last_button_frame=0, apply_speed=0)
cs = SimpleNamespace(
CP=SimpleNamespace(
carFingerprint=car_model,
minEnableSpeed=24 * CV.MPH_TO_MS,
),
buttons_counter=2,
out=SimpleNamespace(
vEgo=(60.6 * CV.MPH_TO_MS) / 1.01,
cruiseState=SimpleNamespace(speed=60 * CV.MPH_TO_MS),
),
)
msgs = gmcan.create_gm_cc_spam_command(packer, controller, cs, SimpleNamespace(accel=0.0), SimpleNamespace(is_metric=False))
assert msgs == []
assert controller.apply_speed == 60
def test_non_bolt_cc_redneck_keeps_existing_setpoint_selector(self):
packer = CANPacker(DBC[CAR.CHEVROLET_EQUINOX_CC][Bus.pt])
controller = SimpleNamespace(frame=int(2.0 / DT_CTRL), last_button_frame=0, apply_speed=0)
cs = SimpleNamespace(
CP=SimpleNamespace(
carFingerprint=CAR.CHEVROLET_EQUINOX_CC,
flags=GMFlags.CC_LONG.value,
minEnableSpeed=24 * CV.MPH_TO_MS,
),
buttons_counter=2,
out=SimpleNamespace(
vEgo=(60.6 * CV.MPH_TO_MS) / 1.01,
cruiseState=SimpleNamespace(speed=60 * CV.MPH_TO_MS),
),
)
msgs = gmcan.create_gm_cc_spam_command(packer, controller, cs, SimpleNamespace(accel=0.0), SimpleNamespace(is_metric=False))
assert len(msgs) == 1
assert controller.apply_speed == 61
def test_bolt_cc_redneck_requires_persistent_acceleration_after_deceleration(self):
cp = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021)
controller = SimpleNamespace(
frame=100,
gm_cc_last_direction_button=CruiseButtons.DECEL_SET,
gm_cc_last_direction_frame=100,
gm_cc_pending_reverse_button=CruiseButtons.INIT,
gm_cc_pending_reverse_frame=0,
)
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.RES_ACCEL) == CruiseButtons.INIT
controller.frame += int(0.5 / DT_CTRL)
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.RES_ACCEL) == CruiseButtons.INIT
controller.frame += int(0.11 / DT_CTRL)
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.RES_ACCEL) == CruiseButtons.RES_ACCEL
def test_bolt_cc_redneck_deceleration_is_not_debounced(self):
cp = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021)
controller = SimpleNamespace(
frame=100,
gm_cc_last_direction_button=CruiseButtons.RES_ACCEL,
gm_cc_last_direction_frame=100,
gm_cc_pending_reverse_button=CruiseButtons.INIT,
gm_cc_pending_reverse_frame=0,
)
assert gmcan.stabilize_bolt_cc_button(controller, cp, CruiseButtons.DECEL_SET) == CruiseButtons.DECEL_SET
def test_xt4_cc_redneck_spam_matches_physical_button_burst(self):
packer = CANPacker(DBC[CAR.CADILLAC_XT4_CC][Bus.pt])
controller = SimpleNamespace(
frame=int(0.3 / DT_CTRL),
last_button_frame=0,
apply_speed=0,
malibu_button_phase=0,
xt4_cc_button_burst_remaining=0,
xt4_cc_button_burst_button=CruiseButtons.INIT,
xt4_cc_button_burst_last_counter=-1,
xt4_cc_button_observed_counter=-1,
xt4_cc_button_counter_frame=0,
)
cs = SimpleNamespace(
CP=SimpleNamespace(
carFingerprint=CAR.CADILLAC_XT4_CC,
flags=GMFlags.CC_LONG.value,
minEnableSpeed=24 * CV.MPH_TO_MS,
),
buttons_counter=0,
out=SimpleNamespace(
vEgo=25.0,
cruiseState=SimpleNamespace(speed=20.0),
),
)
actuators = SimpleNamespace(accel=1.0)
dats = []
send_counts = []
for counter in (0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 0, 0, 0, 1, 1, 1):
cs.buttons_counter = counter
msgs = gmcan.create_gm_cc_spam_command(packer, controller, cs, actuators, SimpleNamespace(is_metric=False))
send_counts.append(len(msgs))
dats.extend(bytes(msg[1]).hex() for msg in msgs)
controller.frame += 1
assert send_counts == [0, 1, 0] * gmcan.XT4_CC_BUTTON_BURST_FRAMES
assert dats == [
"000000010125de",
"00000001022acd",
"00000001032fbc",
"000000010020ef",
"000000010125de",
"00000001022acd",
]
assert controller.xt4_cc_button_burst_remaining == 0
def test_acc_dashboard_command_preserves_raw_fcw_alert_level(self):
packer = CANPacker(DBC[CAR.CHEVROLET_BOLT_ACC_2022_2023][Bus.pt])
parser = CANParser(DBC[CAR.CHEVROLET_BOLT_ACC_2022_2023][Bus.pt], [("ASCMActiveCruiseControlStatus", 0)], 0)
msg = gmcan.create_acc_dashboard_command(
packer,
0,
True,
100,
SimpleNamespace(leadDistanceBars=3, leadVisible=True),
0x2,
)
parser.update([0, [msg]])
values = parser.vl["ASCMActiveCruiseControlStatus"]
assert values["ACCAlwaysOne"] == 1
assert values["ACCAlwaysOne2"] == 1
assert values["ACCCruiseState"] == 2
assert values["ACCCmdActive"] == 1
assert values["FCWAlert"] == 2
def test_acc_dashboard_command_allows_camera_acc_zero_reserved_bits(self):
packer = CANPacker(DBC[CAR.CHEVROLET_TRAILBLAZER][Bus.pt])
parser = CANParser(DBC[CAR.CHEVROLET_TRAILBLAZER][Bus.pt], [("ASCMActiveCruiseControlStatus", 0)], 0)
msg = gmcan.create_acc_dashboard_command(
packer,
0,
True,
67.1875,
SimpleNamespace(leadDistanceBars=1, leadVisible=False),
0,
acc_always_one=0,
)
parser.update([0, [msg]])
values = parser.vl["ASCMActiveCruiseControlStatus"]
assert msg[1] == b"\x00\x02\x94\x33\x00\x00"
assert values["ACCAlwaysOne"] == 0
assert values["ACCAlwaysOne2"] == 0
assert values["ACCCruiseState"] == 2
assert values["ACCCmdActive"] == 1
def test_acc_dashboard_always_one_matches_camera_acc_platforms(self):
assert get_acc_dashboard_always_one(SimpleNamespace(carFingerprint=CAR.CHEVROLET_TRAILBLAZER)) == 0
assert get_acc_dashboard_always_one(SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023)) == 1
def test_acc_dashboard_command_uses_openpilot_hud_when_disengaged(self):
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_ASCM][Bus.pt])
parser = CANParser(DBC[CAR.CHEVROLET_VOLT_ASCM][Bus.pt], [("ASCMActiveCruiseControlStatus", 0)], 0)
msg = gmcan.create_acc_dashboard_command(
packer,
0,
False,
50,
SimpleNamespace(leadDistanceBars=2, leadVisible=True),
0x3,
)
parser.update([0, [msg]])
values = parser.vl["ASCMActiveCruiseControlStatus"]
assert values["ACCSpeedSetpoint"] == 50
assert values["ACCCruiseState"] == 2
assert values["ACCGapLevel"] == 0
assert values["ACCCmdActive"] == 0
assert values["ACCLeadCar"] == 1
assert values["FCWAlert"] == 3
def test_acc_dashboard_fcw_alert_prefers_openpilot_alert(self):
cs = SimpleNamespace(
stock_fcw_alert=1,
out=SimpleNamespace(stockAeb=False, stockFcw=False),
)
assert get_acc_dashboard_fcw_alert(VisualAlert.fcw, cs) == 0x3
def test_acc_dashboard_fcw_alert_replays_stock_camera_alert_level(self):
cs = SimpleNamespace(
stock_fcw_alert=2,
out=SimpleNamespace(stockAeb=False, stockFcw=False),
)
assert get_acc_dashboard_fcw_alert(VisualAlert.none, cs) == 2
def test_acc_dashboard_fcw_alert_falls_back_to_stock_aeb_event(self):
cs = SimpleNamespace(
stock_fcw_alert=0,
out=SimpleNamespace(stockAeb=True, stockFcw=False),
)
assert get_acc_dashboard_fcw_alert(VisualAlert.none, cs) == 0x3
def test_acc_dashboard_fcw_alert_falls_back_to_stock_fcw_event(self):
cs = SimpleNamespace(
stock_fcw_alert=0,
out=SimpleNamespace(stockAeb=False, stockFcw=True),
)
assert get_acc_dashboard_fcw_alert(VisualAlert.none, cs) == 0x3
@@ -0,0 +1,86 @@
from types import SimpleNamespace
from opendbc.can import CANPacker
from opendbc.car.gm import gmcan
from opendbc.car.gm.values import CAR, DBC
class TestGMCan:
def setup_method(self):
self.packer = CANPacker(DBC[CAR.CHEVROLET_BOLT_ACC_2022_2023]["pt"])
def test_gas_regen_command_matches_starpilot_bolt_acc(self):
addr, dat, bus = gmcan.create_gas_regen_command(self.packer, 0, 5000, 1, True, False)
assert addr == 0x2CB
assert bus == 0
assert dat.hex() == "41429c4000bd63bf"
def test_gas_regen_command_preserves_always_one3_layout(self):
_, dat, _ = gmcan.create_gas_regen_command(self.packer, 0, 0, 1, True, False, include_always_one3=True)
assert dat.hex() == "4142800000bd7fff"
def test_gas_regen_command_encodes_high_bit_above_8191(self):
_, dat, _ = gmcan.create_gas_regen_command(self.packer, 0, 8848, 1, True, False)
decoded = ((dat[1] & 0x1) << 13) | (dat[2] << 5) | ((dat[3] & 0xF8) >> 3)
assert dat[1] & 0x1
assert decoded == 8848
def test_acc_2cd_command_matches_stock_camera_counter_layout(self):
assert [gmcan.create_acc_2cd_command(0, idx)[1].hex() for idx in range(4)] == [
"002c03d3fd",
"402c03d3fc",
"802c03d3fb",
"c02c03d3fa",
]
def test_prndl2_command_matches_bolt_gen2_regen_paddle_spoof(self):
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL)
addr, dat, bus = gmcan.create_prndl2_command(self.packer, 0, False, CP)
assert addr == 0x1F5
assert bus == 0
assert dat.hex() == "0c0c000600000100"
addr, dat, bus = gmcan.create_prndl2_command(self.packer, 0, True, CP)
assert addr == 0x1F5
assert bus == 0
assert dat.hex() == "0c0c000500020100"
def test_prndl2_command_matches_bolt_gen1_regen_paddle_spoof(self):
CP = SimpleNamespace(carFingerprint=CAR.CHEVROLET_BOLT_CC_2018_2021)
addr, dat, bus = gmcan.create_prndl2_command(self.packer, 0, True, CP)
assert addr == 0x1F5
assert bus == 0
assert dat.hex() == "0c0c000700020100"
def test_regen_paddle_command_matches_bolt_spoof(self):
addr, dat, bus = gmcan.create_regen_paddle_command(self.packer, 0, False)
assert addr == 0xBD
assert bus == 0
assert dat.hex() == "00000000000000"
addr, dat, bus = gmcan.create_regen_paddle_command(self.packer, 0, True)
assert addr == 0xBD
assert bus == 0
assert dat.hex() == "20000000000000"
def test_gas_regen_command_matches_starpilot_volt_2019(self):
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_2019]["pt"])
addr, dat, bus = gmcan.create_gas_regen_command(packer, 0, 5000, 1, True, False, include_always_one3=True, use_volt_layout=True)
assert addr == 0x2CB
assert bus == 0
assert dat.hex() == "41429c4000bd63bf"
def test_gas_regen_command_matches_starpilot_volt_ascm(self):
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_ASCM]["pt"])
addr, dat, bus = gmcan.create_gas_regen_command(packer, 0, 5000, 1, True, False, include_always_one3=True, use_volt_layout=True)
assert addr == 0x2CB
assert bus == 0
assert dat.hex() == "41429c4000bd63bf"
+59 -21
View File
@@ -233,7 +233,7 @@ class CAR(Platforms):
)
CHEVROLET_VOLT = GMASCMPlatformConfig(
[GMCarDocs("Chevrolet Volt 2017-18", min_enable_speed=0, video="https://youtu.be/QeMCN_4TFfQ")],
GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=15.7, centerToFrontRatio=0.45, tireStiffnessFactor=0.469, minEnableSpeed=-1),
GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=15.7, centerToFrontRatio=0.45, tireStiffnessFactor=1.0, minEnableSpeed=-1), #tire stiffness factor hasn't been updated since 2018 and every other gm is on 1.0
dbc_dict={
Bus.pt: "gm_global_a_powertrain_volt",
Bus.radar: "gm_global_a_object",
@@ -241,17 +241,17 @@ class CAR(Platforms):
},
)
CHEVROLET_VOLT_ASCM = GMPlatformConfig(
[GMCarDocs("Chevrolet Volt 2017-18 ASCM Harness", min_enable_speed=0, video="https://youtu.be/QeMCN_4TFfQ")],
[GMCarDocs("Chevrolet Volt ASCM Harness 2017-18", min_enable_speed=0, video="https://youtu.be/QeMCN_4TFfQ")],
CHEVROLET_VOLT.specs,
dbc_dict=CHEVROLET_VOLT.dbc_dict,
)
CHEVROLET_VOLT_CAMERA = GMPlatformConfig(
[GMCarDocs("Chevrolet Volt 2017-18 Camera Harness", "Flashed camera-forward integration with ACC")],
[GMCarDocs("Chevrolet Volt Camera Harness 2017-18", "Flashed camera-forward integration with ACC")],
CHEVROLET_VOLT.specs,
dbc_dict=CHEVROLET_VOLT.dbc_dict,
)
CHEVROLET_VOLT_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Volt 2017-18 - No-ACC", min_enable_speed=0)],
[GMCarDocs("Chevrolet Volt No-ACC 2017-18", min_enable_speed=0)],
CHEVROLET_VOLT.specs,
dbc_dict=CHEVROLET_VOLT.dbc_dict,
)
@@ -264,7 +264,7 @@ class CAR(Platforms):
GMCarSpecs(mass=1496, wheelbase=2.83, steerRatio=15.8, centerToFrontRatio=0.4),
)
CHEVROLET_MALIBU_ASCM = GMPlatformConfig(
[GMCarDocs("Chevrolet Malibu 2017-19 ASCM Harness")],
[GMCarDocs("Chevrolet Malibu ASCM Harness 2017-19")],
CHEVROLET_MALIBU.specs,
)
GMC_ACADIA = GMASCMPlatformConfig(
@@ -272,13 +272,21 @@ class CAR(Platforms):
GMCarSpecs(mass=1975, wheelbase=2.86, steerRatio=14.4, centerToFrontRatio=0.4),
)
GMC_ACADIA_ASCM = GMPlatformConfig(
[GMCarDocs("GMC Acadia 2018 ASCM Harness", video="https://www.youtube.com/watch?v=0ZN6DdsBUZo")],
[GMCarDocs("GMC Acadia ASCM Harness 2018", video="https://www.youtube.com/watch?v=0ZN6DdsBUZo")],
GMC_ACADIA.specs,
)
BUICK_LACROSSE = GMASCMPlatformConfig(
[GMCarDocs("Buick LaCrosse 2017-19", "Driver Confidence Package 2")],
GMCarSpecs(mass=1712, wheelbase=2.91, steerRatio=15.8, centerToFrontRatio=0.4),
)
BUICK_LACROSSE_ASCM = GMPlatformConfig(
[GMCarDocs("Buick LaCrosse ASCM Harness 2017-19")],
BUICK_LACROSSE.specs,
)
BUICK_LACROSSE_ASCM_19US = GMPlatformConfig(
[GMCarDocs("Buick LaCrosse US ASCM Harness 2019")],
BUICK_LACROSSE.specs,
)
BUICK_REGAL = GMASCMPlatformConfig(
[GMCarDocs("Buick Regal Essence 2018")],
GMCarSpecs(mass=1714, wheelbase=2.83, steerRatio=14.4, centerToFrontRatio=0.4),
@@ -288,7 +296,7 @@ class CAR(Platforms):
GMCarSpecs(mass=2564, wheelbase=2.95, steerRatio=17.3),
)
CADILLAC_ESCALADE_ASCM = GMPlatformConfig(
[GMCarDocs("Cadillac Escalade 2018 ASCM Harness", "Driver Assist Package")],
[GMCarDocs("Cadillac Escalade ASCM Harness 2018", "Driver Assist Package")],
CADILLAC_ESCALADE.specs,
)
CADILLAC_ESCALADE_ESV = GMASCMPlatformConfig(
@@ -299,6 +307,10 @@ class CAR(Platforms):
[GMCarDocs("Cadillac Escalade ESV 2019", "Adaptive Cruise Control (ACC) & LKAS")],
CADILLAC_ESCALADE_ESV.specs,
)
CADILLAC_ESCALADE_ESV_2019_ASCM = GMPlatformConfig(
[GMCarDocs("Cadillac Escalade ESV Platinum ASCM Harness 2019", "Adaptive Cruise Control (ACC) & LKAS")],
CADILLAC_ESCALADE_ESV_2019.specs,
)
CHEVROLET_BOLT_ACC_2022_2023 = GMPlatformConfig(
[
GMCarDocs("Chevrolet Bolt ACC 2022-23", "Premier or Premier Redline Trim without Super Cruise Package", video="https://youtu.be/xvwzGMUA210"),
@@ -306,19 +318,19 @@ class CAR(Platforms):
GMCarSpecs(mass=1669, wheelbase=2.63779, steerRatio=16.8, centerToFrontRatio=0.4, tireStiffnessFactor=1.0),
)
CHEVROLET_BOLT_ACC_2022_2023_PEDAL = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV 2022-23 ACC w Pedal")],
[GMCarDocs("Chevrolet Bolt EV ACC w Pedal 2022-23")],
CHEVROLET_BOLT_ACC_2022_2023.specs,
)
CHEVROLET_BOLT_CC_2022_2023 = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV 2022-23 - No-ACC")],
[GMCarDocs("Chevrolet Bolt EV No-ACC 2022-23")],
CHEVROLET_BOLT_ACC_2022_2023.specs,
)
CHEVROLET_BOLT_CC_2018_2021 = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV 2018-21 - No-ACC")],
[GMCarDocs("Chevrolet Bolt EV No-ACC 2018-21")],
CHEVROLET_BOLT_ACC_2022_2023.specs,
)
CHEVROLET_BOLT_CC_2017 = GMPlatformConfig(
[GMCarDocs("Chevrolet Bolt EV 2017 - No-ACC")],
[GMCarDocs("Chevrolet Bolt EV No-ACC 2017")],
CHEVROLET_BOLT_ACC_2022_2023.specs,
)
@@ -329,6 +341,13 @@ class CAR(Platforms):
],
GMCarSpecs(mass=2994, wheelbase=3.75, steerRatio=16.3, tireStiffnessFactor=1.0),
)
CHEVROLET_SILVERADO_CC = GMPlatformConfig(
[
GMCarDocs("Chevrolet Silverado 1500 No-ACC 2020-21"),
GMCarDocs("GMC Sierra 1500 No-ACC 2020-21"),
],
CHEVROLET_SILVERADO.specs,
)
CHEVROLET_EQUINOX = GMPlatformConfig(
[GMCarDocs("Chevrolet Equinox 2019-22")],
GMCarSpecs(mass=1588, wheelbase=2.72, steerRatio=14.4, centerToFrontRatio=0.4),
@@ -342,7 +361,7 @@ class CAR(Platforms):
CarSpecs(mass=2731, wheelbase=3.302, steerRatio=17.3, centerToFrontRatio=0.49),
)
GMC_YUKON_CC = GMPlatformConfig(
[GMCarDocs("GMC Yukon - No-ACC")],
[GMCarDocs("GMC Yukon No-ACC 2019-20")],
CarSpecs(mass=2541, wheelbase=2.95, steerRatio=16.3, centerToFrontRatio=0.4),
)
GMC_YUKON = GMPlatformConfig(
@@ -353,6 +372,14 @@ class CAR(Platforms):
[GMCarDocs("Cadillac XT4 2023", "Driver Assist Package")],
GMCarSpecs(mass=1660, wheelbase=2.78, steerRatio=14.4, centerToFrontRatio=0.4),
)
CADILLAC_XT4_CC = GMPlatformConfig(
[GMCarDocs("Cadillac XT4 No-ACC 2023")],
CADILLAC_XT4.specs,
)
CADILLAC_XT5 = GMSDGMPlatformConfig(
[GMCarDocs("Cadillac XT5 2022", "Driver Assist Package")],
CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5),
)
CADILLAC_XT6 = GMPlatformConfig(
[GMCarDocs("Cadillac XT6 2020", "Driver Assist Package")],
GMCarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.5, centerToFrontRatio=0.4),
@@ -378,31 +405,31 @@ class CAR(Platforms):
CarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.0, centerToFrontRatio=0.5),
)
CADILLAC_CT6_CC = GMPlatformConfig(
[GMCarDocs("Cadillac CT6 - No-ACC")],
[GMCarDocs("Cadillac CT6 No-ACC 2016-20")],
CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4),
)
CADILLAC_XT5_CC = GMPlatformConfig(
[GMCarDocs("Cadillac XT5 - No-ACC")],
CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5),
[GMCarDocs("Cadillac XT5 No-ACC 2022")],
CADILLAC_XT5.specs,
)
CHEVROLET_EQUINOX_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Equinox 2019-22 - No-ACC")],
[GMCarDocs("Chevrolet Equinox No-ACC 2019-22")],
CHEVROLET_EQUINOX.specs,
)
CHEVROLET_MALIBU_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Malibu 2023 - No-ACC")],
[GMCarDocs("Chevrolet Malibu No-ACC 2023")],
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=18.25, centerToFrontRatio=0.4, tireStiffnessFactor=0.997),
)
CHEVROLET_MALIBU_HYBRID_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Malibu Hybrid 2017 - No-ACC")],
[GMCarDocs("Chevrolet Malibu Hybrid No-ACC 2017")],
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4),
)
CHEVROLET_SUBURBAN_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Suburban Premier 2016-20 - No-ACC")],
[GMCarDocs("Chevrolet Suburban Premier No-ACC 2016-20")],
CHEVROLET_SUBURBAN.specs,
)
CHEVROLET_TRAILBLAZER_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Trailblazer 2021-22 - No-ACC")],
[GMCarDocs("Chevrolet Trailblazer No-ACC 2021-22")],
CHEVROLET_TRAILBLAZER.specs,
)
CHEVROLET_TRAX = GMPlatformConfig(
@@ -527,6 +554,7 @@ ALT_ACCS = {CAR.GMC_YUKON, CAR.GMC_YUKON_CC}
# We're integrated at the Safety Data Gateway Module on these cars
SDGM_CAR = {
CAR.CADILLAC_XT4,
CAR.CADILLAC_XT5,
CAR.CADILLAC_XT6,
CAR.CHEVROLET_TRAVERSE,
CAR.CHEVROLET_BLAZER,
@@ -549,6 +577,8 @@ CC_ONLY_CAR = {
CAR.CADILLAC_XT5_CC,
CAR.CHEVROLET_MALIBU_CC,
CAR.CHEVROLET_MALIBU_HYBRID_CC,
CAR.CHEVROLET_SILVERADO_CC,
CAR.CADILLAC_XT4_CC,
}
CC_REGEN_PADDLE_CAR = {
CAR.CHEVROLET_BOLT_CC_2018_2021,
@@ -559,7 +589,15 @@ CC_REGEN_PADDLE_CAR = {
CAMERA_ACC_CAR.update(CC_ONLY_CAR)
# ASCM-INT paths are only enabled when SASCM (0x2FF) is detected at runtime
ASCM_INT = {CAR.CHEVROLET_VOLT_ASCM, CAR.GMC_ACADIA_ASCM, CAR.CHEVROLET_MALIBU_ASCM, CAR.CADILLAC_ESCALADE_ASCM}
ASCM_INT = {
CAR.CHEVROLET_VOLT_ASCM,
CAR.GMC_ACADIA_ASCM,
CAR.CHEVROLET_MALIBU_ASCM,
CAR.CADILLAC_ESCALADE_ASCM,
CAR.CADILLAC_ESCALADE_ESV_2019_ASCM,
CAR.BUICK_LACROSSE_ASCM,
CAR.BUICK_LACROSSE_ASCM_19US,
}
STEER_THRESHOLD = 1.0
+281 -47
View File
@@ -1,16 +1,130 @@
import math
import numpy as np
from opendbc.can import CANPacker
from opendbc.car import Bus, DT_CTRL, rate_limit, make_tester_present_msg, structs
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY, Bus, DT_CTRL, create_gas_interceptor_command, rate_limit, make_tester_present_msg, structs
from opendbc.car.honda import hondacan
from opendbc.car.honda.values import CAR, CruiseButtons, HONDA_BOSCH, HONDA_BOSCH_CANFD, HONDA_BOSCH_RADARLESS, \
HONDA_BOSCH_TJA_CONTROL, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams
from opendbc.car.honda.values import (
CAR,
CruiseButtons,
HONDA_BOSCH,
HONDA_BOSCH_CANFD,
HONDA_BOSCH_RADARLESS,
HONDA_BOSCH_TJA_CONTROL,
HONDA_NIDEC_ALT_PCM_ACCEL,
CarControllerParams,
HondaFlags,
)
from opendbc.car.interfaces import CarControllerBase
from openpilot.common.params import Params
VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
def get_civic_bosch_modified_torque_lpf_tau(torque_cmd: float, prev_torque_cmd: float, v_ego: float) -> float:
torque_delta = abs(float(torque_cmd) - float(prev_torque_cmd))
torque_cmd_abs = abs(float(torque_cmd))
sign_change = (float(torque_cmd) * float(prev_torque_cmd)) < 0.0
highway = v_ego > (50.0 * 0.44704)
low_speed = v_ego < (30.0 * 0.44704)
if highway:
if torque_cmd_abs < 0.12:
return 0.18 if sign_change else 0.16
if sign_change and torque_delta > 0.15:
return 0.10
return 0.12
if sign_change and torque_cmd_abs < 0.25:
return 0.28 if low_speed else 0.22
# Extra damping for the tiny near-center commands where both modified EPS
# firmwares still show hunting and escalating sway.
if torque_cmd_abs < 0.12:
return 0.28 if low_speed else 0.20
if low_speed:
if torque_delta > 0.50:
return 0.14
elif torque_delta > 0.20:
return 0.16
elif torque_delta > 0.05:
return 0.18
else:
return 0.22
if torque_delta > 0.50:
return 0.12
elif torque_delta > 0.20:
return 0.13
elif torque_delta > 0.05:
return 0.15
else:
return 0.18
def get_civic_bosch_modified_steering_pressed(
raw_pressed: bool, steering_torque: float, torque_cmd: float, filter_s: float, was_pressed: bool
) -> tuple[float, bool]:
torque_product = steering_torque * torque_cmd
torque_cmd_abs = abs(torque_cmd)
if raw_pressed:
if torque_product < 0.0:
trigger_s = 0.08 if was_pressed else 0.10
rise_rate = 1.0
elif torque_cmd_abs < 0.10:
trigger_s = 0.20 if was_pressed else 0.24
rise_rate = 0.75
else:
trigger_s = 0.70 if was_pressed else 0.80
rise_rate = 0.50
filter_s = min(1.0, filter_s + (rise_rate * DT_CTRL))
steering_pressed = filter_s >= trigger_s
else:
filter_s = max(0.0, filter_s - 8.0 * DT_CTRL)
steering_pressed = filter_s > 0.04 and was_pressed
return filter_s, steering_pressed
def get_honda_bosch_wind_brake_mps2(v_ego: float) -> float:
return float(np.interp(v_ego, [0.0, 13.4, 22.4, 31.3, 40.2], [0.000, 0.049, 0.136, 0.267, 0.441]))
def update_honda_bosch_live_learning(
gas_factor: float,
wind_factor: float,
wind_factor_before_brake: float,
desired_accel: float,
actual_accel: float,
gas_pedal_force: float,
wind_brake_mps2: float,
brake_pressed: bool,
v_ego: float,
) -> tuple[float, float, float]:
accel_error = desired_accel - actual_accel
if accel_error != 0.0 and gas_pedal_force > 0.0:
gas_factor = float(np.clip(gas_factor + accel_error / 50.0 * gas_pedal_force, 0.1, 3.0))
if accel_error != 0.0 and not brake_pressed and v_ego > 0.0:
wind_adjust = 1.0 + wind_brake_mps2 / 1000.0
if accel_error > 0.0:
wind_factor = float(np.clip(wind_factor * wind_adjust, 0.1, 3.0))
else:
wind_factor = float(np.clip(wind_factor / wind_adjust, 0.1, 3.0))
if gas_pedal_force <= 0.0:
wind_factor = max(wind_factor, wind_factor_before_brake)
else:
wind_factor_before_brake = wind_factor
return gas_factor, wind_factor, wind_factor_before_brake
def compute_gb_honda_bosch(accel, speed):
# TODO returns 0s, is unused
return 0.0, 0.0
@@ -36,18 +150,18 @@ def compute_gas_brake(accel, speed, fingerprint):
# TODO not clear this does anything useful
def actuator_hysteresis(brake, braking, brake_steady, v_ego, car_fingerprint):
# hyst params
brake_hyst_on = 0.02 # to activate brakes exceed this value
brake_hyst_on = 0.02 # to activate brakes exceed this value
brake_hyst_off = 0.005 # to deactivate brakes below this value
brake_hyst_gap = 0.01 # don't change brake command for small oscillations within this value
brake_hyst_gap = 0.01 # don't change brake command for small oscillations within this value
# *** hysteresis logic to avoid brake blinking. go above 0.1 to trigger
if (brake < brake_hyst_on and not braking) or brake < brake_hyst_off:
brake = 0.
braking = brake > 0.
brake = 0.0
braking = brake > 0.0
# for small brake oscillations within brake_hyst_gap, don't change the brake command
if brake == 0.:
brake_steady = 0.
if brake == 0.0:
brake_steady = 0.0
elif brake > brake_steady + brake_hyst_gap:
brake_steady = brake - brake_hyst_gap
elif brake < brake_steady - brake_hyst_gap:
@@ -64,7 +178,7 @@ def brake_pump_hysteresis(apply_brake, apply_brake_last, last_pump_ts, ts):
# - there is an increment in brake request
# - we are applying steady state brakes and we haven't been running the pump
# for more than 20s (to prevent pressure bleeding)
if apply_brake > apply_brake_last or (ts - last_pump_ts > 20. and apply_brake > 0):
if apply_brake > apply_brake_last or (ts - last_pump_ts > 20.0 and apply_brake > 0):
last_pump_ts = ts
# once the pump is on, run it for at least 0.2s
@@ -93,14 +207,15 @@ class CarController(CarControllerBase):
super().__init__(dbc_names, CP)
self.packer = CANPacker(dbc_names[Bus.pt])
self.params = CarControllerParams(CP)
self.param_store = Params()
self.CAN = hondacan.CanBus(CP)
self.tja_control = CP.carFingerprint in HONDA_BOSCH_TJA_CONTROL
self.braking = False
self.brake_steady = 0.
self.brake_last = 0.
self.brake_steady = 0.0
self.brake_last = 0.0
self.apply_brake_last = 0
self.last_pump_ts = 0.
self.last_pump_ts = 0.0
self.stopping_counter = 0
self.accel = 0.0
@@ -108,12 +223,41 @@ class CarController(CarControllerBase):
self.gas = 0.0
self.brake = 0.0
self.last_torque = 0.0
self.torque_lpf = 0.0
self.prev_torque_cmd = 0.0
self.steering_pressed_filter_s = 0.0
self.steering_pressed_robust_prev = False
self.bosch_last_gas = 0.0
self.bosch_gas_factor = self.param_store.get_float("HondaGasFactorParams", default=1.0)
self.bosch_wind_factor = self.param_store.get_float("HondaWindFactorParams", default=1.0)
self.bosch_wind_factor_before_brake = self.bosch_wind_factor
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
self.pitch = 0.0
def _modified_civic_standard_active(self) -> bool:
return self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH and bool(self.CP.flags & HondaFlags.EPS_MODIFIED)
def _filtered_steering_pressed(self, CS, torque_cmd: float) -> bool:
self.steering_pressed_filter_s, steering_pressed = get_civic_bosch_modified_steering_pressed(
bool(CS.out.steeringPressed),
float(getattr(CS.out, "steeringTorque", 0.0)),
float(torque_cmd),
self.steering_pressed_filter_s,
self.steering_pressed_robust_prev,
)
self.steering_pressed_robust_prev = steering_pressed
return steering_pressed
def update(self, CC, CS, now_nanos, starpilot_toggles):
actuators = CC.actuators
hud_control = CC.hudControl
hud_v_cruise = hud_control.setSpeed / CS.v_cruise_factor if hud_control.speedVisible else 255
pcm_cancel_cmd = CC.cruiseControl.cancel
gas_interceptor_command = 0.0
if len(CC.orientationNED) == 3:
self.pitch = CC.orientationNED[1]
hill_brake = math.sin(self.pitch) * ACCELERATION_DUE_TO_GRAVITY
if CC.longActive:
accel = actuators.accel
@@ -122,17 +266,36 @@ class CarController(CarControllerBase):
accel = 0.0
gas, brake = 0.0, 0.0
torque_cmd = float(actuators.torque)
filtered_steering_pressed = bool(CS.out.steeringPressed)
if self._modified_civic_standard_active():
if CC.latActive:
filtered_steering_pressed = self._filtered_steering_pressed(CS, torque_cmd)
if filtered_steering_pressed:
self.torque_lpf = 0.0
self.prev_torque_cmd = 0.0
torque_cmd = 0.0
else:
tau = get_civic_bosch_modified_torque_lpf_tau(torque_cmd, self.prev_torque_cmd, CS.out.vEgo)
alpha = DT_CTRL / (tau + DT_CTRL)
self.torque_lpf = alpha * torque_cmd + ((1.0 - alpha) * self.torque_lpf)
self.prev_torque_cmd = torque_cmd
torque_cmd = self.torque_lpf
else:
self.torque_lpf = 0.0
self.prev_torque_cmd = 0.0
self.steering_pressed_filter_s = 0.0
self.steering_pressed_robust_prev = False
# *** rate limit steer ***
limited_torque = rate_limit(actuators.torque, self.last_torque, -self.params.STEER_DELTA_DOWN * DT_CTRL,
self.params.STEER_DELTA_UP * DT_CTRL)
limited_torque = rate_limit(torque_cmd, self.last_torque, -self.params.STEER_DELTA_DOWN * DT_CTRL, self.params.STEER_DELTA_UP * DT_CTRL)
self.last_torque = limited_torque
# *** apply brake hysteresis ***
pre_limit_brake, self.braking, self.brake_steady = actuator_hysteresis(brake, self.braking, self.brake_steady,
CS.out.vEgo, self.CP.carFingerprint)
pre_limit_brake, self.braking, self.brake_steady = actuator_hysteresis(brake, self.braking, self.brake_steady, CS.out.vEgo, self.CP.carFingerprint)
# *** rate limit after the enable check ***
self.brake_last = rate_limit(pre_limit_brake, self.brake_last, -2., DT_CTRL)
self.brake_last = rate_limit(pre_limit_brake, self.brake_last, -2.0, DT_CTRL)
# vehicle hud display, wait for one update from 10Hz 0x304 msg
alert_fcw, alert_steer_required = process_hud_alert(hud_control.visualAlert)
@@ -140,8 +303,7 @@ class CarController(CarControllerBase):
# **** process the car messages ****
# steer torque is converted back to CAN reference (positive when steering right)
apply_torque = int(np.interp(-limited_torque * self.params.STEER_MAX,
self.params.STEER_LOOKUP_BP, self.params.STEER_LOOKUP_V))
apply_torque = int(np.interp(-limited_torque * self.params.STEER_MAX, self.params.STEER_LOOKUP_BP, self.params.STEER_LOOKUP_V))
# Send CAN commands
can_sends = []
@@ -149,37 +311,29 @@ class CarController(CarControllerBase):
# tester present - w/ no response (keeps radar disabled)
if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and self.CP.openpilotLongitudinalControl:
if self.frame % 10 == 0:
can_sends.append(make_tester_present_msg(0x18DAB0F1, 1, suppress_response=True))
can_sends.append(make_tester_present_msg(0x18DAB0F1, self.CAN.pt, suppress_response=True))
# Send steering command.
can_sends.append(hondacan.create_steering_control(self.packer, self.CAN, apply_torque, CC.latActive, self.tja_control))
# wind brake from air resistance decel at high speed
wind_brake = np.interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15])
wind_brake = float(np.interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15]))
wind_brake_mps2 = get_honda_bosch_wind_brake_mps2(CS.out.vEgo)
# all of this is only relevant for HONDA NIDEC
max_accel = np.interp(CS.out.vEgo, self.params.NIDEC_MAX_ACCEL_BP, self.params.NIDEC_MAX_ACCEL_V)
# TODO this 1.44 is just to maintain previous behavior
pcm_speed_BP = [-wind_brake,
-wind_brake * (3 / 4),
0.0,
0.5]
pcm_speed_BP = [-wind_brake, -wind_brake * (3 / 4), 0.0, 0.5]
# The Honda ODYSSEY seems to have different PCM_ACCEL
# msgs, is it other cars too?
if not CC.longActive:
if self.CP.enableGasInterceptorDEPRECATED or not CC.longActive:
pcm_speed = 0.0
pcm_accel = int(0.0)
elif self.CP.carFingerprint in HONDA_NIDEC_ALT_PCM_ACCEL:
pcm_speed_V = [0.0,
np.clip(CS.out.vEgo - 3.0, 0.0, 100.0),
np.clip(CS.out.vEgo + 0.0, 0.0, 100.0),
np.clip(CS.out.vEgo + 5.0, 0.0, 100.0)]
pcm_speed_V = [0.0, np.clip(CS.out.vEgo - 3.0, 0.0, 100.0), np.clip(CS.out.vEgo + 0.0, 0.0, 100.0), np.clip(CS.out.vEgo + 5.0, 0.0, 100.0)]
pcm_speed = float(np.interp(gas - brake, pcm_speed_BP, pcm_speed_V))
pcm_accel = int(1.0 * self.params.NIDEC_GAS_MAX)
else:
pcm_speed_V = [0.0,
np.clip(CS.out.vEgo - 2.0, 0.0, 100.0),
np.clip(CS.out.vEgo + 2.0, 0.0, 100.0),
np.clip(CS.out.vEgo + 5.0, 0.0, 100.0)]
pcm_speed_V = [0.0, np.clip(CS.out.vEgo - 2.0, 0.0, 100.0), np.clip(CS.out.vEgo + 2.0, 0.0, 100.0), np.clip(CS.out.vEgo + 5.0, 0.0, 100.0)]
pcm_speed = float(np.interp(gas - brake, pcm_speed_BP, pcm_speed_V))
pcm_accel = int(np.clip((accel / 1.44) / max_accel, 0.0, 1.0) * self.params.NIDEC_GAS_MAX)
@@ -199,35 +353,108 @@ class CarController(CarControllerBase):
if self.CP.carFingerprint in HONDA_BOSCH:
self.accel = float(np.clip(accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX))
self.gas = float(np.interp(accel, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V))
gas_pedal_force = self.accel + hill_brake
if self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS:
gas_pedal_force += wind_brake_mps2 * self.bosch_wind_factor
if actuators.longControlState == LongCtrlState.pid and not CS.out.gasPressed:
gas_error = self.accel - CS.out.aEgo
if gas_error != 0.0 and gas_pedal_force > 0.0:
if self.CP.carFingerprint == CAR.HONDA_INSIGHT:
gas_learn_speed = 150.0
elif self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR):
gas_learn_speed = 300.0
else:
gas_learn_speed = 50.0
self.bosch_gas_factor = float(np.clip(self.bosch_gas_factor + gas_error / gas_learn_speed * gas_pedal_force, 0.1, 3.0))
if gas_error != 0.0 and not CS.out.brakePressed and CS.out.vEgo > 0.0:
wind_learn_speed = 100.0 if self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR) else 1000.0
wind_adjust = 1.0 + wind_brake_mps2 / wind_learn_speed
if gas_error > 0.0:
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor * wind_adjust, 0.1, 3.0))
else:
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor / wind_adjust, 0.1, 3.0))
if gas_pedal_force <= 0.0:
self.bosch_wind_factor = max(self.bosch_wind_factor, self.bosch_wind_factor_before_brake)
else:
self.bosch_wind_factor_before_brake = self.bosch_wind_factor
if gas_pedal_force >= self.params.BOSCH_ACCEL_MAX:
self.bosch_gas_factor = min(self.bosch_gas_factor, self.bosch_gas_factor_before_gasmax)
self.bosch_wind_factor = min(self.bosch_wind_factor, self.bosch_wind_factor_before_gasmax)
else:
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
self.gas = float(np.interp(gas_pedal_force * self.bosch_gas_factor, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V))
self.gas = min(self.gas, max(60.0, self.bosch_last_gas + 60.0))
self.bosch_last_gas = self.gas
stopping = actuators.longControlState == LongCtrlState.stopping
self.stopping_counter = self.stopping_counter + 1 if stopping else 0
can_sends.extend(hondacan.create_acc_commands(self.packer, self.CAN, CC.enabled, CC.longActive, self.accel, self.gas,
self.stopping_counter, self.CP.carFingerprint))
can_sends.extend(
hondacan.create_acc_commands(self.packer, self.CAN, CC.enabled, CC.longActive, self.accel, self.gas, self.stopping_counter, self.CP.carFingerprint)
)
else:
apply_brake = np.clip(self.brake_last - wind_brake, 0.0, 1.0)
apply_brake = int(np.clip(apply_brake * self.params.NIDEC_BRAKE_MAX, 0, self.params.NIDEC_BRAKE_MAX - 1))
pump_on, self.last_pump_ts = brake_pump_hysteresis(apply_brake, self.apply_brake_last, self.last_pump_ts, ts)
pcm_override = True
can_sends.append(hondacan.create_brake_command(self.packer, self.CAN, apply_brake, pump_on,
pcm_override, pcm_cancel_cmd, alert_fcw,
self.CP.carFingerprint, CS.stock_brake))
can_sends.append(
hondacan.create_brake_command(
self.packer, self.CAN, apply_brake, pump_on, pcm_override, pcm_cancel_cmd, alert_fcw, self.CP.carFingerprint, CS.stock_brake
)
)
self.apply_brake_last = apply_brake
self.brake = apply_brake / self.params.NIDEC_BRAKE_MAX
if self.CP.enableGasInterceptorDEPRECATED:
gas_error = actuators.accel - CS.out.aEgo
if not CS.out.gasPressed and actuators.longControlState == LongCtrlState.pid:
if gas_error != 0.0 and gas > 0.0:
self.bosch_gas_factor = float(np.clip(self.bosch_gas_factor + gas_error / 150.0 * (gas * 4.8), 0.1, 3.0))
if gas_error != 0.0 and not CS.out.brakePressed and CS.out.vEgo > 0.0:
wind_adjust = 1.0 + (wind_brake * 4.8) / 1000.0
if gas_error > 0.0:
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor * wind_adjust, 0.1, 5.0))
else:
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor / wind_adjust, 0.1, 5.0))
if gas <= 0.0:
self.bosch_wind_factor = max(self.bosch_wind_factor, self.bosch_wind_factor_before_brake)
else:
self.bosch_wind_factor_before_brake = self.bosch_wind_factor
gas_mult = float(np.interp(CS.out.vEgo, [0.0, 10.0], [0.4, 1.0]))
if CC.longActive:
gas_interceptor_command = float(np.clip(
gas_mult * ((gas * self.bosch_gas_factor) - brake + (wind_brake * self.bosch_wind_factor * 3.0 / 4.0)),
0.0,
1.0,
))
idx = (self.frame // 2) % 0x10
can_sends.append(create_gas_interceptor_command(self.packer, gas_interceptor_command, idx))
# Send dashboard UI commands.
if self.frame % 10 == 0:
if self.CP.openpilotLongitudinalControl:
# On Nidec, this also controls longitudinal positive acceleration
can_sends.append(hondacan.create_acc_hud(self.packer, self.CAN.pt, self.CP, CC.enabled, pcm_speed, pcm_accel,
hud_control, hud_v_cruise, CS.is_metric, CS.acc_hud))
can_sends.append(
hondacan.create_acc_hud(self.packer, self.CAN.pt, self.CP, CC.enabled, pcm_speed, pcm_accel, hud_control, hud_v_cruise, CS.is_metric, CS.acc_hud)
)
steering_available = CS.out.cruiseState.available and CS.out.vEgo > self.CP.minSteerSpeed
reduced_steering = CS.out.steeringPressed
can_sends.extend(hondacan.create_lkas_hud(self.packer, self.CAN.lkas, self.CP, hud_control, CC.latActive,
steering_available, reduced_steering, alert_steer_required, CS.lkas_hud))
reduced_steering = filtered_steering_pressed
can_sends.extend(
hondacan.create_lkas_hud(
self.packer, self.CAN.lkas, self.CP, hud_control, CC.latActive, steering_available, reduced_steering, alert_steer_required, CS.lkas_hud
)
)
if self.CP.openpilotLongitudinalControl:
# TODO: combining with create_acc_hud block above will change message order and will need replay logs regenerated
@@ -237,7 +464,14 @@ class CarController(CarControllerBase):
can_sends.append(hondacan.create_legacy_brake_command(self.packer, self.CAN.pt))
if self.CP.carFingerprint not in HONDA_BOSCH:
self.speed = pcm_speed
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
if self.CP.enableGasInterceptorDEPRECATED:
self.gas = gas_interceptor_command
else:
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
if self.frame > 0 and self.frame % 6000 == 0:
self.param_store.put_float("HondaGasFactorParams", self.bosch_gas_factor)
self.param_store.put_float("HondaWindFactorParams", self.bosch_wind_factor)
new_actuators = actuators.as_builder()
new_actuators.speed = self.speed
+62 -25
View File
@@ -3,11 +3,11 @@ from collections import defaultdict
from cereal import custom
from opendbc.can import CANDefine, CANParser
from opendbc.car import Bus, create_button_events, structs
from opendbc.car import Bus, DT_CTRL, create_button_events, structs
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.honda.hondacan import CanBus
from opendbc.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, HONDA_BOSCH_ALT_RADAR, HONDA_BOSCH_CANFD, \
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, \
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, HONDA_BOSCH_TJA_CONTROL, \
HondaFlags, CruiseButtons, CruiseSettings, GearShifter, CarControllerParams, HondaStarPilotFlags
from opendbc.car.interfaces import CarStateBase
@@ -54,13 +54,19 @@ class CarState(CarStateBase):
self.brake_switch_active = False
self.low_speed_alert = False
self.dynamic_v_cruise_units = self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_ALT_RADAR | HONDA_BOSCH_CANFD)
self.dynamic_v_cruise_units = self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_ALT_RADAR |
HONDA_BOSCH_TJA_CONTROL | HONDA_BOSCH_CANFD)
self.cruise_setting = 0
self.v_cruise_pcm_prev = 0
# When available we use cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] to populate vEgoCluster
# However, on cars without a digital speedometer this is not always present (HRV, FIT, CRV 2016, ILX and RDX)
self.dash_speed_seen = False
self.is_metric = False
self.v_cruise_factor = 1.
self.initial_accFault_cleared = False
self.initial_accFault_cleared_timer = int(10 / DT_CTRL)
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
cp = can_parsers[Bus.pt]
@@ -81,18 +87,19 @@ class CarState(CarStateBase):
self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"]
# used for car hud message
self.is_metric = not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
self.is_metric = self.CP.carFingerprint in (CAR.HONDA_ODYSSEY_TWN,) or not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
self.v_cruise_factor = CV.MPH_TO_MS if self.dynamic_v_cruise_units and not self.is_metric else CV.KPH_TO_MS
# ******************* parse out can *******************
# blend in transmission speed at low speed, since it has more low speed accuracy
# STANDSTILL->WHEELS_MOVING bit can be noisy around zero, so use XMISSION_SPEED
lowspeed_source = cp.vl["CAR_SPEED"]["CAR_SPEED"] if self.CP.carFingerprint == CAR.ACURA_INTEGRA else cp.vl["ENGINE_DATA"]["XMISSION_SPEED"]
v_wheel = sum([cp.vl["WHEEL_SPEEDS"][f"WHEEL_SPEED_{s}"] for s in ("FL", "FR", "RL", "RR")]) / 4.0 * CV.KPH_TO_MS
v_weight = float(np.interp(v_wheel, v_weight_bp, v_weight_v))
ret.vEgoRaw = (1. - v_weight) * cp.vl["ENGINE_DATA"]["XMISSION_SPEED"] * CV.KPH_TO_MS * self.CP.wheelSpeedFactor + v_weight * v_wheel
ret.vEgoRaw = (1. - v_weight) * lowspeed_source * CV.KPH_TO_MS * self.CP.wheelSpeedFactor + v_weight * v_wheel
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
ret.standstill = cp.vl["ENGINE_DATA"]["XMISSION_SPEED"] < 1e-5
ret.standstill = lowspeed_source < 1e-5
# doorOpen is true if we can find any door open, but signal locations vary, and we may only see the driver's door
# TODO: Test the eight Nidec cars without SCM signals for driver's door state, may be able to consolidate further
@@ -107,7 +114,8 @@ class CarState(CarStateBase):
ret.seatbeltUnlatched = bool(cp.vl["SEATBELT_STATUS"]["SEATBELT_DRIVER_LAMP"] or not cp.vl["SEATBELT_STATUS"]["SEATBELT_DRIVER_LATCHED"])
steer_status = self.steer_status_values[cp.vl["STEER_STATUS"]["STEER_STATUS"]]
ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TMP_FAULT")
ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TJA_LOW_SPEED_LOCKOUT",
"TMP_FAULT")
if self.CP.carFingerprint in HONDA_BOSCH_ALT_RADAR:
# TODO: See if this logic works for all other Honda
min_steer_speed = max(CarControllerParams.STEER_GLOBAL_MIN_SPEED, self.CP.minSteerSpeed)
@@ -117,7 +125,11 @@ class CarState(CarStateBase):
# LOW_SPEED_LOCKOUT is not worth a warning
# NO_TORQUE_ALERT_2 can be caused by bump or steering nudge from driver
# FIXME: the stock camera stops steering on NO_TORQUE_ALERT_1
ret.steerFaultTemporary = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2")
ret.steerFaultTemporary = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "TJA_LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2")
if self.CP.carFingerprint == CAR.ACURA_MDX_4G and steer_status == "TJA_LOW_SPEED_LOCKOUT":
ret.steerFaultPermanent = False
ret.steerFaultTemporary = False
# All Honda EPS cut off slightly above standstill, some much higher
# Don't alert in the near-standstill range, but alert for per-vehicle configured minimums above that
@@ -128,22 +140,23 @@ class CarState(CarStateBase):
self.low_speed_alert = False
ret.lowSpeedAlert = self.low_speed_alert
if self.CP.carFingerprint in HONDA_BOSCH_RADARLESS:
if self.CP.carFingerprint not in HONDA_BOSCH:
ret.carFaultedNonCritical = bool(cp_cam.vl["ACC_HUD"]["ACC_PROBLEM"] or cp_cam.vl["LKAS_HUD"]["LKAS_PROBLEM"])
elif self.CP.carFingerprint in HONDA_BOSCH_RADARLESS:
ret.accFaulted = bool(cp.vl["CRUISE_FAULT_STATUS"]["CRUISE_FAULT"])
else:
if self.CP.openpilotLongitudinalControl:
elif self.CP.openpilotLongitudinalControl:
if self.CP.carFingerprint in (HONDA_BOSCH_CANFD | HONDA_BOSCH_TJA_CONTROL) and (self.CP.flags & HondaFlags.BOSCH_ALT_BRAKE):
ret.accFaulted = bool(cp.vl["BRAKE_MODULE"]["CRUISE_FAULT"])
else:
ret.accFaulted = bool(cp.vl[self.brake_error_msg]["BRAKE_ERROR_1"] or cp.vl[self.brake_error_msg]["BRAKE_ERROR_2"])
# Log non-critical stock ACC/LKAS faults if Nidec (camera)
if self.CP.carFingerprint not in HONDA_BOSCH:
ret.carFaultedNonCritical = bool(cp_cam.vl["ACC_HUD"]["ACC_PROBLEM"] or cp_cam.vl["LKAS_HUD"]["LKAS_PROBLEM"])
ret.espDisabled = cp.vl["VSA_STATUS"]["ESP_DISABLED"] != 0
self.dash_speed_seen = self.dash_speed_seen or cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] > 1e-3
if self.dash_speed_seen:
conversion = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
ret.vEgoCluster = cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] * conversion
if self.CP.carFingerprint not in (CAR.HONDA_ODYSSEY_TWN,):
self.dash_speed_seen = self.dash_speed_seen or cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] > 1e-3
if self.dash_speed_seen:
conversion = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
ret.vEgoCluster = cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] * conversion
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE"]
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE_RATE"]
@@ -154,12 +167,16 @@ class CarState(CarStateBase):
ret.parkingBrake = bool(cp.vl[self.car_state_scm_msg]["PARKING_BRAKE_ON"])
if self.CP.transmissionType == TransmissionType.manual:
ret.gearShifter = GearShifter.reverse if bool(cp.vl["SCM_FEEDBACK"]["REVERSE_LIGHT"]) else GearShifter.drive
ret.gearShifter = GearShifter.reverse if bool(cp.vl[self.car_state_scm_msg]["REVERSE_LIGHT"]) else GearShifter.drive
else:
gear_position = self.shifter_values.get(cp.vl[self.gearbox_msg]["GEAR_SHIFTER"], None)
ret.gearShifter = self.parse_gear_shifter(gear_position)
ret.gasPressed = cp.vl["POWERTRAIN_DATA"]["PEDAL_GAS"] > 1e-5
if self.CP.enableGasInterceptorDEPRECATED:
gas = (cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2.
ret.gasPressed = gas > 492
else:
ret.gasPressed = cp.vl["POWERTRAIN_DATA"]["PEDAL_GAS"] > 1e-5
ret.steeringTorque = cp.vl["STEER_STATUS"]["STEER_TORQUE_SENSOR"]
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD.get(self.CP.carFingerprint, 1200)
@@ -184,22 +201,33 @@ class CarState(CarStateBase):
if self.CP.flags & HondaFlags.BOSCH_ALT_BRAKE:
ret.brakePressed = cp.vl["BRAKE_MODULE"]["BRAKE_PRESSED"] != 0
else:
powertrain_data = cp.vl["POWERTRAIN_DATA"]
# brake switch has shown some single time step noise, so only considered when
# switch is on for at least 2 consecutive CAN samples
# brake switch rises earlier than brake pressed but is never 1 when in park
brake_switch_vals = cp.vl_all["POWERTRAIN_DATA"]["BRAKE_SWITCH"]
if len(brake_switch_vals):
brake_switch = cp.vl["POWERTRAIN_DATA"]["BRAKE_SWITCH"] != 0
brake_switch = powertrain_data["BRAKE_SWITCH"] != 0
if len(brake_switch_vals) > 1:
self.brake_switch_prev = brake_switch_vals[-2] != 0
self.brake_switch_active = brake_switch and self.brake_switch_prev
self.brake_switch_prev = brake_switch
ret.brakePressed = (cp.vl["POWERTRAIN_DATA"]["BRAKE_PRESSED"] != 0) or self.brake_switch_active
ret.brakePressed = (powertrain_data["BRAKE_PRESSED"] != 0) or self.brake_switch_active
ret.brake = cp.vl["VSA_STATUS"]["USER_BRAKE"]
ret.cruiseState.enabled = cp.vl["POWERTRAIN_DATA"]["ACC_STATUS"] != 0
ret.cruiseState.available = bool(cp.vl[self.car_state_scm_msg]["MAIN_ON"])
if ret.accFaulted:
if self.CP.carFingerprint in HONDA_BOSCH and not self.initial_accFault_cleared:
ret.accFaulted = False
ret.cruiseState.available = False
elif self.initial_accFault_cleared_timer == 0:
self.initial_accFault_cleared = True
if self.initial_accFault_cleared_timer > 0:
self.initial_accFault_cleared_timer -= 1
# Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models
if self.CP.carFingerprint in (CAR.HONDA_PILOT, CAR.HONDA_RIDGELINE):
if ret.brake > 0.1:
@@ -218,7 +246,7 @@ class CarState(CarStateBase):
ret.stockFcw = cp_cam.vl["BRAKE_COMMAND"]["FCW"] != 0
self.acc_hud = cp_cam.vl["ACC_HUD"]
self.stock_brake = cp_cam.vl["BRAKE_COMMAND"]
if self.CP.carFingerprint in HONDA_BOSCH_RADARLESS:
if self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_CANFD):
self.lkas_hud = cp_cam.vl["LKAS_HUD"]
if self.CP.enableBsm:
@@ -235,12 +263,21 @@ class CarState(CarStateBase):
fp_ret = custom.StarPilotCarState.new_message()
fp_ret.dashboardSpeedLimit = calculate_speed_limit(self.CP, self.FPCP, cp, cp_cam)
if self.FPCP.flags & HondaStarPilotFlags.HAS_CAMERA_MESSAGES:
sign_bus = cp if (self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS - HONDA_BOSCH_CANFD)) else cp_cam
fp_ret.dashboardStopSign = 1 if sign_bus.vl["CAMERA_MESSAGES"]["ROAD_SIGN"] == 89 else 0
return ret, fp_ret
def get_can_parsers(self, CP):
pt_messages = [("GAS_SENSOR", 0)] if CP.enableGasInterceptorDEPRECATED else []
pt_parser = CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CanBus(CP).pt)
if CP.enableGasInterceptorDEPRECATED:
pt_parser.message_states[0x201].ignore_checksum = True
pt_parser.message_states[0x201].ignore_counter = True
parsers = {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).pt),
Bus.pt: pt_parser,
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).camera),
}
if CP.enableBsm:
+29 -1
View File
@@ -84,6 +84,7 @@ FW_VERSIONS = {
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TBX-H120\x00\x00',
b'39990-TVA,A150\x00\x00',
b'39990-TVA-A140\x00\x00',
b'39990-TVA-A150\x00\x00',
b'39990-TVA-A160\x00\x00',
@@ -142,6 +143,29 @@ FW_VERSIONS = {
b'38897-TWD-J020\x00\x00',
],
},
CAR.HONDA_CLARITY: {
(Ecu.shiftByWire, 0x18da0bf1, None): [
b'54008-TRW-A910\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-TRW-A010\x00\x00',
b'57114-TRW-A020\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TRW-A020\x00\x00',
b'39990-TRW,A020\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-TRW-A210\x00\x00',
b'77959-TRW-A220\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [
b'38897-TRW-A010\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-TRW-A110\x00\x00',
],
},
CAR.HONDA_CIVIC: {
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-5CG-A040\x00\x00',
@@ -163,6 +187,7 @@ FW_VERSIONS = {
b'57114-TEA-Q220\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TBA,A030\x00\x00',
b'39990-TBA-A030\x00\x00',
b'39990-TBG-A030\x00\x00',
b'39990-TEA-T020\x00\x00',
@@ -230,11 +255,13 @@ FW_VERSIONS = {
b'57114-TGL-G330\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TBA-C020\x00\x00',
b'39990-TBA-C120\x00\x00',
b'39990-TBA-C020\x00\x00',
b'39990-TEA-T330\x00\x00',
b'39990-TEA-T820\x00\x00',
b'39990-TEZ-T020\x00\x00',
b'39990-TGG,A020\x00\x00',
b'39990-TGG,A120\x00\x00',
b'39990-TGG-A020\x00\x00',
b'39990-TGG-A120\x00\x00',
b'39990-TGG-J510\x00\x00',
@@ -368,6 +395,7 @@ FW_VERSIONS = {
b'57114-TMC-Z050\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TLA,A040\x00\x00',
b'39990-TLA-A040\x00\x00',
b'39990-TLA-A110\x00\x00',
b'39990-TLA-A220\x00\x00',
+5 -4
View File
@@ -167,18 +167,19 @@ def create_acc_hud(packer, bus, CP, enabled, pcm_speed, pcm_accel, hud_control,
def create_lkas_hud(packer, bus, CP, hud_control, lat_active, steering_available, reduced_steering, alert_steer_required, lkas_hud):
commands = []
lanes_visible = bool(hud_control.lanesVisible or lat_active)
lkas_hud_values = {
'LKAS_READY': 1,
'LKAS_STATE_CHANGE': 1,
'STEERING_REQUIRED': alert_steer_required,
'SOLID_LANES': hud_control.lanesVisible,
'SOLID_LANES': lanes_visible,
'BEEP': 0,
}
if CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_CANFD):
lkas_hud_values['LANE_LINES'] = 3
lkas_hud_values['DASHED_LANES'] = hud_control.lanesVisible
lkas_hud_values['DASHED_LANES'] = lanes_visible
# car likely needs to see LKAS_PROBLEM fall within a specific time frame, so forward from camera
# TODO: needed for Bosch CAN FD?
@@ -192,8 +193,8 @@ def create_lkas_hud(packer, bus, CP, hud_control, lat_active, steering_available
# New HUD concept for selected Bosch cars, overwrites some of the above
# TODO: make global across all Honda if feedback is favorable
if CP.carFingerprint in HONDA_BOSCH_ALT_RADAR:
lkas_hud_values['DASHED_LANES'] = steering_available
lkas_hud_values['SOLID_LANES'] = lat_active
lkas_hud_values['DASHED_LANES'] = bool(steering_available or lanes_visible)
lkas_hud_values['SOLID_LANES'] = lanes_visible
lkas_hud_values['LKAS_PROBLEM'] = lat_active and reduced_steering
if CP.flags & HondaFlags.BOSCH_EXT_HUD and not CP.openpilotLongitudinalControl:
+139 -17
View File
@@ -23,6 +23,8 @@ class CarInterface(CarInterfaceBase):
def get_pid_accel_limits(CP, current_speed, cruise_speed):
if CP.carFingerprint in HONDA_BOSCH:
return CarControllerParams.BOSCH_ACCEL_MIN, CarControllerParams.BOSCH_ACCEL_MAX
elif CP.enableGasInterceptorDEPRECATED:
return CarControllerParams.NIDEC_ACCEL_MIN, CarControllerParams.NIDEC_ACCEL_MAX
else:
# NIDECs don't allow acceleration near cruise_speed,
# so limit limits of pid to prevent windup
@@ -46,15 +48,17 @@ class CarInterface(CarInterfaceBase):
# Disable the radar and let openpilot control longitudinal
# WARNING: THIS DISABLES AEB!
# If Bosch radarless, this blocks ACC messages from the camera
# TODO: get radar disable working on Bosch CANFD
ret.alphaLongitudinalAvailable = candidate not in HONDA_BOSCH_CANFD
ret.openpilotLongitudinalControl = alpha_long and (candidate not in HONDA_BOSCH_CANFD)
ret.alphaLongitudinalAvailable = True
ret.openpilotLongitudinalControl = alpha_long
ret.pcmCruise = not ret.openpilotLongitudinalControl
else:
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hondaNidec)]
ret.openpilotLongitudinalControl = True
ret.pcmCruise = True
ret.enableGasInterceptorDEPRECATED = 0x201 in fingerprint[CAN.pt]
if ret.enableGasInterceptorDEPRECATED:
ret.pcmCruise = False
if candidate == CAR.HONDA_CRV_5G:
ret.enableBsm = 0x12f8bfa7 in fingerprint[CAN.radar]
@@ -80,6 +84,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kf = 0.00006 # conservative feed-forward
ret.steerActuatorDelay = 0.1
ret.stoppingDecelRate = 0.3
if candidate in HONDA_BOSCH:
ret.longitudinalActuatorDelay = 0.5 # s
@@ -90,14 +95,32 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kiBP = [0., 5., 35.]
ret.longitudinalTuning.kiV = [1.2, 0.8, 0.5]
# Disable control if EPS mod detected
eps_modified = False
for fw in car_fw:
if fw.ecu == "eps" and b"," in fw.fwVersion:
ret.dashcamOnly = True
eps_modified = True
if eps_modified:
ret.flags |= HondaFlags.EPS_MODIFIED.value
if candidate == CAR.HONDA_CITY_7G:
ret.vEgoStopping = 2.0
ret.vEgoStarting = ret.vEgoStopping
ret.stoppingDecelRate = 0.3
if candidate == CAR.HONDA_CIVIC:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[1.1], [0.33]]
if eps_modified:
# stock request input values: 0x0000, 0x00DE, 0x014D, 0x01EF, 0x0290, 0x0377, 0x0454, 0x0610, 0x06EE
# stock request output values: 0x0000, 0x0917, 0x0DC5, 0x1017, 0x119F, 0x140B, 0x1680, 0x1680, 0x1680
# modified request output values: 0x0000, 0x0917, 0x0DC5, 0x1017, 0x119F, 0x140B, 0x1680, 0x2880, 0x3180
# stock filter output values: 0x009F, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108
# modified filter output values: 0x009F, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0400, 0x0480
# note: max request allowed is 4096, but request is capped at 3840 in firmware, so modifications result in 2x max
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 8000], [0, 2560, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.1]]
else:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[1.1], [0.33]]
elif candidate in (CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CIVIC_BOSCH_DIESEL):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
@@ -112,7 +135,17 @@ class CarInterface(CarInterfaceBase):
elif candidate == CAR.HONDA_ACCORD:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
if eps_modified:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.09]]
else:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
if ret.transmissionType == TransmissionType.manual:
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [-0.2, 2.0]
elif candidate == CAR.HONDA_ACCORD_11G:
ret.steerActuatorDelay = 0.22
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 5200], [0, 2560, 12747]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ACURA_ILX:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] # TODO: determine if there is a dead zone at the top end
@@ -124,8 +157,15 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = 1.025
elif candidate == CAR.HONDA_CRV_5G:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.64], [0.192]]
if eps_modified:
# stock request input values: 0x0000, 0x00DB, 0x01BB, 0x0296, 0x0377, 0x0454, 0x0532, 0x0610, 0x067F
# stock request output values: 0x0000, 0x0500, 0x0A15, 0x0E6D, 0x1100, 0x1200, 0x129A, 0x134D, 0x1400
# modified request output values: 0x0000, 0x0500, 0x0A15, 0x0E6D, 0x1100, 0x1200, 0x1ACD, 0x239A, 0x2800
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 10000], [0, 2560, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.21], [0.07]]
else:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.64], [0.192]]
ret.wheelSpeedFactor = 1.025
elif candidate == CAR.HONDA_CRV_HYBRID:
@@ -133,6 +173,13 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
ret.wheelSpeedFactor = 1.025
elif candidate == CAR.HONDA_CRV_6G:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 5100], [0, 5100]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if ret.flags & HondaFlags.HYBRID:
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [-0.3, 2.0]
elif candidate == CAR.HONDA_FIT:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.05]]
@@ -148,22 +195,52 @@ class CarInterface(CarInterfaceBase):
ret.wheelSpeedFactor = 1.025
else:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] # TODO: can probably use some tuning
# The 3G HR-V settles more cleanly in lead follow when planner delay
# better matches its stronger immediate longitudinal response.
ret.longitudinalActuatorDelay = 0.4
elif candidate == CAR.HONDA_CLARITY:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
ret.stopAccel = 0.0
elif candidate == CAR.ACURA_RDX:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 1000], [0, 1000]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate == CAR.ACURA_RDX_3G:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4095], [0, 4095]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.06]]
CarControllerParams.BOSCH_GAS_LOOKUP_V = [0, 2200]
elif candidate == CAR.ACURA_RDX_3G_MMR:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
CarControllerParams.BOSCH_GAS_LOOKUP_V = [0, 2000]
if not ret.openpilotLongitudinalControl:
ret.minSteerSpeed = 70. * CV.KPH_TO_MS
elif candidate == CAR.HONDA_ODYSSEY:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
elif candidate == CAR.HONDA_PILOT:
elif candidate == CAR.HONDA_ODYSSEY_TWN:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 32767], [0, 32767]]
elif candidate in (CAR.HONDA_PILOT, CAR.HONDA_PILOT_4G):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kpV = [[0, 10], [0.05, 0.5]]
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kiV = [[0, 10], [0.0125, 0.125]]
elif candidate == CAR.ACURA_MDX_4G:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 4209], [0, 2560, 9150]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ACURA_MDX_4G_MMR:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 4920], [0, 2560, 12000]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.HONDA_RIDGELINE:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
@@ -173,7 +250,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
elif candidate == CAR.HONDA_E:
elif candidate in (CAR.HONDA_E, CAR.HONDA_E_ADVANCE):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] # TODO: can probably use some tuning
@@ -189,19 +266,48 @@ class CarInterface(CarInterfaceBase):
# When using stock ACC, the radar intercepts and filters steering commands the EPS would otherwise accept
ret.minSteerSpeed = 70. * CV.KPH_TO_MS
elif candidate == CAR.ACURA_TLX_2G_MMR:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]]
ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kpV = [[0, 10], [0.05, 0.5]]
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kiV = [[0, 10], [0.0125, 0.125]]
elif candidate in (CAR.HONDA_FIT_4G,):
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ACURA_INTEGRA:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate == CAR.ACURA_ADX:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 5000], [0, 5000]]
ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kpV = [[0, 10], [0.05, 0.5]]
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kiV = [[0, 10], [0.0125, 0.125]]
elif candidate == CAR.HONDA_PASSPORT_4G:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 5120], [0, 2560, 12789]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
else:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
# These cars use alternate user brake msg (0x1BE)
if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, *HONDA_BOSCH_CANFD):
if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, CAR.ACURA_RDX_3G, CAR.ACURA_MDX_4G,
CAR.ACURA_ADX, *HONDA_BOSCH_CANFD):
ret.flags |= HondaFlags.BOSCH_ALT_BRAKE.value
if ret.flags & HondaFlags.BOSCH_ALT_BRAKE:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.ALT_BRAKE.value
if candidate in HONDA_NIDEC_ALT_SCM_MESSAGES:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.NIDEC_ALT.value
if ret.enableGasInterceptorDEPRECATED:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.GAS_INTERCEPTOR.value
if ret.openpilotLongitudinalControl and candidate in HONDA_BOSCH:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.BOSCH_LONG.value
if candidate in HONDA_BOSCH_RADARLESS:
@@ -212,8 +318,24 @@ class CarInterface(CarInterfaceBase):
# min speed to enable ACC. if car can do stop and go, then set enabling speed
# to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not
# conflict with PCM acc
ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.HONDA_CIVIC})
ret.minEnableSpeed = -1. if ret.autoResumeSng else 25.51 * CV.MPH_TO_MS
if candidate == CAR.HONDA_FIT_4G and not ret.openpilotLongitudinalControl:
ret.autoResumeSng = False
elif ret.transmissionType == TransmissionType.manual and not ret.openpilotLongitudinalControl:
ret.autoResumeSng = False
else:
ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.HONDA_CIVIC, CAR.HONDA_CLARITY}) or ret.enableGasInterceptorDEPRECATED
if ret.autoResumeSng:
ret.minEnableSpeed = -1.
elif candidate == CAR.HONDA_ODYSSEY_TWN:
ret.minEnableSpeed = 19. * CV.MPH_TO_MS
elif candidate == CAR.HONDA_FIT_4G:
ret.minEnableSpeed = 30. * CV.KPH_TO_MS
else:
ret.minEnableSpeed = 25.51 * CV.MPH_TO_MS
if candidate == CAR.HONDA_PILOT_4G:
CarControllerParams.BOSCH_GAS_LOOKUP_V = [0, 2200]
ret.steerLimitTimer = 0.8
ret.radarDelay = 0.1
@@ -1,12 +1,44 @@
import re
from types import SimpleNamespace
import pytest
from opendbc.car import structs
from opendbc.car.structs import CarParams
from opendbc.car import gen_empty_fingerprint
from opendbc.car.honda.interface import CarInterface
from opendbc.car.honda.carcontroller import (
CarController,
get_civic_bosch_modified_steering_pressed,
get_civic_bosch_modified_torque_lpf_tau,
get_honda_bosch_wind_brake_mps2,
update_honda_bosch_live_learning,
)
from opendbc.car.honda.hondacan import create_lkas_hud
from opendbc.car.honda.fingerprints import FW_VERSIONS
from opendbc.car.honda.values import HONDA_BOSCH, HONDA_BOSCH_TJA_CONTROL
from opendbc.car.honda.values import CAR, DBC, HONDA_BOSCH, HONDA_BOSCH_TJA_CONTROL, CarControllerParams, HondaFlags, HondaSafetyFlags, \
HondaStarPilotFlags
HONDA_FW_VERSION_RE = br"[A-Z0-9]{5}-[A-Z0-9]{3}(-|,)[A-Z0-9]{4}(\x00){2}$"
HONDA_FW_VERSION_RE = rb"[A-Z0-9]{5}-[A-Z0-9]{3}(-|,)[A-Z0-9]{4}(\x00){2}$"
def get_test_toggles() -> SimpleNamespace:
return SimpleNamespace(always_on_lateral_lkas=False, force_torque_controller=False, nnff=False, nnff_lite=False)
class TestHondaFingerprint:
def test_honda_lkas_hud_shows_lane_lines_when_lateral_only_is_active(self):
class FakePacker:
@staticmethod
def make_can_msg(name, bus, values):
return name, bus, values
CP = CarInterface.get_non_essential_params(CAR.HONDA_CIVIC_BOSCH)
hud_control = SimpleNamespace(lanesVisible=False)
cmds = create_lkas_hud(FakePacker(), 0, CP, hud_control, True, True, False, False, {})
assert cmds[0][2]["SOLID_LANES"] is True
def test_fw_version_format(self):
# Asserts all FW versions follow an expected format
for fw_by_ecu in FW_VERSIONS.values():
@@ -16,3 +48,230 @@ class TestHondaFingerprint:
def test_tja_bosch_only(self):
assert set(HONDA_BOSCH_TJA_CONTROL).issubset(set(HONDA_BOSCH)), "Nidec car found in TJA control list"
def test_modified_civic_torque_lpf_tau_reacts_to_sign_change(self):
assert get_civic_bosch_modified_torque_lpf_tau(0.7, -0.1, 25.0) == 0.10
assert get_civic_bosch_modified_torque_lpf_tau(0.02, -0.01, 8.0) == 0.28
assert get_civic_bosch_modified_torque_lpf_tau(0.02, 0.01, 12.0) == 0.28
assert get_civic_bosch_modified_torque_lpf_tau(0.02, 0.01, 20.0) == 0.20
assert get_civic_bosch_modified_torque_lpf_tau(0.02, 0.01, 25.0) == 0.16
assert get_civic_bosch_modified_torque_lpf_tau(0.30, 0.0, 12.0) == 0.16
assert get_civic_bosch_modified_torque_lpf_tau(0.30, 0.0, 20.0) == 0.13
def test_modified_civic_steering_pressed_filter_rejects_short_same_direction_spikes(self):
filter_s, pressed = get_civic_bosch_modified_steering_pressed(True, 1500.0, 0.8, 0.01, False)
assert not pressed
assert filter_s > 0.01
filter_s = 0.79
filter_s, pressed = get_civic_bosch_modified_steering_pressed(True, 1500.0, 0.8, filter_s, False)
assert not pressed
filter_s = 0.80
filter_s, pressed = get_civic_bosch_modified_steering_pressed(True, 1500.0, 0.8, filter_s, False)
assert pressed
def test_modified_civic_steering_pressed_filter_allows_opposing_driver_torque_quickly(self):
filter_s, pressed = get_civic_bosch_modified_steering_pressed(True, -1500.0, 0.8, 0.10, False)
assert pressed
def test_honda_bosch_wind_brake_curve_matches_reference_points(self):
assert get_honda_bosch_wind_brake_mps2(0.0) == pytest.approx(0.0)
assert get_honda_bosch_wind_brake_mps2(22.4) == pytest.approx(0.136)
assert get_honda_bosch_wind_brake_mps2(40.2) == pytest.approx(0.441)
def test_honda_bosch_live_learning_increases_factors_when_under_accelerating(self):
gas_factor, wind_factor, wind_factor_before_brake = update_honda_bosch_live_learning(
1.0,
1.0,
0.0,
desired_accel=1.0,
actual_accel=0.5,
gas_pedal_force=1.2,
wind_brake_mps2=0.136,
brake_pressed=False,
v_ego=22.4,
)
assert gas_factor == pytest.approx(1.012)
assert wind_factor == pytest.approx(1.000136)
assert wind_factor_before_brake == pytest.approx(wind_factor)
def test_honda_bosch_live_learning_restores_wind_factor_while_braking(self):
gas_factor, wind_factor, wind_factor_before_brake = update_honda_bosch_live_learning(
1.4,
1.1,
1.3,
desired_accel=-0.2,
actual_accel=0.0,
gas_pedal_force=-0.1,
wind_brake_mps2=0.136,
brake_pressed=True,
v_ego=22.4,
)
assert gas_factor == pytest.approx(1.4)
assert wind_factor == pytest.approx(1.3)
assert wind_factor_before_brake == pytest.approx(1.3)
def test_official_modified_eps_firmwares_restored(self):
assert b'39990-TVA,A150\x00\x00' in FW_VERSIONS[CAR.HONDA_ACCORD][(CarParams.Ecu.eps, 0x18DA30F1, None)]
assert b'39990-TBA,A030\x00\x00' in FW_VERSIONS[CAR.HONDA_CIVIC][(CarParams.Ecu.eps, 0x18DA30F1, None)]
assert b'39990-TBA-C120\x00\x00' in FW_VERSIONS[CAR.HONDA_CIVIC_BOSCH][(CarParams.Ecu.eps, 0x18DA30F1, None)]
assert b'39990-TGG,A020\x00\x00' in FW_VERSIONS[CAR.HONDA_CIVIC_BOSCH][(CarParams.Ecu.eps, 0x18DA30F1, None)]
assert b'39990-TLA,A040\x00\x00' in FW_VERSIONS[CAR.HONDA_CRV_5G][(CarParams.Ecu.eps, 0x18DA30F1, None)]
def test_modified_eps_candidates_keep_support_and_restore_upstream_tunes(self):
toggles = SimpleNamespace(force_torque_controller=False, nnff=False, nnff_lite=False)
civic_fw = [CarParams.CarFw(ecu=CarParams.Ecu.eps, fwVersion=b'39990-TBA,A030\x00\x00', address=0x18DA30F1, subAddress=0)]
civic_cp = CarInterface.get_params(CAR.HONDA_CIVIC, gen_empty_fingerprint(), civic_fw, False, False, False, toggles)
assert not civic_cp.dashcamOnly
assert civic_cp.flags & HondaFlags.EPS_MODIFIED
assert list(civic_cp.lateralParams.torqueBP) == [0, 2560, 8000]
assert list(civic_cp.lateralParams.torqueV) == [0, 2560, 3840]
assert list(civic_cp.lateralTuning.pid.kpV) == pytest.approx([0.3])
assert list(civic_cp.lateralTuning.pid.kiV) == pytest.approx([0.1])
civic_bosch_fw = [CarParams.CarFw(ecu=CarParams.Ecu.eps, fwVersion=b'39990-TGG,A020\x00\x00', address=0x18DA30F1, subAddress=0)]
civic_bosch_cp = CarInterface.get_params(CAR.HONDA_CIVIC_BOSCH, gen_empty_fingerprint(), civic_bosch_fw, False, False, False, toggles)
assert not civic_bosch_cp.dashcamOnly
assert civic_bosch_cp.flags & HondaFlags.EPS_MODIFIED
accord_fw = [CarParams.CarFw(ecu=CarParams.Ecu.eps, fwVersion=b'39990-TVA,A150\x00\x00', address=0x18DA30F1, subAddress=0)]
accord_cp = CarInterface.get_params(CAR.HONDA_ACCORD, gen_empty_fingerprint(), accord_fw, False, False, False, toggles)
assert not accord_cp.dashcamOnly
assert accord_cp.flags & HondaFlags.EPS_MODIFIED
assert list(accord_cp.lateralTuning.pid.kpV) == pytest.approx([0.3])
assert list(accord_cp.lateralTuning.pid.kiV) == pytest.approx([0.09])
crv_fw = [CarParams.CarFw(ecu=CarParams.Ecu.eps, fwVersion=b'39990-TLA,A040\x00\x00', address=0x18DA30F1, subAddress=0)]
crv_cp = CarInterface.get_params(CAR.HONDA_CRV_5G, gen_empty_fingerprint(), crv_fw, False, False, False, toggles)
assert not crv_cp.dashcamOnly
assert crv_cp.flags & HondaFlags.EPS_MODIFIED
assert list(crv_cp.lateralParams.torqueBP) == [0, 2560, 10000]
assert list(crv_cp.lateralParams.torqueV) == [0, 2560, 3840]
assert list(crv_cp.lateralTuning.pid.kpV) == pytest.approx([0.21])
assert list(crv_cp.lateralTuning.pid.kiV) == pytest.approx([0.07])
def test_modified_civic_bosch_keeps_official_support(self):
toggles = SimpleNamespace(force_torque_controller=False, nnff=False, nnff_lite=False)
car_fw = [CarParams.CarFw(ecu=CarParams.Ecu.eps, fwVersion=b'39990-TGG,A020\x00\x00', address=0x18DA30F1, subAddress=0)]
CP = CarInterface.get_params(CAR.HONDA_CIVIC_BOSCH, gen_empty_fingerprint(), car_fw, False, False, False, toggles)
assert not CP.dashcamOnly
assert CP.flags & HondaFlags.EPS_MODIFIED
assert CP.lateralTuning.which() == "torque"
def test_honda_clarity_supports_pid_and_torque_paths(self):
pid_toggles = SimpleNamespace(force_torque_controller=False, nnff=False, nnff_lite=False)
car_fw = [CarParams.CarFw(ecu=CarParams.Ecu.eps, fwVersion=b'39990-TRW,A020\x00\x00', address=0x18DA30F1, subAddress=0)]
pid_cp = CarInterface.get_params(CAR.HONDA_CLARITY, gen_empty_fingerprint(), car_fw, False, False, False, pid_toggles)
assert not pid_cp.dashcamOnly
assert pid_cp.flags & HondaFlags.EPS_MODIFIED
assert pid_cp.lateralTuning.which() == "pid"
assert list(pid_cp.lateralParams.torqueBP) == [0, 2560]
assert list(pid_cp.lateralParams.torqueV) == [0, 2560]
assert list(pid_cp.lateralTuning.pid.kpV) == pytest.approx([0.8])
assert list(pid_cp.lateralTuning.pid.kiV) == pytest.approx([0.24])
assert pid_cp.autoResumeSng
assert pid_cp.minEnableSpeed == pytest.approx(-1.0)
assert pid_cp.stopAccel == pytest.approx(0.0)
torque_toggles = SimpleNamespace(force_torque_controller=True, nnff=False, nnff_lite=False)
torque_cp = CarInterface.get_params(CAR.HONDA_CLARITY, gen_empty_fingerprint(), car_fw, False, False, False, torque_toggles)
assert torque_cp.lateralTuning.which() == "torque"
def test_canfd_bosch_alpha_long_is_available(self):
toggles = get_test_toggles()
CP = CarInterface.get_params(CAR.HONDA_PILOT_4G, gen_empty_fingerprint(), [], True, False, False, toggles)
assert CP.alphaLongitudinalAvailable
assert CP.openpilotLongitudinalControl
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_LONG
def test_nidec_pedal_detection_enables_interceptor_path(self):
toggles = get_test_toggles()
fingerprint = gen_empty_fingerprint()
fingerprint[0][0x201] = 6
CP = CarInterface.get_params(CAR.HONDA_CIVIC, fingerprint, [], False, False, False, toggles)
accel_limits = CarInterface.get_pid_accel_limits(CP, current_speed=5.0, cruise_speed=12.0)
assert CP.enableGasInterceptorDEPRECATED
assert not CP.pcmCruise
assert accel_limits == (CarControllerParams.NIDEC_ACCEL_MIN, CarControllerParams.NIDEC_ACCEL_MAX)
def test_honda_camera_message_flag_uses_fingerprint_detection(self):
toggles = get_test_toggles()
fingerprint = gen_empty_fingerprint()
fingerprint[0][0x35E] = 8
CP = CarInterface.get_params(CAR.HONDA_ACCORD, fingerprint, [], True, False, False, toggles)
FPCP = CarInterface.get_starpilot_params(CAR.HONDA_ACCORD, fingerprint, [], CP, toggles)
assert FPCP.flags & HondaStarPilotFlags.HAS_CAMERA_MESSAGES
def test_honda_live_learning_params_reload(self, monkeypatch):
toggles = get_test_toggles()
class FakeParams:
def get_float(self, key, block=False, return_default=False, default=0.0):
if key == "HondaGasFactorParams":
return 1.25
if key == "HondaWindFactorParams":
return 0.85
return default
monkeypatch.setattr("opendbc.car.honda.carcontroller.Params", lambda: FakeParams())
CP = CarInterface.get_params(CAR.HONDA_ACCORD, gen_empty_fingerprint(), [], True, False, False, toggles)
controller = CarController(DBC[CP.carFingerprint], CP)
assert controller.bosch_gas_factor == pytest.approx(1.25)
assert controller.bosch_wind_factor == pytest.approx(0.85)
def test_honda_bosch_controller_does_not_deepen_planner_braking(self, monkeypatch):
toggles = get_test_toggles()
CP = CarInterface.get_params(CAR.HONDA_HRV_3G, gen_empty_fingerprint(), [], True, False, False, toggles)
controller = CarController(DBC[CP.carFingerprint], CP)
monkeypatch.setattr("opendbc.car.honda.carcontroller.hondacan.create_steering_control", lambda *args, **kwargs: (0, []))
monkeypatch.setattr("opendbc.car.honda.carcontroller.hondacan.create_acc_commands", lambda *args, **kwargs: [])
CC = structs.CarControl.new_message()
CC.enabled = True
CC.longActive = True
CC.latActive = False
CC.cruiseControl.cancel = False
CC.cruiseControl.resume = False
CC.hudControl.speedVisible = False
CC.hudControl.setSpeed = 0.0
CC.hudControl.visualAlert = structs.CarControl.HUDControl.VisualAlert.none
CC.actuators.accel = -0.3
CC.actuators.torque = 0.0
CC.actuators.longControlState = structs.CarControl.Actuators.LongControlState.pid
controller.frame = 2
CS = SimpleNamespace(
out=SimpleNamespace(vEgo=25.0, aEgo=1.5, steeringPressed=False, gasPressed=False, brakePressed=False),
v_cruise_factor=1.0,
)
new_actuators, _ = controller.update(CC.as_reader(), CS, 0, toggles)
assert new_actuators.accel == pytest.approx(-0.3)
def test_honda_hrv_3g_uses_matched_longitudinal_delay(self):
toggles = get_test_toggles()
hrv3g_cp = CarInterface.get_params(CAR.HONDA_HRV_3G, gen_empty_fingerprint(), [], True, False, False, toggles)
accord_cp = CarInterface.get_params(CAR.HONDA_ACCORD, gen_empty_fingerprint(), [], True, False, False, toggles)
assert hrv3g_cp.longitudinalActuatorDelay == pytest.approx(0.4)
assert accord_cp.longitudinalActuatorDelay == pytest.approx(0.5)
+114 -2
View File
@@ -56,6 +56,7 @@ class HondaSafetyFlags(IntFlag):
NIDEC_ALT = 4
RADARLESS = 8
BOSCH_CANFD = 16
GAS_INTERCEPTOR = 32
class HondaFlags(IntFlag):
@@ -79,6 +80,7 @@ class HondaFlags(IntFlag):
ALLOW_MANUAL_TRANS = 1024
HYBRID = 2048
BOSCH_TJA_CONTROL = 4096
EPS_MODIFIED = 8192
# Car button codes
@@ -246,6 +248,12 @@ class CAR(Platforms):
{Bus.pt: 'acura_rdx_2020_can_generated'},
flags=HondaFlags.BOSCH_ALT_BRAKE,
)
ACURA_RDX_3G_MMR = HondaBoschPlatformConfig(
[HondaCarDocs("Acura RDX 2022-26", "All", min_steer_speed=70. * CV.KPH_TO_MS)],
CarSpecs(mass=4079 * CV.LB_TO_KG, wheelbase=2.75, centerToFrontRatio=0.41, steerRatio=16.2),
{Bus.pt: 'acura_rdx_2020_can_generated'},
flags=HondaFlags.BOSCH_ALT_BRAKE | HondaFlags.BOSCH_ALT_RADAR,
)
HONDA_INSIGHT = HondaBoschPlatformConfig(
[HondaCarDocs("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
CarSpecs(mass=2987 * CV.LB_TO_KG, wheelbase=2.7, steerRatio=15.0, centerToFrontRatio=0.39, tireStiffnessFactor=0.82), # as spec
@@ -256,6 +264,11 @@ class CAR(Platforms):
CarSpecs(mass=3338.8 * CV.LB_TO_KG, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
{Bus.pt: 'acura_rdx_2020_can_generated'},
)
HONDA_E_ADVANCE = HondaBoschPlatformConfig(
[], # don't show in docs, base trim already in docs
CarSpecs(mass=1527, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
{Bus.pt: 'honda_e_advance_2020_can_generated'},
)
HONDA_PILOT_4G = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Honda Pilot 2023-25", "All")],
CarSpecs(mass=4660 * CV.LB_TO_KG, wheelbase=2.89, centerToFrontRatio=0.442, steerRatio=17.5),
@@ -264,6 +277,12 @@ class CAR(Platforms):
[HondaCarDocs("Honda Passport 2026", "All")],
CarSpecs(mass=4620 * CV.LB_TO_KG, wheelbase=2.89, centerToFrontRatio=0.442, steerRatio=18.5),
)
ACURA_MDX_4G = HondaBoschPlatformConfig(
[HondaCarDocs("Acura MDX 2022-24", "All", min_steer_speed=70. * CV.KPH_TO_MS)],
CarSpecs(mass=4788 * CV.LB_TO_KG, wheelbase=2.89, steerRatio=15.8, centerToFrontRatio=0.428),
{Bus.pt: 'honda_common_canfd_generated'},
flags=HondaFlags.BOSCH_ALT_RADAR | HondaFlags.BOSCH_TJA_CONTROL,
)
# mid-model refresh
ACURA_MDX_4G_MMR = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Acura MDX 2025", "All except Type S")],
@@ -281,6 +300,34 @@ class CAR(Platforms):
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
flags=HondaFlags.BOSCH_ALT_RADAR,
)
ACURA_TLX_2G_MMR = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Acura TLX 2024-25", "All")],
CarSpecs(mass=3990 * CV.LB_TO_KG, wheelbase=2.87, centerToFrontRatio=0.43, steerRatio=13.7),
)
HONDA_FIT_4G = HondaBoschPlatformConfig(
[
HondaCarDocs("Honda Fit (Taiwan) 2021", "All"),
HondaCarDocs("Honda Fit (Taiwan) 2024-25", "All"),
],
CarSpecs(mass=1229, wheelbase=2.53, steerRatio=19.7, centerToFrontRatio=0.39, minSteerSpeed=23. * CV.KPH_TO_MS),
{Bus.pt: 'honda_bosch_radarless_generated'},
flags=HondaFlags.BOSCH_RADARLESS,
)
ACURA_INTEGRA = HondaBoschPlatformConfig(
[
HondaCarDocs("Acura Integra 2023-26", "All"),
HondaCarDocs("Honda Prelude 2026", "All"),
],
CarSpecs(mass=3338.8 * CV.LB_TO_KG, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
{Bus.pt: 'honda_bosch_radarless_generated'},
flags=HondaFlags.BOSCH_RADARLESS,
)
ACURA_ADX = HondaBoschPlatformConfig(
[HondaCarDocs("Acura ADX 2025-26", "All")],
CarSpecs(mass=3578 * CV.LB_TO_KG, wheelbase=2.65, steerRatio=16.6, centerToFrontRatio=0.43),
{Bus.pt: 'honda_bosch_radarless_generated'},
flags=HondaFlags.BOSCH_RADARLESS,
)
# Nidec Cars
ACURA_ILX = HondaNidecPlatformConfig(
@@ -304,6 +351,12 @@ class CAR(Platforms):
radar_dbc_dict('honda_crv_touring_2016_can_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES | HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_CRV_SA = HondaNidecPlatformConfig(
[], # South Africa version of CRV Touring, don't show in docs
HONDA_CRV.specs,
radar_dbc_dict('acura_rdx_2018_can_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES | HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_FIT = HondaNidecPlatformConfig(
[HondaCarDocs("Honda Fit 2018-20", min_steer_speed=12. * CV.MPH_TO_MS)],
CarSpecs(mass=2644 * CV.LB_TO_KG, wheelbase=2.53, steerRatio=13.06, centerToFrontRatio=0.39, tireStiffnessFactor=0.75),
@@ -322,12 +375,27 @@ class CAR(Platforms):
radar_dbc_dict('acura_ilx_2016_can_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES,
)
HONDA_CLARITY = HondaNidecPlatformConfig(
[HondaCarDocs("Honda Clarity 2018-21", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
CarSpecs(mass=1838, wheelbase=2.75, centerToFrontRatio=0.4, steerRatio=16.5),
radar_dbc_dict('honda_clarity_hybrid_2018_can_generated'),
flags=HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_ODYSSEY = HondaNidecPlatformConfig(
[HondaCarDocs("Honda Odyssey 2018-20")],
CarSpecs(mass=1900, wheelbase=3.0, steerRatio=14.35, centerToFrontRatio=0.41, tireStiffnessFactor=0.82),
radar_dbc_dict('honda_odyssey_exl_2018_generated'),
flags=HondaFlags.NIDEC_ALT_PCM_ACCEL | HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_ODYSSEY_TWN = HondaNidecPlatformConfig(
[
HondaCarDocs("Honda Odyssey (Taiwan) 2018-19"),
HondaCarDocs("Honda Odyssey (Singapore) 2021"),
],
CarSpecs(mass=1865, wheelbase=2.9, steerRatio=14.35, centerToFrontRatio=0.44, tireStiffnessFactor=0.82),
radar_dbc_dict('honda_odyssey_twn_2018_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES,
)
ACURA_RDX = HondaNidecPlatformConfig(
[HondaCarDocs("Acura RDX 2016-18", "AcuraWatch Plus or Advance Package", min_steer_speed=12. * CV.MPH_TO_MS)],
CarSpecs(mass=3925 * CV.LB_TO_KG, wheelbase=2.68, steerRatio=15.0, centerToFrontRatio=0.38, tireStiffnessFactor=0.444), # as spec
@@ -355,6 +423,43 @@ class CAR(Platforms):
radar_dbc_dict('honda_civic_touring_2016_can_generated'),
flags=HondaFlags.HAS_ALL_DOOR_STATES
)
HONDA_ACCORD_9G = HondaNidecPlatformConfig(
[
HondaCarDocs("Honda Accord 2016-17"),
HondaCarDocs("Honda Accord Hybrid 2017", "All"),
],
CarSpecs(mass=3343 * CV.LB_TO_KG, wheelbase=2.78, steerRatio=17.5, centerToFrontRatio=0.37),
radar_dbc_dict('honda_accord_2017_can_ext_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES | HondaFlags.HAS_ALL_DOOR_STATES,
)
ACURA_MDX_3G = HondaNidecPlatformConfig(
[
HondaCarDocs("Acura MDX 2014-16", "Advance Package"),
HondaCarDocs("Acura MDX 2017-19", "All"),
HondaCarDocs("Acura MDX Hybrid 2017-19", "All"),
],
CarSpecs(mass=4215 * CV.LB_TO_KG, wheelbase=2.82, steerRatio=16.8, centerToFrontRatio=0.428),
radar_dbc_dict('acura_mdx_2017_can_ext_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES,
)
ACURA_MDX_3G_MMR = HondaNidecPlatformConfig(
[
HondaCarDocs("Acura MDX 2020", "All"),
HondaCarDocs("Acura MDX Hybrid 2020", "All"),
],
CarSpecs(mass=4215 * CV.LB_TO_KG, wheelbase=2.82, steerRatio=16.8, centerToFrontRatio=0.428),
radar_dbc_dict('acura_ilx_2016_can_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES,
)
ACURA_TLX_1G = HondaNidecPlatformConfig(
[
HondaCarDocs("Acura TLX 2015-17", "Advance Package"),
HondaCarDocs("Acura TLX 2018-20", "All"),
],
CarSpecs(mass=3680 * CV.LB_TO_KG, wheelbase=2.78, steerRatio=17.0, centerToFrontRatio=0.40, tireStiffnessFactor=0.18),
radar_dbc_dict('acura_mdx_2017_can_ext_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES | HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_NIDEC_ALT_PCM_ACCEL = CAR.with_flags(HondaFlags.NIDEC_ALT_PCM_ACCEL)
@@ -389,6 +494,11 @@ STEER_THRESHOLD = {
CAR.HONDA_CRV_6G: 600,
CAR.HONDA_CITY_7G: 600,
CAR.HONDA_NBOX_2G: 600,
CAR.HONDA_ODYSSEY_5G_MMR: 600,
CAR.HONDA_ACCORD_9G: 30,
CAR.ACURA_MDX_3G: 30,
CAR.ACURA_MDX_3G_MMR: 30,
CAR.ACURA_TLX_1G: 30,
}
@@ -433,9 +543,11 @@ FW_QUERY_CONFIG = FwQueryConfig(
# Note that we still attempt to match with them when they are present
# This is or'd with (ALL_ECUS - ESSENTIAL_ECUS) from fw_versions.py
non_essential_ecus={
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_E, *HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_E, CAR.HONDA_E_ADVANCE, CAR.ACURA_MDX_4G, CAR.HONDA_CRV_SA,
CAR.ACURA_MDX_3G, CAR.HONDA_ACCORD_9G, *HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
Ecu.vsa: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC, CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CRV_5G, CAR.HONDA_CRV_HYBRID,
CAR.HONDA_E, CAR.HONDA_INSIGHT, CAR.HONDA_NBOX_2G, *HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
CAR.HONDA_E, CAR.HONDA_E_ADVANCE, CAR.HONDA_INSIGHT, CAR.HONDA_NBOX_2G, CAR.ACURA_MDX_4G, CAR.HONDA_ACCORD_9G,
*HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
},
extra_ecus=[
(Ecu.combinationMeter, 0x18da60f1, None),

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