Compare commits

..

278 Commits

Author SHA1 Message Date
Jason Wen 1d77743cf6 Merge branch 'stats_sp' into hkg-angle-steering-2025-stats
# Conflicts:
#	opendbc_repo
2025-11-03 17:27:42 -05:00
Jason Wen 17f3bc475b handle them all 2025-11-03 17:23:16 -05:00
Jason Wen 749d56ef7d staticmethod 2025-11-03 17:17:36 -05:00
Jason Wen 4345f01d17 slightly more 2025-11-03 17:16:27 -05:00
Jason Wen bd4836df14 init 2025-11-03 14:39:53 -05:00
Jason Wen 1eee21622a init 2025-11-03 14:39:28 -05:00
DevTekVE 617805f924 cleanup 2025-11-03 19:55:08 +01:00
DevTekVE 48885b2848 refactor(statsd): update typings and remove unused NoReturn annotation
- Removed unnecessary `NoReturn` typing for `stats_main` to simplify function definition.
- Adjusted `get_influxdb_line_raw` to refine typing for `value` parameter.
2025-11-03 19:51:29 +01:00
DevTekVE 962b29573e refactor(statsd): adjust imports and minor code formatting updates
- Updated `Ratekeeper` import path for consistency with the `openpilot` module structure.
- Fixed minor formatting for improved readability.
2025-11-03 19:40:18 +01:00
DevTekVE 33b7513c8d refactor(statsd): improve sp_stats error handling and param processing
- Enhanced exception handling for `params.get` to prevent crashes.
- Added support for nested dict values to be included in stats.
2025-11-03 19:33:05 +01:00
DevTekVE c7c2dbb4f2 feat(statsd): add raw metric type and SunnyPilot-specific stats collection
- Introduced `METRIC_TYPE.RAW` for base64-encoded raw data metrics.
- Added `sp_stats` thread to export SunnyPilot params as raw metrics.
- Enhanced telemetry handling with decoding and serialization updates.
2025-11-03 18:42:47 +01:00
DevTekVE de8cec269a Dont complain 2025-11-03 15:13:54 +01:00
DevTekVE b9fd55d17b refactor(statsd): add intercept parameter to StatLogSP for configurable logging
- Introduced optional `intercept` parameter to `StatLogSP` to manage `comma_statlog` initialization.
- Updated usage in `sunnylink` to disable interception where unnecessary.
2025-11-03 12:21:03 +01:00
DevTekVE c0f2f232d0 fix 2025-11-03 12:15:17 +01:00
DevTekVE fd468531fa refactor(statsd): enhance and unify StatLogSP implementation
- Replaced custom `StatLogSP` in sunnylink with centralized implementation from `system.statsd`.
- Ensures consistent logic for StatLogSP handling across modules.
2025-11-03 12:12:33 +01:00
DevTekVE 4720e7b11a update statsd_sp process configuration for enhanced readiness logic
- Modified `statsd_sp` initialization to include `always_run` alongside `sunnylink_ready_shim`.
- Ensures robust process activation conditions.
2025-11-03 10:48:12 +01:00
DevTekVE 63e4e742e3 statsd: fix formatting issue in telemetry string generation
- Corrected missing comma between `sunnylink_dongle_id` and `comma_dongle_id`.
2025-11-03 10:08:38 +01:00
DevTekVE 12bed4d731 sunnylink: re-enable and refine stat_handler for telemetry processing
- Reactivated `stat_handler` thread with improved path handling.
- Made `stat_handler` more flexible by allowing directory injection.
2025-11-03 10:04:16 +01:00
DevTekVE a900462ef1 sunnylink: add statsd process and related telemetry logging infrastructure
- Introduced `statsd_sp` process for handling Sunnylink-specific stats.
- Enhanced metrics logging with improved directory structure and data handling.
2025-11-03 10:01:01 +01:00
Matt Purnell 071147baaf docs: Update README installation branches and discord links (#1453)
* Use sunnypilot CARS.md, update number of supported cars, add comma

* Update device reference

* Update discord links to forum links

* Update references to -c3-new branches and release

* Update broken link to branches table

* Update README.md

---------

Co-authored-by: DevTekVE <devtekve@gmail.com>
2025-11-03 06:52:17 +01:00
DevTekVE 18af4d6ad6 ui: Fix spacing in sunnylink panel (#1450)
Fix spacing
2025-11-02 20:26:17 +01:00
DevTekVE b81d5bca3c ui: update discord references and add forum widget (#1440)
* sunnylink: introduce community popup with QR code embedding

- Added `SunnylinkCommunityPopup` widget to promote the sunnypilot Community Forum.
- Integrated a QR code generator and display for quick access.
- Updated `WiFiPromptWidget` to include a "Learn More" button triggering the community popup.

* sunnylink: adjust community popup styling for better layout

- Reduced font size of description text slightly for consistency.
- Decreased QR code dimensions to improve visual balance.

* Making more space out of thin air

* sunnylink: update community references to use forum links

- Replaced Discord links with Community Forum URLs for better alignment.
- Improved clarity in sponsorship instructions.
2025-11-02 06:50:41 +01:00
Amy Jeanes 682d738ffa Tesla: Coop Steering (#1283)
* Tesla: Coop Steering

* bump

* bump

* sync with opendbc/master

* resolve comment

* add oscillation warning and add confirmation

* styling desc

* beta

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-11-01 22:47:30 -04:00
DevTekVE f60c2b6a83 sunnylink: update uploader button logic to support novice tier and above (#1438)
* sunnylink: update uploader button logic to support novice tier and above

- Adjusted the enable condition to include SponsorTier::Novice and above.

* sunnylink: improve uploader button visibility and accessibility logic

- Made uploader button conditionally visible based on user tier and settings.
- Clarified button label to specify testing purposes only.
2025-11-01 12:14:57 +01:00
DevTekVE f833819143 ci: update trigger for prebuilt (#1439)
Updated workflow `if` conditions to use `vars.PREBUILT_PR_LABEL`.
2025-10-31 17:54:39 +01:00
THERoenPR 707e2aedae controlsd: add CP_SP to get_pid_accel_limits (#1410)
* Add CP_SP to get_pid_accel_limits() call in controlsd

Match input parameters of CP_SP commit

* bump

* bump

---------

Co-authored-by: roenthomas <43324106+roenthomas@users.noreply.github.com>
Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-10-28 22:13:39 -04:00
DevTekVE 55147d8a55 ci: use environment variable for PR label in query (#1436)
* ci: use environment variable for PR label in query

- Replaced static `PR_LABEL` references with `${{ env.PR_LABEL }}` for consistency.
- Ensures flexibility and reduces hardcoded values in the workflow.

* does this work better?

* fuck this

* aight
2025-10-28 18:58:04 +01:00
DevTekVE de7acc5466 ci: integrate Discourse notifications and refactor notification logic (#1435)
* ci: integrate Discourse notifications and refactor notification logic

- Replaced Discord webhook notifications with Discourse topic updates.
- Introduced reusable `post-to-discourse` composite action.
- Added `test-discourse.yaml` workflow for debugging and verification.

* ci: adjust notification dependencies and prepare_strategy reference

- Updated `notify` step to depend on `prepare_strategy` instead of `build`.
- Adjusted variable references to use `prepare_strategy` outputs.

* Forcing debug

* ci: update environment variable references and add commit information

- Switched `PUBLIC_REPO_URL` source to environment variable for consistency.
- Added commit SHA variables to enhance template generation logic.

* more tweaks!

* more tweaks!

* bad bot lmao

* Test?

* i mean....

* i mean....

* getting there

* testing the if

* testing the if

* ci: re-enable notify steps for prebuilt workflow

- Uncommented `build` and `publish` dependencies.
- Restored conditional logic to trigger only for relevant events.

* ci: enhance Discourse action to support new topic creation

- Added support for creating new topics with `category-id` and `title`.
- Improved input validation and response handling for flexibility.

* ci: improve conditions for prebuilt workflow notifications

- Refined `if` clause to ensure branches in `DEV_FEEDBACK_NOTIFICATION_BRANCHES` are targeted.
- Adjusted logic for accurate topic ID mapping in Discourse integration.

* forgot to rename
2025-10-28 16:01:21 +01:00
Nayan e4aada10a4 Bug: Model UI Crash Fix (#1431)
Model UI Crash Fix
2025-10-26 21:43:30 -04:00
James Vecellio-Grant b460d5804c LiveLocationKalman: skip tests on unsupported msgq (#1407)
* locationd llk: skip tests on unsupported msgq

* Update sunnypilot/selfdrive/locationd/tests/test_locationd.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-25 23:47:37 -04:00
James Vecellio-Grant eecb8e5c19 models: bump model json to v8 (#1430)
models: bump model json to v8 post release

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-10-25 22:55:26 -04:00
Jason Wen 1a4ea66987 version: bump to 2025.002.000 2025-10-25 22:45:17 -04:00
Jason Wen c1e15e5544 changelog: add new contributor entry 2025-10-25 01:00:46 -04:00
MuskratGG 3a45fff1b9 ui: openpilot Longitudinal Control → sunnypilot Longitudinal Control (#1422)
* Update developer_panel.cc

Changed mentions of "openpilot Longitudinal Control" to "sunnypilot Longitudinal Control" to align with other UI elements pointing users towards enabling "sunnypilot Longitudinal Control"

* Update warning message for longitudinal control

* more

* a bit more

* slightly more

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-10-24 21:09:01 -04:00
github-actions[bot] ae9bd39883 [bot] Update Python packages (#1428)
Update Python packages

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-10-24 17:04:27 -04:00
Jason Wen 43e7d87176 version: more release branches (#1427) 2025-10-24 15:34:50 -04:00
github-actions[bot] 432c6050ed [bot] Update Python packages (#1338)
Update Python packages

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-10-24 15:28:08 -04:00
Jason Wen 4e3b1f1f6b interface: add is_release flag to get_params_sp (#1426)
* interface: add `is_release` flag to `get_params_sp`

* split and rename

* debump
2025-10-24 14:56:24 -04:00
Jason Wen 5d47ffdb8a Speed Limit Assist: Disable for Rivian (#1421)
* Speed Limit Assist: Disable for Tesla in release

* add test

* unused

* use constant

* eh

* flip

* universal it

* check release state and align in tests

* use this

* eh

* update changelog

* Speed Limit Assist: Disable for Rivian

* desc

* changelog
2025-10-23 03:48:04 -04:00
Jason Wen 1c89e2b885 Speed Limit Assist: Disable for Tesla in release (#1418)
* Speed Limit Assist: Disable for Tesla in release

* add test

* unused

* use constant

* eh

* flip

* universal it

* check release state and align in tests

* use this

* eh

* update changelog
2025-10-23 03:26:32 -04:00
Jason Wen c552567ada ui: increase minimum button width in ButtonParamControlSP (#1419) 2025-10-23 01:08:19 -04:00
Jason Wen 7097e69aa3 Speed Limit Assist: generalize availability helper (#1416)
* init infra to disable sla in certain conditions

* a bit more

* in another PR

* in another PR

* since when?

* start here
2025-10-22 11:17:02 -04:00
Jason Wen 657ff0f8ec ui: refine ICBM description handling and availability logic (#1414)
* ui: refine ICBM description handling and availability logic

* car -> platform

* retain
2025-10-22 00:09:10 -04:00
Jason Wen 641af6d7e7 changelog: more new contributors! (#1413) 2025-10-21 17:55:27 -04:00
Jason Wen f57de1c5b2 version: a new beginning (#1411)
* version: a new beginning

* changelog

* singular

* show ours

* actual

* readjust

* updated

* more

* official spelling

* more

* sync

* fix

* send it

* push

* we never had this lol

* syncs
2025-10-21 17:12:57 -04:00
Jason Wen cb5d120136 FCA: update minEnableSpeed and LKAS control logic (#1386)
* FCA: update minEnableSpeed and LKAS control logic

* bump
2025-10-21 14:22:37 -04:00
Jason Wen c85b6a0d1c branches: track sunnypilot release branches separately (#1409)
* branches: track sunnypilot release branches separately

* more remotes for legacy support

* bruh

* revert
2025-10-21 00:53:16 -04:00
DevTekVE 0e2313dc31 Merge branch 'master' into hkg-angle-steering-2025 2025-10-18 11:14:45 +02:00
Jason Wen 025a930ce8 ui: update longitudinal-related settings handling (#1401)
* ui: update ICBM-related settings handling

* oops

* oops

* single location

* some more

* fix cruise toggles

* always init true

* check this

* nah

* should be this
2025-10-18 04:04:48 -04:00
Jason Wen 79ea7db103 Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into hkg-angle-steering-2025 2025-10-17 23:42:01 -04:00
Jason Wen 523c92c6fe Speed Limit Assist: lower preActive timer for Non PCM Longitudinal and ICBM cars (#1403)
5 seconds preActive for non pcm long now
2025-10-17 23:41:33 -04:00
Jason Wen 72282f2d2e Speed Limit Assist: update events handling (#1400)
* Speed Limit Assist: update active event handling

* ok no more for non pcm long it was annoying

* 5 seconds preActive for non pcm long now

* Revert "5 seconds preActive for non pcm long now"

This reverts commit dfcc601035.

* dynamic alert size

* do the same here

* lint
2025-10-17 23:30:06 -04:00
Jason Wen 2825c00fcc controlsd: update lateral delay param in a separate thread (#1402) 2025-10-17 22:53:31 -04:00
Jason Wen f9ae9192fa Merge branch 'ui-icbm-universal' into hkg-angle-steering-2025 2025-10-17 21:55:00 -04:00
Jason Wen 7ec23006c6 check this 2025-10-17 21:54:44 -04:00
Jason Wen 2be9447a6c Merge branch 'ui-icbm-universal' into hkg-angle-steering-2025 2025-10-17 21:19:09 -04:00
Jason Wen cfd926778e always init true 2025-10-17 21:19:03 -04:00
Jason Wen a97a67e3d0 need 2025-10-17 21:17:31 -04:00
Jason Wen 518b6de08d Merge branch 'ui-icbm-universal' into hkg-angle-steering-2025 2025-10-17 21:15:59 -04:00
Jason Wen 6933e3bcdb fix cruise toggles 2025-10-17 21:15:43 -04:00
Jason Wen 05e0ca8bee some more 2025-10-17 20:46:36 -04:00
Jason Wen 410614fcf3 single location 2025-10-17 20:26:18 -04:00
Jason Wen e2bc0996ef Merge branch 'ui-icbm-universal' into hkg-angle-steering-2025 2025-10-17 12:21:47 -04:00
Jason Wen 1be0c20cf5 oops 2025-10-17 12:21:37 -04:00
Jason Wen 839143b9ed oops 2025-10-17 12:20:23 -04:00
Jason Wen bce86637ae Merge branch 'ui-icbm-universal' into hkg-angle-steering-2025 2025-10-17 12:15:23 -04:00
Jason Wen b833d3ee89 ui: update ICBM-related settings handling 2025-10-17 12:14:44 -04:00
Jason Wen e0441dfb4b Merge branch 'sla-event' into hkg-angle-steering-2025 2025-10-17 11:58:42 -04:00
Jason Wen 62ec40bba6 Speed Limit Assist: update active event handling 2025-10-17 11:58:19 -04:00
Jason Wen 15c6d38028 bump 2025-10-16 17:05:58 -04:00
Jason Wen 56eb9f555c Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into hkg-angle-steering-2025
# Conflicts:
#	sunnypilot/selfdrive/controls/lib/e2e_alerts_helper.py
2025-10-16 01:12:10 -04:00
Jason Wen 2f9951df02 Merge branch 'e2e-alert-state-machine' into hkg-angle-steering-2025 2025-10-15 23:55:40 -04:00
Jason Wen 6030bf4da3 less 2025-10-15 23:52:03 -04:00
Jason Wen 074694d660 lead depart: only arm if we have a confirmed close lead for over a second after allowing alert 2025-10-15 23:48:13 -04:00
Jason Wen df35f48f3b magic 2025-10-15 22:56:08 -04:00
Jason Wen 4fb9704540 time based 2025-10-15 22:51:40 -04:00
Jason Wen 48cbe266fc 10 frames for both 2025-10-15 22:50:42 -04:00
Jason Wen 21aa7ff367 rename 2025-10-15 22:47:08 -04:00
Jason Wen 7caf05dd51 not used 2025-10-15 22:41:00 -04:00
Jason Wen 2d779f5db9 E2E Helper: universal state machine 2025-10-15 22:38:57 -04:00
Jason Wen 18208f1da0 Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into hkg-angle-steering-2025 2025-10-15 17:41:56 -04:00
Jason Wen 5a3c6ddf57 gate lka angle steering out of alpha long 2025-10-14 23:25:00 -04:00
Jason Wen eaa8732ab0 Merge branch 'e2e-alerts-cooldown' into hkg-angle-steering-2025 2025-10-14 14:44:00 -04:00
Jason Wen 6f0284c84f try preventing startup false trigger 2025-10-14 14:43:47 -04:00
Jason Wen 999ea03f23 try preventing startup false trigger 2025-10-14 14:42:42 -04:00
Jason Wen 0975db3ff1 Merge branch 'e2e-alerts-cooldown' into hkg-angle-steering-2025 2025-10-14 14:31:59 -04:00
Jason Wen 8d70a8b80a only when long not engaged 2025-10-14 14:31:48 -04:00
Jason Wen da93f92887 rename 2025-10-14 14:26:57 -04:00
Jason Wen 9117f6c071 Merge branch 'e2e-alerts-cooldown' into hkg-angle-steering-2025 2025-10-14 14:23:46 -04:00
Jason Wen 3567ff9691 introduce recent moving check 2025-10-14 14:22:41 -04:00
Jason Wen f44ae2ced9 too complicated 2025-10-14 14:08:40 -04:00
Jason Wen 376e0ca615 only allow one trigger per standstill session 2025-10-14 14:07:16 -04:00
Jason Wen 32b7686468 Merge branch 'master' into e2e-alerts-cooldown 2025-10-14 11:40:58 -04:00
nayan b9e0f52ea9 E2E Alert Cooldown 2025-10-14 07:43:15 -04:00
Jason Wen a3163b680f Merge branch 'sla-chimes' into hkg-angle-steering-2025 2025-10-14 02:01:05 -04:00
Jason Wen 8a927d808f Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-10-14 02:00:36 -04:00
Jason Wen bc7d5e474d Speed Limit Assist: audible alerts for certain states 2025-10-14 01:45:13 -04:00
Jason Wen 36f192b5fe Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into hkg-angle-steering-2025 2025-10-13 03:10:47 -04:00
Jason Wen ffd5cd4ac2 Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into hkg-angle-steering-2025 2025-10-11 02:29:47 -04:00
Jason Wen e4a00fcd6c Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into hkg-angle-steering-2025 2025-10-10 17:28:16 -04:00
Jason Wen 0bdcb41103 Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into hkg-angle-steering-2025
# Conflicts:
#	common/params_keys.h
#	opendbc_repo
#	selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.cc
2025-10-10 17:02:14 -04:00
DevTekVE 78051085ca Merge branch 'master' into hkg-angle-steering-2025 2025-09-23 07:54:32 +02:00
DevTekVE 4910d5809a bump opendbc 2025-09-23 07:45:39 +02:00
DevTekVE 8dd862ff28 yikes, becoming picky huh? 2025-09-14 22:50:21 +02:00
DevTekVE 1b57497da9 Merge remote-tracking branch 'origin/master' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-09-14 22:48:00 +02:00
DevTekVE 8d8d1ffc7a bump opendbc again 2025-09-14 22:46:20 +02:00
DevTekVE c5919d5495 wrong dbc lol 2025-09-14 22:42:19 +02:00
DevTekVE da71951c95 This is no longer in use nor needed. Bai! 2025-09-14 12:56:28 +02:00
DevTekVE 25a152cd8b Merge remote-tracking branch 'origin/master' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-09-14 12:44:23 +02:00
DevTekVE 9077a1082a Sorry for C3 :( but moving you out to a last working branch before I sync it up 2025-09-14 06:52:24 +02:00
DevTekVE 7ae7000254 Rework override behavior and feeling 2025-09-14 06:38:00 +02:00
DevTekVE 7029455706 better juggle 2025-09-13 08:32:27 +02:00
DevTekVE 3a71a62215 Merge branch 'master' into hkg-angle-steering-2025 2025-09-12 10:14:52 +02:00
DevTekVE 00622e8c33 Merge remote-tracking branch 'origin/master' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-09-05 09:46:41 +02:00
DevTekVE 549da3ee92 Merge branch 'master' into hkg-angle-steering-2025 2025-09-04 20:20:37 +02:00
DevTekVE e038a65ef8 Merge branch 'master' into hkg-angle-steering-2025 2025-08-31 13:14:33 +02:00
DevTekVE 8d0513c657 dbc: update CHECKSUM format for multiple messages to improve data integrity 2025-08-30 19:56:21 +02:00
DevTekVE 2cea48f4cd Merge remote-tracking branch 'origin/master' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-08-30 15:27:45 +02:00
DevTekVE 8855a9ab65 Improve surprise jerk by safety blocks 2025-08-26 14:47:26 +02:00
DevTekVE 32321c01cc A bit more helpful safety block investigation help 2025-08-26 10:09:11 +02:00
DevTekVE 52cd65fefb lint dont bother me 2025-08-25 08:24:24 +02:00
DevTekVE 1fcdeccd40 Merge branch 'master' into hkg-angle-steering-2025
# Conflicts:
#	common/params_keys.h
#	opendbc_repo
2025-08-25 08:01:51 +02:00
DevTekVE 3517c36978 Revert "Add HkgAngleDebug structure and enhance angle debugging in car controller" 2025-08-24 19:02:48 +02:00
DevTekVE fb30c3c1e8 cleanup and honour params 2025-08-23 15:42:47 +02:00
DevTekVE 1c25e568d5 Update steering pressed logic to include hands-on-wheel detection for improved safety 2025-08-23 15:11:07 +02:00
DevTekVE f172122b7c Update steering pressed logic to include hands-on-wheel detection for improved safety 2025-08-22 19:55:16 +02:00
Jason Wen 67d6cdc7cd Merge remote-tracking branch 'sunnypilot/sunnypilot/hkg-angle-steering-2025' into hkg-angle-steering-2025 2025-08-21 16:39:36 -04:00
DevTekVE 6724085cfd Refactor angle limit calculations and adjust average road roll for improved steering dynamics 2025-08-21 20:09:57 +02:00
DevTekVE 6774f34eee Refine non-linear mapping in torque reduction gain calculation for improved steering response 2025-08-21 00:21:46 +02:00
DevTekVE 6d0402896d Adjust STEER_THRESHOLD and refine non-linear mapping in torque reduction gain calculation for improved steering response 2025-08-20 23:16:04 +02:00
DevTekVE 344021a3d9 Adjust non-linear mapping in torque reduction gain calculation for improved response 2025-08-20 19:54:31 +02:00
DevTekVE a9b85ab27d Refactor HkgAngleDebug structure to include current and baseline limits for angle parameters 2025-08-20 19:54:10 +02:00
DevTekVE 17204a46e4 Add HkgAngleDebug structure and enhance angle debugging in car controller 2025-08-20 18:39:53 +02:00
DevTekVE 7c4d415462 Enhance torque reduction gain calculation with non-linear mapping and smoothing 2025-08-20 00:12:43 +02:00
DevTekVE b8985b6d72 Enhance torque reduction gain calculation with non-linear mapping and smoothing 2025-08-19 19:50:13 +02:00
DevTekVE c669473f88 Refine torque reduction parameters and update UI for angle error analysis 2025-08-19 19:35:34 +02:00
DevTekVE 8751435bf5 Improving tq redc gain and override behavior 2025-08-19 10:08:51 +02:00
DevTekVE 30ae210761 Merge branch 'master' into hkg-angle-steering-2025 2025-08-19 10:07:42 +02:00
Jason Wen 3eb693f58b Merge remote-tracking branch 'sunnypilot/sunnypilot/hkg-angle-steering-2025' into hkg-angle-steering-2025 2025-08-18 12:30:29 -04:00
DevTekVE 7b4a31c5ac bugfix 2025-08-17 16:07:45 +02:00
DevTekVE 1527c8cf88 bump opendbc 2025-08-17 15:31:31 +02:00
DevTekVE ab0a7ae666 no joystick on this branch, causing issues 2025-08-17 15:25:40 +02:00
DevTekVE 11ec2f1f21 Apply suggestions from code review 2025-08-17 15:10:17 +02:00
DevTekVE 2c6808d37e Merge branch 'master' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-08-17 15:02:28 +02:00
Jason Wen 2e96382c49 notebook init 2025-08-17 00:34:01 -04:00
DevTekVE 0239e440ca Adjust replay 2025-08-15 10:32:07 +02:00
Jason Wen 76b972daff Hyundai angle steering: STEERING_ANGLE_2 available on all cars 2025-08-14 01:56:46 -04:00
Jason Wen bc3ef3e7dd Hyundai angle steering: hugging no more - use the true steering angle signal from MDPS 2025-08-13 23:08:32 -04:00
DevTekVE 9839291dd0 Merge remote-tracking branch 'origin/master' into hkg-angle-steering-2025 2025-08-13 20:13:42 +02:00
DevTekVE 17cba328d6 refactor: update torque tuning configuration for angle steering
- Adjusted torque tuning configuration to avoid reliance on torque controller for Hyundai angle steering.
- Simplified control logic by removing unnecessary checks for torque control type.
refactor: clean up code formatting and improve test structure for torque reduction gain
2025-08-13 20:03:51 +02:00
DevTekVE 86093765d8 Merge branch 'master' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-08-13 07:55:46 +02:00
DevTekVE 05fa1c8ae8 Adjust default params and cleanup 2025-08-12 21:36:22 +02:00
DevTekVE e8a40d6b85 Merge branch 'master' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
#	system/manager/process_config.py
2025-08-10 14:24:10 +02:00
DevTekVE c265e0bb85 Merge remote-tracking branch 'origin/master' into hkg-angle-steering-2025
# Conflicts:
#	common/params_keys.h
#	opendbc_repo
#	system/manager/manager.py
2025-08-02 09:56:58 +02:00
DevTekVE c6b118788b Merge branch 'master-new' into hkg-angle-steering-2025 2025-07-31 18:25:08 +02:00
DevTekVE b004f6dbdc Merge branch 'master-new' into hkg-angle-steering-2025 2025-07-31 18:17:34 +02:00
DevTekVE cd4930b680 Bump opendbc 2025-07-26 10:56:49 +02:00
DevTekVE f861aca628 Refactor vehicle model initialization and adjust angle limits for baseline model 2025-07-26 08:12:06 +02:00
DevTekVE 1ff0d8e2ee please don't bother me anymore! 2025-07-26 08:09:51 +02:00
DevTekVE d76d70764e Update slip factor precision for Hyundai steering parameters
- Adjusted `slip_factor` in Hyundai CANFD safety modes for improved consistency and accuracy.
- Ensured proper representation of `slip_factor` output in test logs.
2025-07-25 20:17:19 +02:00
DevTekVE dc73ce0b71 save tools replay 2025-07-25 19:47:31 +02:00
DevTekVE 3f666748af bump opendbc 2025-07-25 14:16:02 +02:00
DevTekVE 8de8a8838c bumo opendbc 2025-07-25 14:08:53 +02:00
DevTekVE f563b7eb71 Refactor steering angle limit application for improved safety and model compliance 2025-07-25 12:12:42 +02:00
DevTekVE 3c18b83708 save temp 2025-07-25 09:56:30 +02:00
DevTekVE bd35f5904b Enhance steering angle rate limiting and safety enforcement logic
- Introduced explicit post-rate limiting using model-specific dynamics.
- Improved low-speed smoothing and precision of applied angles.
2025-07-25 08:12:41 +02:00
DevTekVE 474f2737f6 Refactor steering angle limit logic for conservative seleion
- Removed unused lateral accel/jerk logic for simplicity.
- Updated angle limit calculations to choose the smallest delta for safer control.
2025-07-24 21:48:24 +02:00
DevTekVE ea1ac4a212 Revert "Add configurable max lateral accel and jerk parameters for Hyundai vehicles"
This reverts commit b95f8c5929.

Revert "Add baseline safety model and improve steering angle limiting logic"

This reverts commit b53cbb2e18.

Revert "Disable lateral accel/jerk params and ensure float consistency in angle limits"

This reverts commit 165d7c7b36.
2025-07-24 10:02:48 +02:00
DevTekVE 165d7c7b36 Disable lateral accel/jerk params and ensure float consistency in angle limits
- Commented out unused lateral accel/jerk parameters for clarity.
- Ensured `np.clip` always returns a float for precision.
2025-07-24 09:41:52 +02:00
DevTekVE b53cbb2e18 Add baseline safety model and improve steering angle limiting logic
- Introduced a baseline safety model (`GENESIS_GV80_2025`) for comparison.
- Enhanced steer angle limit calculation using both baseline and current limits for improved safety and precision.
2025-07-24 09:38:03 +02:00
DevTekVE b95f8c5929 Add configurable max lateral accel and jerk parameters for Hyundai vehicles
- Introduced user-configurable options for max lateral acceleration and jerk.
- Enables fine-tuning of vehicle handling for smoother control.
2025-07-24 08:39:10 +02:00
DevTekVE e564bb0b85 bumo openbc 2025-07-23 18:46:52 +02:00
DevTekVE e2ec8a7b13 Refine lateral control limits and simplify safety model handling
- Reduced max lateral acceleration and jerk by 20% for smoother handling.
- Removed unused `get_safety_CP` function, simplifying `VehicleModel` initialization.
2025-07-22 08:07:51 +02:00
DevTekVE 75c6f0f10e Test with gv80 as baseline for limits 2025-07-20 22:14:18 +02:00
DevTekVE af38044b42 Merge branch 'master-new' into hkg-angle-steering-2025 2025-07-20 10:14:46 +02:00
DevTekVE 684fa846d8 Merge branch 'master-new' into hkg-angle-steering-2025
# Conflicts:
#	.codespellignore
#	opendbc_repo
#	system/manager/manager.py
2025-07-19 21:51:46 +02:00
DevTekVE 416e722855 Update baseline model to IONIQ 5 PE for improved angle safety tuning
- Replaced conservative GENESIS_GV80_2025 model with IONIQ 5 PE parameters.
- Adjusted steering parameters (ratio, slip factor, wheelbase) for better lateral control performance.
2025-07-19 21:46:17 +02:00
DevTekVE 9fd4613bbb Add 2025 Kia EV6 support with updated radar and camera fingerprints 2025-07-09 09:47:31 +02:00
DevTekVE a0362e3c5f "Refined UI labels and tooltips for HKG tuning options to improve clarity and user understanding." 2025-06-29 16:48:53 +02:00
DevTekVE e32ef1cdc0 Fix incorrect torque sign usage in torque reduction calculation
Ensure `actuators.torque` uses its absolute value in the `calculate_angle_torque_reduction_gain` method to prevent sign-related issues during Hyundai steering angle control.
2025-06-29 14:33:30 +02:00
DevTekVE 20673ec8a6 Adjust warning font size in angle tuning settings panel. 2025-06-29 13:35:09 +02:00
DevTekVE 53fbdf7329 Rename "IdleTorque" to "ActiveTorque" for clarity.
The parameter name "HkgTuningAngleIdleTorqueReductionGain" was updated to "HkgTuningAngleActiveTorqueReductionGain" across multiple files for better clarity and alignment with its functionality. This change ensures consistency in naming conventions and improves code readability.
2025-06-29 13:23:56 +02:00
DevTekVE 6f72b74fac Add idle torque reduction for Hyundai lateral control
Introduced `ANGLE_IDLE_TORQUE_REDUCTION_GAIN` to manage torque when the vehicle is stationary, ensuring smoother handling and better lane centering. Updated parsing, parameters, and UI settings to support this new idle torque parameter. Adjusted torque calculation logic and smoothing factor behavior for enhanced control flexibility.
2025-06-29 13:22:18 +02:00
DevTekVE e83705a32e Merge branch 'master-new' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-06-29 09:44:01 +02:00
DevTekVE 95d36b9ba2 Refactor and enhance HKG angle tuning logic.
Introduced a toggle for angle smoothing factor and renamed related parameters for clarity. Refactored backend settings to use new parameter names and expanded smoothing matrices for better tuning granularity. Updated UI elements to reflect these changes, emphasizing usability and consistency.
2025-06-28 21:25:44 +02:00
DevTekVE b9e74254bd Merge branch 'master-new' into hkg-angle-steering-2025 2025-06-27 10:46:22 +02:00
DevTekVE b4405b200d Merge remote-tracking branch 'origin/master-new' into hkg-angle-steering-2025 2025-06-25 09:27:21 +02:00
DevTekVE a8a3fdac54 Rename parameter in calculate_target_torque for clarity. 2025-06-23 22:53:45 +02:00
DevTekVE 4eddc622a7 Refactor torque calculations in Hyundai controller
Rename methods and variables for clarity in torque reduction and override calculations. Adjust logic to streamline handling of steering inputs and improve maintainability.
2025-06-23 22:51:40 +02:00
DevTekVE 4e42ada240 Refactor torque management in Hyundai controller for cleaner override and ramp logic
Extract torque ramping and override functionality into dedicated methods within `LkasTorqueManager` to improve maintainability and reduce redundancy. Simplify `update` logic by delegating state-specific operations to new methods.
2025-06-23 22:47:51 +02:00
DevTekVE 6266217655 Introduce LkasTorqueManager for LKAS torque handling in Hyundai controller
Encapsulate LKAS torque calculations, ramping, and override logic into the new `LkasTorqueManager` class to improve modularity and maintainability. Replace existing torque logic with calls to the manager.
2025-06-23 22:20:10 +02:00
DevTekVE ea09d32e98 Remove lateral acceleration logic from Hyundai steering controller 2025-06-23 21:55:17 +02:00
DevTekVE 15958c88d3 Refactor lateral acceleration scaling logic in Hyundai controller
Move scaling of `max_angle_delta` under high lateral acceleration to improve clarity and prevent redundant operations.
2025-06-23 20:22:03 +02:00
DevTekVE b80d7fb5ea Adding GV70 electrified 2026 2025-06-22 14:30:59 +02:00
DevTekVE 1c3d25c6ff Refine lateral acceleration handling in Hyundai steering logic
Enforce absolute check for `real_a_lat` against `MAX_LATERAL_ACCEL` to improve angle scaling under high lateral acceleration conditions.
2025-06-22 11:03:35 +02:00
rav4kumar c9f22b32c7 Revert "Incorporate lateral acceleration in Hyundai angle steering logic"
This reverts commit c0524985bb.
2025-06-21 11:40:58 -07:00
DevTekVE c0524985bb Incorporate lateral acceleration in Hyundai angle steering logic
Add handling for IMU lateral acceleration to refine steering angle limits in CAN FD configurations. Parse and utilize `IMU_LatAccelVal` signal for enhanced lateral control accuracy.
2025-06-21 17:34:13 +02:00
DevTekVE 83839c7ea7 Add angle steering support and refactor related logic for Hyundai CAN FD.
Introduced support for CAN FD angle steering, including updated parameters, signal parsing, and new tests. Refactored related steering logic for clarity, reducing unused code and enhancing maintainability.
2025-06-21 13:38:50 +02:00
DevTekVE c1a1d4b4c3 Update lint script to exclude .xml files in layouts directory
Added `layouts/.*\.xml` to `IGNORED_FILES` in `lint.sh` to prevent linting of layout XML files.
2025-06-20 10:50:45 +02:00
DevTekVE b5af7a905a Merge branch 'master-new' into hkg-angle-steering-2025 2025-06-18 20:13:45 +02:00
DevTekVE 96b1b2f55f Update steering request logic in Hyundai controller
Ensure steering request activation depends on lateral control being active. This adds clarity and aligns better with control logic requirements.
2025-06-17 18:51:54 +02:00
DevTekVE 9361ba5d70 Refactor Hyundai steering angle handling logic
Streamline steering angle calculations and fault avoidance logic by removing redundant comments and unused code. Simplified `round_angle` implementation for clarity and consistency.
2025-06-17 12:08:06 +02:00
DevTekVE 4e9014311e Refactor steeringPressed logic in Hyundai carstate.py.
Revised the determination of `steeringPressed` to account for both hands-on-wheel detection and torque overriding in CAN FD setups. Simplified fallback logic for non-CAN FD configurations for better code clarity and maintainability.
2025-06-12 00:31:07 +02:00
DevTekVE 232873fc70 Refine steering press detection logic.
Adjusted the sensitivity and threshold values for `HOD_Dir_Status` in steering press updates, improving accuracy in detecting steering input. This change aligns with updated parameter requirements for better responsiveness.
2025-06-12 00:14:05 +02:00
DevTekVE 0a61fca9c9 Fix steering press detection for Hyundai models.
Updated the condition to detect steering press by changing HOD_Dir_Status threshold from `> 2` to `>= 2`. This ensures the detection logic aligns correctly with expected behavior.
2025-06-12 00:06:52 +02:00
DevTekVE 480bdc34dc Add support for CANFD angle steering in Hyundai cars
Introduced handling for the `HOD_FD_01_100ms` message when the CANFD angle steering flag is enabled. This ensures proper message parsing and extends compatibility for specific Hyundai vehicle configurations.
2025-06-12 00:04:44 +02:00
DevTekVE 716b475a13 Update Hyundai controls for HOD status and steer limits
Adjusted the steering override frame window and incorporated new HOD_Dir_Status to improve hands-on detection. Added parsing for new signals in Hyundai CAN FD, enhancing steering override responsiveness and reliability.
2025-06-12 00:01:31 +02:00
DevTekVE b1ec5ec034 Adjust override angle cap in Hyundai car controller
Increased the minimum override angle cap from 0.01 to 0.1 and explicitly cast the maximum cap to a float. This change improves consistency and ensures proper handling of steering limits.
2025-06-11 23:20:19 +02:00
DevTekVE 470613c2b7 Adjust Hyundai steer override parameters for improved control.
Reduced the override frame window and updated the angle cap logic to use MAX_ANGLE_RATE. These changes aim to enhance steering responsiveness and safety by fine-tuning steer angle limits.
2025-06-11 23:07:49 +02:00
DevTekVE 336c5b4154 Remove smoothing_factor from Hyundai car controller logic
The `smoothing_factor` parameter and related logic have been removed to simplify the steering angle smoothing approach. All references and usage of this parameter have been eliminated, relying solely on speed-based dynamic interpolation. This change streamlines the code while maintaining functionality.
2025-06-11 23:04:32 +02:00
DevTekVE abdb9dc750 Adjust Hyundai steering override frame logic
Reduced `OVERRIDE_FRAME_WINDOW` and updated condition to properly respect override frame limits. This ensures smoother handling and more precise steering adjustments under certain driving scenarios.
2025-06-11 22:49:04 +02:00
DevTekVE ab98683973 Refactor steering override logic in Hyundai carcontroller
Replaced `recently_overridden` with `frames_since_override` for better granularity and added dynamic override angle limits using interpolation. These changes enhance steering control accuracy during user overrides and improve overall code readability.
2025-06-11 22:42:05 +02:00
DevTekVE 186c24dbe6 Refine Hyundai steering override handling logic
Adjusted logic for recently overridden steering to improve angle limits and torque smoothing. Removed unused or redundant code, optimizing the functionality and maintaining cleaner readability.
2025-06-11 21:49:18 +02:00
DevTekVE 9cdf6340a1 Refactor steering angle smoothing for clarity and reuse.
Extracted the steering angle smoothing logic into a standalone function `sp_smooth_angle` to enhance readability and reusability. Adjusted angle smoothing parameters and introduced a maximum vehicle speed threshold for applying smoothing. Minor updates improve maintainability and ensure consistent behavior across speed ranges.
2025-06-11 10:07:44 +02:00
DevTekVE 2855b1341c Adjust steering thresholds for Hyundai CAN FD vehicles
Updated `STEER_THRESHOLD` to 350 and `NO_LONGER_OVERRIDING_THRESHOLD` to 150 for better alignment with Hyundai CAN FD steering behavior. These changes ensure improved compatibility and more accurate steering response.
2025-06-10 09:53:08 +02:00
DevTekVE cf28f99976 Revert "Add twilsonco's LKAS torque calculator for improved lateral control"
This reverts commit b1770fb0e7aece0e160b1b083cb260edbbdc53dd.
2025-06-10 09:40:59 +02:00
DevTekVE a39d67dc47 Fix apply_angle_last reset logic in Hyundai carcontroller
Re-enables resetting `apply_angle_last` to `steering_angle` when steering is recently overridden. This ensures proper handling of steering angle limits during transitions.
2025-06-08 19:04:02 +02:00
DevTekVE 7e75257f12 Refine Hyundai steering control logic.
Simplified torque ramp-up logic by combining conditions and adjusted `STEER_THRESHOLD` for CANFD angle steering. These changes aim to enhance control precision and maintain consistency in overrides.
2025-06-08 19:02:49 +02:00
DevTekVE df38449553 Reduce override timeout for Hyundai carcontroller
Decrease the override timeout from 100 to 50 frames, ensuring quicker recognition of driver input override. This improves responsiveness and aligns with refined control behavior.
2025-06-08 18:22:44 +02:00
DevTekVE 1385ef3bc5 Fix steering control behavior during user override
Removed restrictive rate limiting during recent user overrides to improve steering response. Adjusted logic to ensure correct handling of steering angle when lateral control is inactive or overridden.
2025-06-08 18:01:47 +02:00
DevTekVE 7c23c11c51 Refine steering logic with override detection.
Adjust steering behavior to account for recent user overrides, improving safety and control. Introduced a "recently_overridden" check to limit angle rates and torque adjustments when user intervention is detected.
2025-06-08 17:52:16 +02:00
DevTekVE aeff2e12ec Refine steering logic with user override handling.
Added logic to use the current steering angle when the steering wheel is pressed, ensuring smoother transitions during user overrides. Updated function parameters and implementation to reflect this enhancement.
2025-06-08 17:38:34 +02:00
DevTekVE 7274899671 Refactor Hyundai override logic for steering thresholds
Removed redundant `recently_overridden` logic and introduced a more robust approach for tracking user steering overrides. Added `NO_LONGER_OVERRIDING_THRESHOLD` and updated conditions to improve steer override handling. Adjustments ensure smoother torque transitions and more accurate steering state detection.
2025-06-08 17:00:44 +02:00
DevTekVE 6c00fd608f pass tests? 2025-06-08 12:28:11 +02:00
DevTekVE df6a034c11 Bump opendbc 2025-06-08 12:26:09 +02:00
DevTekVE acb109c290 adding plotjuggler stuff 2025-06-08 10:02:44 +02:00
DevTekVE b227b00249 Update torque clamping to use parameterized min torque
Replaced hardcoded `angle_min_active_torque` with `ANGLE_MIN_TORQUE` from params for better configurability and consistency. This ensures the torque clamping logic aligns with defined parameters.
2025-06-07 19:43:01 +02:00
DevTekVE 3ec9d6c18a Merge branch 'master-new' into hkg-angle-steering-2025
# Conflicts:
#	common/params_keys.h
2025-06-07 15:04:16 +02:00
DevTekVE 86db8b95f0 Refactor torque calculation and deactivate live tuning.
Updated torque calculation logic with a new optional parameter for minimum active torque, streamlining control behavior. Deactivated and cleaned up references to HkgAngleLiveTuning, simplifying configuration and reducing runtime complexities. Updated relevant UI and parameter descriptions for clarity.
2025-06-07 11:55:57 +02:00
DevTekVE 4cfff8a35f Merge branch 'master-new' into hkg-angle-steering-2025 2025-06-06 23:08:37 +02:00
DevTekVE 962fedf48c Merge branch 'master-new' into hkg-angle-steering-2025
# Conflicts:
#	opendbc/car/tests/routes.py
2025-06-06 20:49:06 +02:00
DevTekVE 04494414d1 Merge branch 'master-new' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-06-05 09:18:53 +02:00
DevTekVE 0b83576e9b Adjust torque ramping logic and update steering thresholds
Increase the override window and refine torque ramp-up behavior to avoid conflicts during recent overrides. Updated steering driver allowance and threshold values for CANFD angle steering to improve compatibility and performance.
2025-06-02 09:49:31 +02:00
DevTekVE ce4ef0f817 Refine steering override logic in Hyundai car controller
Added logic to track recent steering overrides and adjust LKAS torque behavior accordingly. This ensures smoother transitions when the steering is overridden and reduces potential conflicts with driver input. Updated CANFD-specific steering thresholds for enhanced compatibility.
2025-06-02 09:12:03 +02:00
DevTekVE f0b15c1c56 Adding twil's torque calculation 2025-06-01 19:04:34 +02:00
DevTekVE f898e9fdfe Merge branch 'master-new' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-06-01 09:46:45 +02:00
DevTekVE 8ee7804b0e Bump opendbc (no tesla controls, no twil yet) 2025-05-29 16:31:42 +02:00
DevTekVE 923228194e bump opendbc to prior tesla changes until i can pass safety validations 2025-05-28 12:44:44 +02:00
DevTekVE 8837b2e3f6 Merge branch 'master-new' into hkg-angle-steering-2025
# Conflicts:
#	opendbc_repo
2025-05-28 12:36:02 +02:00
DevTekVE f48c9dc1c2 bump opendbc 2025-05-25 17:34:24 +02:00
DevTekVE 74aa07a8cd Ingore something i dont control thx 2025-05-25 17:31:37 +02:00
DevTekVE 5236e4860f Make lint happy, maybe 2025-05-25 17:31:37 +02:00
DevTekVE 3d174da1c3 adding some of my tests and validaitons 2025-05-25 17:31:25 +02:00
DevTekVE 8faa40f3a3 clean 2025-05-25 17:31:25 +02:00
DevTekVE 3e03275f28 Add PlotJuggler layout for analyzing torque and angle data
This new layout visualizes actuator data, CAN steering messages, and car state variables. It provides multiple time-series plots to aid in debugging and analysis. Plugin configurations are also included for extended functionality.
2025-05-25 17:31:22 +02:00
DevTekVE 7595cf8a25 Refine Hyundai angle and torque control logic.
Simplified control flag handling for angle steering, adjusted torque calculations for smoother ramp rates, and updated tuning parameters for the Hyundai Ioniq 5 PE. Minor adjustment to return value handling in lateral control functions.
2025-05-25 17:31:22 +02:00
DevTekVE 2675d43adb bump opendbc
Remove duplicate STEER_ANGLE_SATURATION_THRESHOLD import

Cleaned up an unnecessary duplicate import of STEER_ANGLE_SATURATION_THRESHOLD from latcontrol_angle_torque. This simplifies the module imports and prevents potential redundancy or confusion.

Refactor lateral control to combine torque and angle logic

Merged functionalities of LatControlTorque and LatControlAngle into a single LatControlAngleTorque class. Refactored code to utilize methods from both parent classes, reducing duplication and improving maintainability.

Add angle-torque hybrid lateral control for Hyundai CAN FD

Introduces `LatControlAngleTorque` to enable hybrid angle and torque-based steering for specific Hyundai models. Updates related logic in carcontroller, interface, and controlsd to accommodate this new lateral control method. Adjusts torque parameters for enhanced control in supported models.
2025-05-25 17:31:21 +02:00
DevTekVE d9f4ce82e6 clean 2025-05-25 17:31:21 +02:00
DevTekVE 648a1845d8 cleanup the mess 2025-05-25 17:31:21 +02:00
DevTekVE a87eff6d1c Add HKG Angle Live Tuning parameter and update related handling 2025-05-25 17:31:21 +02:00
DevTekVE dd6ad37e23 Absolutely zero clue on this, I did it with AI and it's for me to play. Don't take this notebook seriously please 2025-05-25 17:31:21 +02:00
DevTekVE c5e778b939 How annoying the linter on a comment lol 2025-05-25 17:31:21 +02:00
DevTekVE a9ab81a77a useless but should keep linter happy 2025-05-25 17:31:21 +02:00
DevTekVE 2d40e1d8e5 Refactor torque parameter handling in Hyundai carcontroller
Replaced direct access to `params` with instance variables for torque parameters to improve code clarity and maintainability. Updated smoothing factor description in angle tuning settings to include speed-related behavior. This enhances readability and prepares for further tuning adjustments.
2025-05-25 17:31:20 +02:00
DevTekVE 7c8f367a5d Fix data type for HkgTuningOverridingCycles value
Updated the value of HkgTuningOverridingCycles to a string for consistency with other parameters in the tuning configuration. This ensures proper handling and avoids potential issues with type mismatches.

Add overriding cycles parameter for torque adjustment

Introduced "HkgTuningOverridingCycles" for configurable user override torque ramp-down cycles. Updated relevant logic in torque control and UI settings to handle the new parameter. This improves flexibility in adjusting steering torque override behavior.
2025-05-25 17:31:20 +02:00
DevTekVE ff4cf558aa Add HKG angle tuning settings with min/max torque parameters
Introduce separate angle tuning controls for HKG vehicles, including smoothing factor, min torque, and max torque parameters. Refactor developer panel to integrate the new settings into a dedicated UI panel, enhancing modularity and customization capabilities.
2025-05-25 17:31:20 +02:00
DevTekVE 0e151e51bc Update HKG Angle Smoothing Factor description in Developer Panel
Enhanced the description to clarify its effect on steering behavior. Included details on how the smoothing factor impacts steering smoothness using EMA, aiding user understanding.
2025-05-25 17:31:20 +02:00
DevTekVE 60cc0031b0 Revert "Revert "Revert the EMA calculation on the curvature to test another approach""
This reverts commit 58fcda8c
2025-05-25 17:31:20 +02:00
DevTekVE d24cac0998 Refactor steering angle logic for smoother control adjustments
Refactored the calculation and application of the steering angle to improve code clarity and ensure smoother transitions. Removed unused parameter update logic in `latcontrol_angle.py` and enhanced handling of driver overrides in `carcontroller.py`.
2025-05-25 17:31:20 +02:00
DevTekVE 45d110830c Fix typo in parameter access method.
Replaced `self._params` with `self.params` to correctly access the parameter `HkgTuningAngleSmoothingFactor`. This ensures the smoothing factor is updated as intended during the control loop.
2025-05-25 17:31:20 +02:00
DevTekVE ea3a9ae911 Improve angle smoothing by integrating dynamic parameter tuning
Introduced a dynamic smoothing factor using the `HkgTuningAngleSmoothingFactor` parameter. This allows more granular control over curvature smoothing based on customizable user input, enhancing driving smoothness. Added necessary logic to process and apply this parameter efficiently.
2025-05-25 17:31:19 +02:00
DevTekVE 6bff8c0e7c Revert "Revert the EMA calculation on the curvature to test another approach"
This reverts commit bd471b3498.
2025-05-25 17:31:19 +02:00
DevTekVE bc6b8802b8 Add HKG angle smoothing factor for steering adjustments
Introduced a new parameter, `HkgTuningAngleSmoothingFactor`, to apply exponential moving average (EMA) smoothing to steering angle changes, reducing sudden adjustments. Added associated UI controls, parameter persistence, and integration into Hyundai carcontroller logic for improved steering stability.
2025-05-25 17:31:19 +02:00
DevTekVE 252ef572d3 Revert the EMA calculation on the curvature to test another approach 2025-05-25 17:31:19 +02:00
DevTekVE 414d397e3f Handle missing pygame import gracefully
Wrap the pygame import in a try-except block to catch ImportError. This prevents the script from crashing and provides a clear message prompting the user to install pygame if it's missing.

Remove "inputs" package and update "pygame" dependency

The "inputs" package has been removed from the lockfile and dependency list, while "pygame" is now included universally without the "dev" extra marker. This change simplifies dependencies and ensures consistency across environments.

Update dependencies: replace 'inputs' with 'pygame'

Replaced the 'inputs' library with 'pygame' for joystickd dependencies in `pyproject.toml`. Additionally, removed a redundant 'pygame' entry from the general dependencies.

Ugly, I know, but soundd is unhappy with joystick

Allowing lat with mads

Invert steering input for joystick control

The steering axis input is now multiplied by -1 to reverse its direction. This ensures correct handling of the left stick's horizontal input, aligning behavior with expected control dynamics.

Refactor joystick control to use pygame for broader support

Replaced the `inputs` library with `pygame` for joystick handling, providing improved compatibility with Xbox and PlayStation controllers. Added initialization, adaptive mappings, deadzone handling, and enhanced event processing for robust joystick operation. Updated README with dependencies and usage information for Xbox controllers.
2025-05-25 17:31:19 +02:00
DevTekVE 11b7b3789d Adjust speed thresholds in filter_speed_matrox.
Updated the `filter_speed_matrox` values to improve curvature filtering behavior at different speeds. This change ensures better handling and stability across a wider range of driving conditions.
2025-05-25 17:31:19 +02:00
DevTekVE 871ac53717 Optimize curvature filtering by adding speed-dependent logic.
Introduced speed-based dynamic alpha adjustment using interpolation for smoother curvature filtering. This improves steering angle calculations by adapting filter sensitivity to vehicle speed, enhancing control performance.
2025-05-25 17:31:19 +02:00
DevTekVE 64ea66b6e6 chsnge alpha to nicer value 2025-05-25 17:31:19 +02:00
DevTekVE 6d7c6759b3 Adjust curvature handling and filtering parameters
Updated curvature breakpoints and torque scaling for improved control in sharp turns. Increased filter alpha for faster curvature response while maintaining system stability.
2025-05-25 17:31:18 +02:00
DevTekVE 4cea013570 Adjust curvature handling and filtering parameters
Updated curvature breakpoints in Hyundai carcontroller to improve torque scaling for curved driving. Slightly refined the filter coefficient in lateral control for smoother curvature filtering and more accurate steering adjustments.
2025-05-25 17:31:18 +02:00
DevTekVE eb375c0587 Refactor curvature-based steering angle and torque logic.
Introduced dynamic torque scaling based on curvature for smoother and more adaptive steering control. Replaced raw curvature inputs with filtered curvature for enhanced stability and reduced noise in steering angle calculations. Removed unused speed scaling logic to simplify the lateral control flow.
2025-05-25 17:31:18 +02:00
DevTekVE 7fd8a5a4bd Reapply "Significant improvement on the jerkiness"
This reverts commit 85ce84e7b7.
2025-05-25 17:31:18 +02:00
DevTekVE b3c90216bb Revert "Significant improvement on the jerkiness"
This reverts commit ea1af879ba2905b076ccfe65993a9db701d689dd.

Revert "More improvement but still not quite"

This reverts commit ad95493c5c61b2ace7c459d2ebc151ddaa80040f.

Revert "Adjust low-speed scaling for lateral control angle"

This reverts commit 6f789ac1ebb66b0239b4028303573c2d7d386b39.

Revert "Refactor speed-based steering scaling logic."

This reverts commit 1d40735ab8db8d470ff3b287a6b42847beffff7d.
2025-05-25 17:31:18 +02:00
DevTekVE 10f345f956 Refactor speed-based steering scaling logic.
Updated the steering angle computation to use a clearer and more descriptive speed-scaling configuration. Replaced low-speed-specific logic with a generalized approach based on speed breakpoints and corresponding influence factors. This improves maintainability and ensures smoother steering adjustments at varying speeds.
2025-05-25 17:31:18 +02:00
DevTekVE 956d2c36d0 Adjust low-speed scaling for lateral control angle
Refined the low-speed scaling parameters by modifying speed breakpoints and factors. This improves handling at lower speeds for smoother and more predictable behavior.
2025-05-25 17:31:18 +02:00
DevTekVE 55e688b6f2 More improvement but still not quite 2025-05-25 17:31:17 +02:00
DevTekVE f017954027 Significant improvement on the jerkiness 2025-05-25 17:31:17 +02:00
DevTekVE 7e992d11b1 bump panda and opendbc 2025-05-25 17:31:15 +02:00
122 changed files with 6115 additions and 2333 deletions
+2
View File
@@ -2,4 +2,6 @@ Wen
REGIST
PullRequest
cancelled
indeces
FOF
NoO
-46
View File
@@ -1,46 +0,0 @@
name: Publish Docs
on:
push:
branches:
- main
pull_request:
workflow_dispatch:
inputs:
publish:
description: 'Set to true to publish to forum'
required: false
type: boolean
env:
DOCS_CATEGORY_ID: 114
DOCS_DATA_EXPLORER_QUERY_ID: 2
DOCS_TARGET: https://forum.sunnypilot.ai
DOCS_API_KEY: ${{ secrets.DISCOURSE_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
jobs:
# dry_run:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - uses: ruby/setup-ruby@v1
# with:
# ruby-version: "3.3"
# bundler-cache: true
# working-directory: ./release/ci
# - run: bundle exec ./sync_docs.rb --dry-run
# working-directory: ./release/ci
publish:
# if: github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish == 'true')
# needs: dry_run
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"
bundler-cache: true
working-directory: ./release/ci
- run: bundle exec ./sync_docs.rb
working-directory: ./release/ci
@@ -0,0 +1,105 @@
name: 'Post to Discourse'
description: 'Posts a message to a Discourse topic (existing or new)'
inputs:
discourse-url:
description: 'Discourse instance URL (e.g., https://discourse.example.com)'
required: true
api-key:
description: 'Discourse API key'
required: true
api-username:
description: 'Discourse API username'
required: true
topic-id:
description: 'Discourse topic ID to post to (use this OR category-id + title)'
required: false
category-id:
description: 'Category ID for new topic (required if topic-id not provided)'
required: false
title:
description: 'Title for new topic (required if topic-id not provided)'
required: false
message:
description: 'Message content (markdown supported)'
required: true
outputs:
post-number:
description: 'The post number in the topic'
value: ${{ steps.post.outputs.post_number }}
post-url:
description: 'Direct URL to the post'
value: ${{ steps.post.outputs.post_url }}
topic-id:
description: 'The topic ID (useful when creating a new topic)'
value: ${{ steps.post.outputs.topic_id }}
runs:
using: "composite"
steps:
- name: Post to Discourse
id: post
shell: bash
run: |
# Validate inputs
if [ -z "${{ inputs.topic-id }}" ] && ([ -z "${{ inputs.category-id }}" ] || [ -z "${{ inputs.title }}" ]); then
echo "❌ Error: Must provide either topic-id OR both category-id and title"
exit 1
fi
if [ -n "${{ inputs.topic-id }}" ] && ([ -n "${{ inputs.category-id }}" ] || [ -n "${{ inputs.title }}" ]); then
echo "⚠️ Warning: Both topic-id and category-id/title provided. Will post to existing topic."
fi
# Determine if creating new topic or posting to existing
if [ -n "${{ inputs.topic-id }}" ]; then
echo "📝 Posting to existing topic ID: ${{ inputs.topic-id }}"
# Create JSON payload for posting to existing topic
PAYLOAD=$(jq -n \
--arg content '${{ inputs.message }}' \
--arg topic_id "${{ inputs.topic-id }}" \
'{topic_id: $topic_id, raw: $content}')
else
echo "✨ Creating new topic: ${{ inputs.title }}"
# Create JSON payload for new topic
PAYLOAD=$(jq -n \
--arg content '${{ inputs.message }}' \
--arg title "${{ inputs.title }}" \
--arg category "${{ inputs.category-id }}" \
'{title: $title, category: ($category | tonumber), raw: $content}')
fi
# Post to Discourse
RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST "${{ inputs.discourse-url }}/posts.json" \
-H "Content-Type: application/json" \
-H "Api-Key: ${{ inputs.api-key }}" \
-H "Api-Username: ${{ inputs.api-username }}" \
-d "$PAYLOAD")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
echo "✅ Successfully posted to Discourse!"
POST_NUMBER=$(echo "$BODY" | jq -r '.post_number // "unknown"')
TOPIC_ID=$(echo "$BODY" | jq -r '.topic_id // "${{ inputs.topic-id }}"')
POST_URL="${{ inputs.discourse-url }}/t/${TOPIC_ID}/${POST_NUMBER}"
echo "post_number=${POST_NUMBER}" >> $GITHUB_OUTPUT
echo "post_url=${POST_URL}" >> $GITHUB_OUTPUT
echo "topic_id=${TOPIC_ID}" >> $GITHUB_OUTPUT
echo "Topic ID: ${TOPIC_ID}"
echo "Post number: ${POST_NUMBER}"
echo "URL: ${POST_URL}"
else
echo "❌ Failed to post to Discourse"
echo "HTTP Code: ${HTTP_CODE}"
echo "Response: ${BODY}"
exit 1
fi
@@ -79,7 +79,7 @@ jobs:
is_stable_branch="$(echo "$CONFIG" | jq -r '.stable_branch // false')";
echo "is_stable_branch=$is_stable_branch" >> $GITHUB_OUTPUT
stable_version=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g');
stable_version=$(cat sunnypilot/common/version.h | grep SUNNYPILOT_VERSION | sed -e 's/[^0-9|.]//g');
echo "version=$([ "$is_stable_branch" = "true" ] && echo "$stable_version" || echo "$BUILD")" >> $GITHUB_OUTPUT
echo "extra_version_identifier=${environment}" >> $GITHUB_OUTPUT
fi
@@ -302,36 +302,51 @@ jobs:
git push -f origin ${TAG}
notify:
needs: [ build, publish ]
needs:
- prepare_strategy
- build
- publish
runs-on: ubuntu-24.04
if: ${{ (always() && !cancelled() && !failure()) && needs.publish.result == 'success' && !failure() && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
if: ${{ (always() && !cancelled() && !failure())
&& needs.publish.result == 'success'
&& (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
&& (fromJSON(vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES_V2)[github.head_ref || github.ref_name] != null) }}
steps:
- uses: actions/checkout@v4
- name: Setup Alpine Linux environment
uses: jirutka/setup-alpine@v1.2.0
with:
packages: 'jq gettext curl'
- name: Send Discord Notification
env:
DISCORD_WEBHOOK: ${{ contains(fromJSON(vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES), env.SOURCE_BRANCH) && secrets.DISCORD_DEV_FEEDBACK_CHANNEL_WEBHOOK || secrets.DISCORD_DEV_PRIVATE_CHANNEL_WEBHOOK }}
- name: Prepare notification message
id: message
run: |
TEMPLATE='${{ vars.DISCORD_GENERAL_UPDATE_NOTICE }}'
export EXTRA_VERSION_IDENTIFIER="${{ needs.build.outputs.extra_version_identifier }}"
export VERSION="${{ needs.build.outputs.version }}"
export branch_name=${{ env.SOURCE_BRANCH }}
export new_branch=${{ needs.build.outputs.new_branch }}
export extra_version_identifier=${{ needs.build.outputs.extra_version_identifier || github.run_number}}
echo ${TEMPLATE} | envsubst | jq -c '.' | tee payload.json
curl -X POST -H "Content-Type: application/json" -d @payload.json $DISCORD_WEBHOOK
TEMPLATE='${{ vars.DISCOURSE_GENERAL_UPDATE_NOTICE }}'
export VERSION="${{ needs.prepare_strategy.outputs.version }}"
export branch_name="${{ env.SOURCE_BRANCH }}"
export new_branch="${{ needs.prepare_strategy.outputs.new_branch }}"
export commit_sha="${{ github.sha }}"
export commit_short_sha="${{ github.sha }}"
export commit_short_sha="${commit_short_sha:0:7}"
export extra_version_identifier="${{ needs.prepare_strategy.outputs.extra_version_identifier || github.run_number }}"
export PUBLIC_REPO_URL="${{ env.PUBLIC_REPO_URL }}"
echo ""
echo "---- ️ To update the list of branches that notify to dev-feedback -----"
echo ""
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/DEV_FEEDBACK_NOTIFICATION_BRANCHES"
echo "2. Current value: ${{ vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES }}"
echo "3. Update as needed (JSON array with no spaces)"
shell: alpine.sh {0}
MESSAGE=$(cat << 'EOF' | envsubst
${{ vars.DISCOURSE_GENERAL_UPDATE_NOTICE }}
EOF
)
{
echo 'content<<EOFMARKER'
echo "$MESSAGE"
echo 'EOFMARKER'
} >> $GITHUB_OUTPUT
shell: bash
- name: Post to Discourse
uses: ./.github/workflows/post-to-discourse
with:
discourse-url: ${{ vars.DISCOURSE_URL }}
api-key: ${{ secrets.DISCOURSE_API_KEY }}
api-username: "system"
topic-id: ${{ fromJSON(vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES_V2)[github.head_ref || github.ref_name].topic_id }}
message: ${{ steps.message.outputs.content }}
manage-pr-labels:
name: Remove prebuilt label
@@ -3,7 +3,6 @@ name: Build dev
env:
DEFAULT_SOURCE_BRANCH: "master"
DEFAULT_TARGET_BRANCH: "master-dev"
PR_LABEL: "dev"
LFS_URL: 'https://gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git/info/lfs'
LFS_PUSH_URL: 'ssh://git@gitlab.com/sunnypilot/public/sunnypilot-new-lfs.git'
@@ -43,7 +42,7 @@ jobs:
if: (
(github.event_name == 'workflow_dispatch')
|| (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev'))))
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == vars.PREBUILT_PR_LABEL || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, vars.PREBUILT_PR_LABEL))))
)
steps:
- uses: actions/checkout@v4
@@ -55,7 +54,7 @@ jobs:
uses: ./.github/workflows/wait-for-action # Path to where you place the action
if: (
(github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev'))))
|| (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == vars.PREBUILT_PR_LABEL || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, vars.PREBUILT_PR_LABEL))))
)
with:
workflow: selfdrive_tests.yaml # The workflow file to monitor
@@ -119,7 +118,7 @@ jobs:
# Use GitHub API to get PRs with specific label, ordered by creation date
PR_LIST=$(gh api graphql -f query='
query($search_query:String!) {
search(query: $search_query, type:ISSUE, first:100) {
search(query: $search_query, type:ISSUE, first:40) {
nodes {
... on PullRequest {
number
@@ -149,7 +148,7 @@ jobs:
}
}
}
}' -F search_query="repo:${{ github.repository }} is:pr is:open label:${PR_LABEL},${PR_LABEL}-c3 draft:false sort:created-asc")
}' -F search_query="repo:${{ github.repository }} is:pr is:open label:${{ vars.PREBUILT_PR_LABEL }},${{ vars.PREBUILT_PR_LABEL }}-c3 draft:false sort:created-asc")
PR_LIST=${PR_LIST//\'/}
echo "PR_LIST=${PR_LIST}" >> $GITHUB_OUTPUT
+78
View File
@@ -0,0 +1,78 @@
name: Debug Discourse Posting
on:
push:
jobs:
test-discourse-post:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Post test message to Discourse
uses: ./.github/workflows/post-to-discourse
with:
discourse-url: ${{ vars.DISCOURSE_URL }}
api-key: ${{ secrets.DISCOURSE_API_KEY }}
api-username: ${{ secrets.DISCOURSE_API_USERNAME }}
topic-id: ${{ vars.DISCOURSE_UPDATES_TOPIC_ID }}
message: |
## 🧪 Test Post from GitHub Actions
**This is a test post to verify Discourse integration**
- **Workflow**: ${{ github.workflow }}
- **Run Number**: #${{ github.run_number }}
- **Branch**: `${{ github.ref_name }}`
- **Commit**: ${{ github.sha }}
- **Actor**: @${{ github.actor }}
- **Timestamp**: ${{ github.event.head_commit.timestamp }}
---
### Fake Build Info (for testing)
- **Version**: 0.9.8-test
- **Build**: #42
- **Branch**: release-test
[View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
*This is an automated test message. Drive safe! 🚗💨*
- name: Create topic on Discourse
uses: ./.github/workflows/post-to-discourse
with:
discourse-url: ${{ vars.DISCOURSE_URL }}
api-key: ${{ secrets.DISCOURSE_API_KEY }}
api-username: ${{ secrets.DISCOURSE_API_USERNAME }}
#topic-id: ${{ vars.DISCOURSE_UPDATES_TOPIC_ID }}
category-id: 4
title: "This is a test of a new topic instead of a reply"
message: |
## 🧪 Test Post from GitHub Actions
**This is a test post to verify Discourse integration**
- **Workflow**: ${{ github.workflow }}
- **Run Number**: #${{ github.run_number }}
- **Branch**: `${{ github.ref_name }}`
- **Commit**: ${{ github.sha }}
- **Actor**: @${{ github.actor }}
- **Timestamp**: ${{ github.event.head_commit.timestamp }}
---
### Fake Build Info (for testing)
- **Version**: 0.9.8-test
- **Build**: #42
- **Branch**: release-test
[View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
*This is an automated test message. Drive safe! 🚗💨*
- name: Display results
if: always()
run: |
echo "::notice::Discourse post test completed"
echo "Check your Discourse topic to verify the post appeared correctly"
-1
View File
@@ -16,7 +16,6 @@ a.out
.cache/
/docs_site/
/docs_sp_site/
*.mp4
*.dylib
+7
View File
@@ -21,5 +21,12 @@
</clean>
</configuration>
</target>
<target id="f2590b2b-9b93-49f9-8510-da3f3724a2ae" name="replay" defaultType="TOOL">
<configuration id="d475264f-6f4c-4092-9b4e-6773309f38b7" name="replay" toolchainName="Default">
<build type="TOOL">
<tool actionId="Tool_External Tools_uv build tools replay" />
</build>
</configuration>
</target>
</component>
</project>
+7
View File
@@ -20,4 +20,11 @@
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
</exec>
</tool>
<tool name="uv build tools replay" showInMainMenu="false" showInEditor="false" showInProject="false" showInSearchPopup="false" disabled="false" useConsole="true" showConsoleOnStdOut="false" showConsoleOnStdErr="false" synchronizeAfterRun="true">
<exec>
<option name="COMMAND" value="bash" />
<option name="PARAMETERS" value="-c &quot;source .venv/bin/activate &amp;&amp; scons -u -j$(nproc) tools/replay/&quot;" />
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
</exec>
</tool>
</toolSet>
+1 -1
View File
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build Debug" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="sunnypilot" TARGET_NAME="uv Scons Build Debug" CONFIG_NAME="uv Scons Build Debug" RUN_PATH="ui">
<configuration default="false" name="Build Debug" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$ProjectFileDir$/selfdrive/ui" PASS_PARENT_ENVS_2="true" PROJECT_NAME="openpilot-special" TARGET_NAME="uv Scons Build Debug" CONFIG_NAME="uv Scons Build Debug" RUN_PATH="ui">
<envs>
<env name="QT_DBL_CLICK_DIST" value="150" />
</envs>
+27
View File
@@ -0,0 +1,27 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug Route Controls" type="PythonConfigurationType" factoryName="Python">
<module name="openpilot-special" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="FINGERPRINT" value="KIA_EV9" />
<env name="SKIP_FW_QUERY" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/selfdrive/car" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/selfdrive/car/card.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="true" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
</component>
+7
View File
@@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Replay for controls + ui" type="Multirun" separateTabs="false" reuseTabsWithFailures="false" startOneByOne="true" markFailedProcess="true" hideSuccessProcess="false" delayTime="0.0">
<runConfiguration name="replay for controls" type="Native Application" />
<runConfiguration name="Build Debug" type="Custom Build Application" />
<method v="2" />
</configuration>
</component>
+7
View File
@@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="replay for controls" type="CLionNativeAppRunConfigurationType" focusToolWindowBeforeRun="true" PROGRAM_PARAMS="&quot;$Prompt$&quot; --block &quot;sendcan,carState,carParams,carOutput,liveTracks,carParamsSP,carStateSP,bookmarkButton&quot;" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="true" WORKING_DIR="file://$ProjectFileDir$/tools/replay" PASS_PARENT_ENVS_2="true" PROJECT_NAME="openpilot-special" TARGET_NAME="replay" CONFIG_NAME="replay" version="1" RUN_PATH="replay">
<method v="2">
<option name="CLION.COMPOUND.BUILD" enabled="true" />
</method>
</configuration>
</component>
+1080
View File
File diff suppressed because it is too large Load Diff
+17 -19
View File
@@ -3,11 +3,9 @@
## 🌞 What is sunnypilot?
[sunnypilot](https://github.com/sunnyhaibin/sunnypilot) is a fork of comma.ai's openpilot, an open source driver assistance system. sunnypilot offers the user a unique driving experience for over 300+ supported car makes and models with modified behaviors of driving assist engagements. sunnypilot complies with comma.ai's safety rules as accurately as possible.
## 💭 Join our Discord
Join the official sunnypilot Discord server to stay up to date with all the latest features and be a part of shaping the future of sunnypilot!
* https://discord.gg/sunnypilot
![](https://dcbadge.vercel.app/api/server/wRW3meAgtx?style=flat) ![Discord Shield](https://discordapp.com/api/guilds/880416502577266699/widget.png?style=shield)
## 💭 Join our Community Forum
Join the official sunnypilot community forum to stay up to date with all the latest features and be a part of shaping the future of sunnypilot!
* https://community.sunnypilot.ai/
## Documentation
https://docs.sunnypilot.ai/ is your one stop shop for everything from features to installation to FAQ about the sunnypilot
@@ -16,13 +14,13 @@ https://docs.sunnypilot.ai/ is your one stop shop for everything from features t
* A supported device to run this software
* a [comma three](https://comma.ai/shop/products/three) or a [C3X](https://comma.ai/shop/comma-3x)
* This software
* One of [the 300+ supported cars](https://github.com/commaai/openpilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot.
* One of [the 325+ supported cars](https://github.com/sunnypilot/sunnypilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford, and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot.
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
## Installation
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging-c3-new` branch.
Please refer to [Recommended Branches](#recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging` branch.
### If you want to use our newest branches (our rewrite)
> [!TIP]
@@ -31,28 +29,28 @@ Please refer to [Recommended Branches](#-recommended-branches) to find your pref
* sunnypilot not installed or you installed a version before 0.8.17?
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://staging-c3-new.sunnypilot.ai```.
3. Input the installation URL per [Recommended Branches](#recommended-branches). Example: ```https://staging.sunnypilot.ai```.
4. Complete the rest of the installation following the onscreen instructions.
* sunnypilot already installed and you installed a version after 0.8.17?
1. On the comma three, go to `Settings` ▶️ `Software`.
1. On the comma three/3X, go to `Settings` ▶️ `Software`.
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging-c3-new`
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging`
| Branch | Installation URL |
|:----------------:|:---------------------------------------------:|
| `staging-c3-new` | `https://staging-c3-new.sunnypilot.ai` |
| `dev-c3-new` | `https://dev-c3-new.sunnypilot.ai` |
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
| `release-c3-new` | **Not yet available**. |
### Recommended Branches
| Branch | Installation URL |
|:---------------:|:---------------------------------------------:|
| `release` | `https://release.sunnypilot.ai` |
| `staging` | `https://staging.sunnypilot.ai` |
| `dev` | `https://dev.sunnypilot.ai` |
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
> [!TIP]
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-c3-new'.
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging'.
> [!NOTE]
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
> Do you require further assistance with software installation? Join the [sunnypilot community forum](https://community.sunnypilot.ai/new-topic?category=general/qa) and create a topic in the General/Q&A Category channel.
<details>
+9
View File
@@ -154,6 +154,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"IntelligentCruiseButtonManagement", {PERSISTENT | BACKUP , BOOL}},
{"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}},
{"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsReleaseSpBranch", {CLEAR_ON_MANAGER_START, BOOL}},
{"LastGPSPositionLLK", {PERSISTENT, STRING}},
{"LeadDepartAlert", {PERSISTENT | BACKUP, BOOL, "0"}},
{"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}},
@@ -207,6 +208,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"HyundaiLongitudinalTuning", {PERSISTENT | BACKUP, INT, "0"}},
{"SubaruStopAndGo", {PERSISTENT | BACKUP, BOOL, "0"}},
{"SubaruStopAndGoManualParkingBrake", {PERSISTENT | BACKUP, BOOL, "0"}},
{"TeslaCoopSteering", {PERSISTENT | BACKUP, BOOL, "0"}},
{"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}},
{"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}},
@@ -258,4 +260,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"TorqueParamsOverrideEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
{"TorqueParamsOverrideFriction", {PERSISTENT | BACKUP, FLOAT, "0.1"}},
{"TorqueParamsOverrideLatAccelFactor", {PERSISTENT | BACKUP, FLOAT, "2.5"}},
// Tuning keys
{"EnableHkgTuningAngleSmoothingFactor", {PERSISTENT | BACKUP, BOOL, "1"}},
{"HkgTuningAngleMinTorqueReductionGain", {PERSISTENT | BACKUP, INT, "10"}},
{"HkgTuningAngleMaxTorqueReductionGain", {PERSISTENT | BACKUP, INT, "100"}},
{"HkgTuningAngleActiveTorqueReductionGain", {PERSISTENT | BACKUP, INT, "100"}},
{"HkgTuningOverridingCycles", {PERSISTENT | BACKUP, INT, "17"}},
};
+3 -1
View File
@@ -15,6 +15,8 @@
#include "common/version.h"
#include "system/hardware/hw.h"
#include "sunnypilot/common/version.h"
class SwaglogState {
public:
SwaglogState() {
@@ -56,7 +58,7 @@ public:
if (char* daemon_name = getenv("MANAGER_DAEMON")) {
ctx_j["daemon"] = daemon_name;
}
ctx_j["version"] = COMMA_VERSION;
ctx_j["version"] = SUNNYPILOT_VERSION;
ctx_j["dirty"] = !getenv("CLEAN");
ctx_j["device"] = Hardware::get_name();
}
+1 -1
View File
@@ -6,7 +6,7 @@ from openpilot.common.markdown import parse_markdown
class TestMarkdown:
def test_all_release_notes(self):
with open(os.path.join(BASEDIR, "RELEASES.md")) as f:
with open(os.path.join(BASEDIR, "CHANGELOG.md")) as f:
release_notes = f.read().split("\n\n")
assert len(release_notes) > 10
+3 -1
View File
@@ -9,6 +9,8 @@
#include "system/hardware/hw.h"
#include "third_party/json11/json11.hpp"
#include "sunnypilot/common/version.h"
std::string daemon_name = "testy";
std::string dongle_id = "test_dongle_id";
int LINE_NO = 0;
@@ -53,7 +55,7 @@ void recv_log(int thread_cnt, int thread_msg_cnt) {
REQUIRE(ctx["dongle_id"].string_value() == dongle_id);
REQUIRE(ctx["dirty"].bool_value() == true);
REQUIRE(ctx["version"].string_value() == COMMA_VERSION);
REQUIRE(ctx["version"].string_value() == SUNNYPILOT_VERSION);
std::string device = Hardware::get_name();
REQUIRE(ctx["device"].string_value() == device);
+16 -14
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.
# 337 Supported Cars
# 339 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|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
@@ -21,7 +21,10 @@ A supported vehicle is one that just works when you install a comma device. All
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Audi S3 2015-17">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EUV 2022-23">Buy Here</a></sub></details>|<a href="https://youtu.be/xvwzGMUA210" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV 2022-23">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EV Non-ACC 2017|Adaptive Cruise Control (ACC)|Stock|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV Non-ACC 2017">Buy Here</a></sub></details>|||
|Chevrolet|Bolt EV Non-ACC 2018-21|Adaptive Cruise Control (ACC)|Stock|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Bolt EV Non-ACC 2018-21">Buy Here</a></sub></details>|||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Equinox 2019-22">Buy Here</a></sub></details>|||
|Chevrolet|Malibu Non-ACC 2016-23|Adaptive Cruise Control (ACC)|Stock|24 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Malibu Non-ACC 2016-23">Buy Here</a></sub></details>|||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Silverado 1500 2020-21">Buy Here</a></sub></details>|||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Chevrolet Trailblazer 2021-22">Buy Here</a></sub></details>|||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Chrysler Pacifica 2017-18">Buy Here</a></sub></details>|||
@@ -236,20 +239,20 @@ A supported vehicle is one that just works when you install a comma device. All
|Rivian|R1T 2022-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Rivian A connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Rivian R1T 2022-24">Buy Here</a></sub></details>||<a href="https://youtu.be/uaISd1j7Z4U" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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|Forester 2017-18|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Forester 2017-18">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>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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|Impreza 2017-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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 2015-18|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Legacy 2015-18">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 2019-21|All[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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|Forester 2017-18|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Forester 2017-18">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>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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|Impreza 2017-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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 2015-18|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Legacy 2015-18">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>8</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 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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 2015-17|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 2015-17">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 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 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>|||
|Subaru|Outback 2015-17|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 2015-17">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 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Subaru Outback 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>|||
|Subaru|Outback 2020-22|All[<sup>8</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 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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|XV 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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>|||
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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>8</sup>](#footnotes)|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<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>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Fabia 2022-23">Buy Here</a></sub></details>[<sup>17</sup>](#footnotes)|||
|Škoda|Kamiq 2021-23[<sup>13,15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Kamiq 2021-23">Buy Here</a></sub></details>[<sup>17</sup>](#footnotes)|||
|Škoda|Karoq 2019-23[<sup>15</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Škoda Karoq 2019-23">Buy Here</a></sub></details>|||
@@ -308,7 +311,6 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|RAV4 Hybrid 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 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|RAV4 Hybrid 2023-25|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 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2023-25">Buy Here</a></sub></details>|<a href="https://youtu.be/4eIsEq4L4Ng" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|Wildlander PHEV 2021|All|openpilot|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Wildlander PHEV 2021">Buy Here</a></sub></details>|||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
-36
View File
@@ -1,36 +0,0 @@
# Safety
openpilot is an Adaptive Cruise Control (ACC) and Automated Lane Centering (ALC) system.
Like other ACC and ALC systems, openpilot is a failsafe passive system and it requires the
driver to be alert and to pay attention at all times.
In order to enforce driver alertness, openpilot includes a driver monitoring feature
that alerts the driver when distracted.
However, even with an attentive driver, we must make further efforts for the system to be
safe. We repeat, **driver alertness is necessary, but not sufficient, for openpilot to be
used safely** and openpilot is provided with no warranty of fitness for any purpose.
openpilot is developed in good faith to be compliant with FMVSS requirements and to follow
industry standards of safety for Level 2 Driver Assistance Systems. In particular, we observe
ISO26262 guidelines, including those from [pertinent documents](https://www.nhtsa.gov/sites/nhtsa.dot.gov/files/documents/13498a_812_573_alcsystemreport.pdf)
released by NHTSA. In addition, we impose strict coding guidelines (like [MISRA C : 2012](https://www.misra.org.uk/what-is-misra/))
on parts of openpilot that are safety relevant. We also perform software-in-the-loop,
hardware-in-the-loop and in-vehicle tests before each software release.
Following Hazard and Risk Analysis and FMEA, at a very high level, we have designed openpilot
ensuring two main safety requirements.
1. The driver must always be capable to immediately retake manual control of the vehicle,
by stepping on the brake pedal or by pressing the cancel button.
2. The vehicle must not alter its trajectory too quickly for the driver to safely
react. This means that while the system is engaged, the actuators are constrained
to operate within reasonable limits[^1].
For additional safety implementation details, refer to [panda safety model](https://github.com/commaai/panda#safety-model). For vehicle specific implementation of the safety concept, refer to [panda/board/safety/](https://github.com/commaai/panda/tree/master/board/safety).
**Extra note**: comma.ai strongly discourages the use of openpilot forks with safety code either missing or
not fully meeting the above requirements.
[^1]: For these actuator limits we observe ISO11270 and ISO15622. Lateral limits described there translate to 0.9 seconds of maximum actuation to achieve a 1m lateral deviation.
-3
View File
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:675116a9b50eb713b2266396aff1460eed8263738455b1d49365f48168b4d4f9
size 1698
-13
View File
@@ -1,13 +0,0 @@
# Definitions
| Branch | Definition | Supported Devices | Description | Stability/Readiness |
|:--------------:|------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---|
| `release` | Release branch | Comma 3X | Stable release branch. After testing on `staging`, updates are pushed here and published publicly. | **Ready to Use:** Highly stable, recommended for most users. |
| `staging` | Staging branch | Comma 3X | Pre-release testing branch. Community feedback is essential to identify issues before public release. | **Varied Stability:** Generally stable, but intended for testing before public release. |
| `dev` | Development branches | Comma 3X | Experimental branch with the latest features and bug fixes brought in manually. Expect bugs and braking changes. | **Experimental:** Least stable, suitable for testers and developers. |
| `master` | Primary development branch | Comma 3X | All Pull Requests are merged here for future releases. CI automatically strips, minifies, and pushes changes to `staging`. Running the `master` branch is suitable for development purposes but not recommended for non-development use. | **For Development Use:** Suitable for developers, may be unstable for general use. |
| `release-tici` | Release branch | Comma 3 | Stable release branch. After testing on `staging-tici`, updates are pushed here and published publicly. | **Ready to Use:** Highly stable, recommended for most users. |
| `staging-tici` | Staging branch | Comma 3 | Pre-release testing branch. Community feedback is essential to identify issues before public release. | **Varied Stability:** Generally stable, but intended for testing before public release. |
!!! tip
Your feedback is invaluable. Testers, even without software development experience, are encourage to run `dev` or `staging` and report issues.
-17
View File
@@ -1,17 +0,0 @@
# Recommended Branches
=== "Comma 3X"
| Branch | Installation URL | Change Logs |
|:---------:|----------------------------------- |---------------------------------------------------------------------------------|
| `release` | **Coming Soon** | **Coming Soon** |
| `staging` | [install.sunnypilot.ai/staging]() | [CHANGELOG](https://github.com/sunnyhaibin/sunnypilot/blob/staging/RELEASES.md) |
| `dev` | [install.sunnypilot.ai/dev]() | [CHANGELOG](https://github.com/sunnyhaibin/sunnypilot/blob/dev/RELEASES.md) |
=== "Comma 3"
| Branch | Installation URL | Change Logs |
|:---------:|--------------------------------------- |---------------------------------------------------------------------------------|
| `release-tici` | **Coming Soon** | **Coming Soon** |
| `staging-tici` | [install.sunnypilot.ai/staging-tici]() | [CHANGELOG](https://github.com/sunnyhaibin/sunnypilot/blob/staging/RELEASES.md) |
-68
View File
@@ -1,68 +0,0 @@
# How to contribute
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about open-sourcing and externalization](https://www.sunnypilot.ai/blog/july/a-new-chapter-transparency/). Development activity is coordinated through our [GitHub Issues](https://github.com/sunnypilot/sunnypilot/issues), [GitHub Discussions](https://github.com/sunnypilot/sunnypilot/discussions), and [Discord](https://discord.sunnypilot.ai).
### Getting Started
* Setup your [development environment](https://github.com/sunnypilot/sunnypilot/tree/master/tools)
* Read about the [development workflow](WORKFLOW.md)
* Join our [Discord](https://discord.sunnypilot.ai)
* Docs are at [https://docs.sunnypilot.ai](https://docs.sunnypilot.ai) and [https://www.sunnypilot.ai/blog](https://www.sunnypilot.ai/blog)
## What contributions are we looking for?
**sunnypilot's priorities are [safety](../SAFETY.md), stability, quality, and features, in that order.** Aligning with comma's ideals, part of sunnypilot's mission is to *solve self-driving cars while delivering shippable intermediaries*, and **all** development is towards that goal.
### What gets merged?
The probability of a pull request being merged is a function of its value to the project and the effort it will take us to get it merged.
If a PR offers *some* value but will take lots of time to get merged, it will be closed.
Simple, well-tested bug fixes are the easiest to merge, and new features are the hardest to get merged.
All of these are examples of good PRs:
* [typo fix](https://github.com/commaai/openpilot/pull/30678)
* [removing unused code](https://github.com/commaai/openpilot/pull/30573)
* [simple car model port](https://github.com/commaai/openpilot/pull/30245)
* [car brand port](https://github.com/commaai/openpilot/pull/23331)
* [UI design changes](https://github.com/sunnypilot/sunnypilot/commit/84f6fce90639135611ec568c4d39a352a300bede)
* [new features](https://github.com/sunnypilot/sunnypilot/commit/68e1379003bfdb599921cf9cd5684bfb762fd676)
### What doesn't get merged?
* **arbitrary style changes**: code is art, and it's up to the author to make it beautiful
* **500+ line PRs**: clean it up, break it up into smaller PRs, or both
* **PRs without a clear goal**: every PR must have a singular and clear goal
### First contribution
Check out any [good first issue from commaai's openpilot](https://github.com/commaai/openpilot/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) to get started.
### What do I need to contribute?
A lot of sunnypilot work requires only a PC, and some requires a comma device.
Most car-related contributions require access to that car, plus a comma device installed in the car.
## Pull Requests
Pull requests should be against the [`master`](https://github.com/sunnypilot/sunnypilot) branch. If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.
A good pull request has all of the following:
- a clearly stated purpose
- every line changed directly contributes to the stated purpose
- verification, i.e. how did you test your PR?
- justification
* if you've optimized something, post benchmarks to prove it's better
* if you've improved your car's tuning, post before and after plots
- passes the CI tests
## Contributing without Code
* Report bugs in [GitHub issues](https://github.com/sunnypilot/sunnypilot/issues).
* Report driving issues in the `#general` Discord channel.
* Consider opting into driver camera uploads to improve the driver monitoring model.
* Connect your device to Wi-Fi regularly, so that comma can pull data for training better driving models.
* Run the `staging-c3` branch and report issues. This branch is like `master` but it's built just like a release.
-43
View File
@@ -1,43 +0,0 @@
# sunnypilot development workflow
Aside from the ML models, most tools used for sunnypilot development are in this repo.
Most development happens on normal Ubuntu workstations, and not in cars or directly on comma devices. See the [setup guide](https://github.com/sunnypilot/sunnypilot/tree/master/tools) for getting your PC setup for sunnypilot development.
## Quick start
```bash
# get the latest stuff
git pull
git lfs pull
git submodule update --init --recursive
# update dependencies
tools/ubuntu_setup.sh
# build everything
scons -j$(nproc)
# build just the ui with either of these
scons -j8 selfdrive/ui/
cd selfdrive/ui/ && scons -u -j8
# test everything
pytest
# test just logging services
cd system/loggerd && pytest .
# run the linter
op lint
```
## Testing
### Automated Testing
All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.
### Code Style and Linting
Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
-274
View File
@@ -1,274 +0,0 @@
# Bug Reports
sunnypilot is an actively maintained project that we constantly strive to improve. With project of this size and complexity,
bugs may occur. If you think you have discovered a bug, you can help us by submitting an issue
in [comma's public issue tracker][comma's issue tracker],
[sunnypilot's public issue tracker][sunnypilot's issue tracker] or on our [Discord][discord], following this guide.
[comma's issue tracker]: https://github.com/commaai/openpilot/issues
[sunnypilot's issue tracker]: https://github.com/sunnypilot/sunnypilot/issues
[discord]: https://discord.sunnypilot.ai
## Before creating an issue
With more than 2,500 users, issues are created frequently. The maintainers of this project are trying very hard to keep
the number of open issues and reports down by fixing bugs as fast as possible. By following this guide, you will know
exactly what information we need to help you quickly.
**But first, please do the following things before creating an issue.**
### Upgrade to the latest version
Chances are that the bug you discovered was already fixed in a subsequent version. Thus, before reporting an issue,
ensure that you're running the [latest release version](https://github.com/sunnypilot/sunnypilot/releases) of sunnypilot.
Please consult our [installation guide](../setup/read-before-installing.md) to learn how to upgrade to the latest version.
!!! warning "Bug fixes are not backported"
Please understand that only bugs that occur in the latest version of sunnypilot will be addressed. Also, to reduce
duplicate efforts, fixes cannot be backported to earlier versions.
### Remove customizations
If you're using customized features, such as your own tweaks of the features, please remove them from the branch
you are testing from before reporting a bug. We can't offer official support for bugs that might hide in your implementations,
so make sure to omit any customizations from the version being tested.
If, after removing the customizations, the bug is gone, the bug is likely caused by your customizations. A good idea is
to add them back gradually to narrow down the root cause of the problem If you did a major version upgrade, make sure
you adjusted all customizations you have implemented.
!!! tip
If you are an advanced user, you could also utilize `git bisect`
to perform a binary search in the history to find a particular regression.
!!! warning "Customizations mentioned in our documentation"
A handful of the features sunnypilot offers can only be implemented with customizations. if you find a bug in any of
the customizations that our documentations explicitly mentioned, you are, of course, encouraged to report it.
**Don't be shy to ask on our [Discord][discord] for help if you run into problems.**
### Search for solutions
At this stage, we know that the problem persists in the latest version and is not caused by any of your customizations.
However, the problem might result from a small typo or a syntactical error in the source code, e.g., `selfdrive/car/interfaces.py`.
Now, before you go through the trouble of creating a bug report that is answered and closed right away with a link to
the relevant documentation section or another already reported or closed issue or discussion, you can save time for us
and yourself by doing some research:
1. [Search our documentation] and look for the relevant sections that could be related to your problem. If found, make
sure that the settings are configured correctly.
2. [Search our Discord][discord] to learn if other users are struggling with similar problems and work together with
our
great community towards a solution. Many problems are solved there.
3. [Search comma's openpilot issue tracker][comma's issue tracker], as another user might
already have reported the same problem that may exist in
stock openpilot, and there might even be a known workaround or fix for it. Thus, no need to create a new issue.
4. [Search sunnypilot's issue tracker][sunnypilot's issue tracker], as another user might already have
reported the same problem, and there
might even be a known workaround or fix for it. Thus, no need to create a new issue.
[Search our documentation]: ?q=
**Keep track of all <u>search terms</u> and <u>relevant links</u>, you'll need them in the bug report.**[^1]
[^1]:
We might be using terminology in our documentation different from yours, but we mean the same. When you include the
search terms and related links in your bug report, you help us to adjust and improve the documentation.
---
At this point, when you still haven't found a solution to your problem, we encourage you to report the issue on our
[Discord][discord] because it's now very likely that you stumbled over something we don't know
yet. Read the following section
to learn how to create a complete and helpful bug report.
## Issue template
We have created an issue template to make the bug reporting process as simple as possible, and more efficient for our
community and us.
- [Title]
- [Context]<small>optional</small>
- [Bug description]
- [Related links]
- [Reproduction]
- [Steps to reproduce]
- [Checklist]
[Title]: #title
[Context]: #context
[Bug description]: #bug-description
[Related links]: #related-links
[Reproduction]: #reproduction
[Steps to reproduce]: #steps-to-reproduce
[Checklist]: #checklist
### Title
A good title is short and descriptive. It should be a one-sentence executive summary of the issue, so the impact and
severity of the bug you want to report can be inferred from the title.
| <!-- --> | Example |
| -------- |--------------------------------------------------------------------------------------------------------------|
| :material-check:{ style="color: #4DB6AC" } __Clear__ | Speed Limit Control (SLC) stuck in `preActive` when engaged |
| :material-close:{ style="color: #EF5350" } __Wordy__ | The Speed Limit Control (SLC) remains in the `preActive` state when longitudinal it's supposed to be engaged |
| :material-close:{ style="color: #EF5350" } __Unclear__ | SLC does not work |
| :material-close:{ style="color: #EF5350" } __Useless__ | Help |
### Context <small>optional</small> { #context }
Before describing the bug, you can provide additional context for us to understand what you were trying to achieve.
Explain the circumstances in which you're using sunnypilot, and what you _think_ might be relevant. Don't write
about the bug here.
!!! note "__Why this might be helpful__"
Some errors only manifest in specific settings, environments or edge cases, for example, when the feature is not available
to certain cars.
### Bug description
Now, to the bug you want to report. Provide a clear, focused, specific, and concise summary of the bug you encountered.
Explain why you think this is a bug that should be reported to sunnypilot, and not to one of its dependencies.[^3]
Adhere to the following principles:
[^3]:
Sometimes, users report bugs on our [sunnypilot's issue tracker] or [Discord][discord]
that are caused by one of our upstream dependencies, including [comma's openpilot], [comma's panda],
or other openpilot forks' dependencies. A good rule of thumb is
to reproduce the issue with stock openpilot in the same conditions and
check if the problem persists. If it does, the problem is likely not
related to sunnypilot and should be reported upstream. When in
doubt, use our [Discord][discord] to ask for help.
[comma's openpilot]: https://github.com/commaai/openpilot
[comma's panda]: https://github.com/commaai/panda
- __Explain the <u>what</u>, not the <u>how</u>__ don't explain
[how to reproduce the bug][Steps to reproduce] here, we're getting there.
Focus on articulating the problem and its impact as clearly as possible.
- __Keep it short and concise__ if the bug can be precisely explained in one
or two sentences, perfect. Don't inflate it maintainers and future users
will be grateful for having to read less.
- __One bug at a time__ if you encounter several unrelated bugs, please
create separate issues for them. Don't report them in the same issue, as
this makes attribution difficult.
---
:material-run-fast: __Stretch goal__ if you found a workaround or a way to fix
the bug, you can help other users temporarily mitigate the problem before
we maintainers can fix the bug in our code base.
!!! note "__Why we need this__"
In order for us to understand the problem, we need a clear description of it and quantify its impact, which is
essential for triage and prioritization.
### Related links
Of course, prior to reporting a bug, you have read our documentation and
[could not find a working solution][search for solutions]. Please share links
to all sections of our documentation that might be relevant to the bug, as it
helps us gradually improve it.
Additionally, since you have searched [comma's issue tracker], [sunnypilot's issue tracker] or [Discord][discord]
before reporting an issue, and have possibly found several issues or
discussions, include those as well. Every link to an issue or discussion creates
a backlink, guiding us maintainers and other users in the future.
---
:material-run-fast: __Stretch goal__ if you also include the search terms you
used when [searching for a solution][search for solutions] to your problem, you
make it easier for us maintainers to improve the documentation.
[search for solutions]: #search-for-solutions
### Reproduction
A minimal reproduction is at the heart of every well-written bug report, as
it allows us maintainers to instantly recreate the necessary conditions to
inspect the bug to quickly find its root cause. It's a proven fact that issues
with concise and small reproductions can be fixed much faster.
After you have created the reproduction, take note of your <u>__comma Dongle ID__</u>. It will be used during the bug
report.
!!! note "__Why we need this__"
If an issue contains no minimal reproduction or just a link to a repository with thousands of files, the
maintainers would need to invest a lot of time into trying to recreate the right conditions to even inspect the
bug, let alone fix it.
!!! warning "Don't share links to repositories"
While we know that it is a good practice among developers to include a link
to a repository with the bug report, we currently don't support those in our
process. The reason is that the reproduction, which is automatically
produced by the <u>__route ID__</u> contains all the necessary
environment information that is often forgotten to be included.
Additionally, there are many non-technical users of sunnypilot that
have trouble creating repositories.
### Steps to reproduce
At this point, you provided us with enough information to understand the bug
and provided us with a reproduction that we could run and inspect. However, when
we check your reproduction, it might not be immediately apparent how we can see
the bug in action.
Thus, please list the specific steps we should follow when running your
reproduction to observe the bug. Keep the steps short and concise, and make sure
not to leave anything out. Use simple language as you would explain it to a
five-year-old, and focus on continuity.
!!! note "__Why we need this__"
We must know how to navigate your reproduction in order
to observe the bug, as some bugs only occur at certain viewports or in
specific conditions.
### Uploading logs and preserving routes
After reproducing the bug, please follow these steps to upload the necessary logs and preserve the routes.
1. Ensure the route is fully uploaded at [comma Connect]. We cannot look
into issues without routes, or at least a comma Dongle ID.
1. Visit [comma Connect], select the route with the issue reproduced.
2. Under the "Files" button, locate "All logs". Click "Upload x files".
3. View the upload queue, and confirm that all raw logs are uploaded.
!!! note
Sometimes when the qlogs of the route are still being uploaded, some raw logs may not be available to
request for upload. Refresh the page a few times once you have confirmed all qlogs have been uploaded,
then try to upload all raw logs again if available.
2. Share your Dongle ID with sunnypilot on [comma Connect].
1. Visit [comma Connect], navigate to the gear icon.
2. Select "Share by email", and enter `support@sunnypilot.ai`.
3. Confirm the sharing by clicking the share icon again.
4. Set the device name to your vehicle's year/make/model and your Discord username, so it can be easily identified.
3. Once all raw logs are uploaded, click "More info" and enable the "Preserved" option to preserve the route.
4. Attach the route ID in your issue submission.
[comma Connect]: https://connect.comma.ai
### Checklist
Thanks for following the guide and creating a high-quality and complete bug
report you are almost done. The checklist ensures that you have read this guide
and have worked to your best knowledge to provide us with everything we need to
know to help you.
- [ ] I have upgraded to the latest release version of sunnypilot.
- [ ] I have removed or disable any customizations and confirmed the bug persists.
- [ ] I have searched the documentation, issue trackers, and Discord for similar issues.
- [ ] I have created a minimal reproduction and noted my comma Dongle ID.
- [ ] I have shared my Dongle ID with sunnypilot at `support@sunnypilot.ai`.
- [ ] I have filled out all required sections of the issue template.
- [ ] I have followed this guide and ensured all necessary information is included.
__We'll take it from here.__
@@ -1,97 +0,0 @@
# Documentation issues
Our documentation is composed of many pages and includes extensive
information on features, configurations, customizations, and much more. If you
have found an inconsistency or see room for improvement, please follow this
guide to submit an issue on our [issue tracker].
[issue tracker]: https://github.com/sunnypilot/sunnypilot/issues
## Issue template
Reporting a documentation issue is usually less involved than reporting a bug.
Please thoroughly read this guide before creating a new documentation issue,
and provide the following information as part of the issue:
- [Title]
- [Description]
- [Related links]
- [Proposed change] <small>optional</small>
- [Checklist]
[Title]: #title
[Description]: #description
[Related links]: #related-links
[Proposed change]: #proposed-change
[Checklist]: #checklist
### Title
A good title should be a short, one-sentence description of the issue, contain
all relevant information and, in particular, keywords to simplify the search in
our issue tracker.
| <!-- --> | Example |
| -------- | -------- |
| :material-check:{ style="color: #4DB6AC" } __Clear__ | Clarify Speed Limit Control engagement
| :material-close:{ style="color: #EF5350" } __Unclear__ | Missing information in the docs
| :material-close:{ style="color: #EF5350" } __Useless__ | Help
### Description
Provide a clear and concise summary of the inconsistency or issue you
encountered in the documentation or the documentation section that needs
improvement. Explain why you think the documentation should be adjusted and
describe the severity of the issue:
- __Keep it short and concise__ if the inconsistency or issue can be
precisely explained in one or two sentences, perfect. Maintainers and future
users will be grateful for having to read less.
- __One issue at a time__ if you encounter several unrelated inconsistencies,
please create separate issues for them. Don't report them in the same issue
it makes attribution difficult.
!!! note "__Why we need this__"
Describing the problem clearly and concisely is a prerequisite for improving
our documentation we need to understand what's wrong, so we can fix it.
### Related links
After you described the documentation section that needs to be adjusted above,
we now ask you to share the link to this specific documentation section and
other possibly related sections. Make sure to use anchor links (permanent links)
where possible, as it simplifies discovery.
!!! note "__Why we need this__"
Providing the links to the documentation help us understand which sections
of our documentation need to be adjusted, extended, or overhauled.
### Proposed change <small>optional</small> { #proposed-change }
Now that you have provided us with the description and links to the
documentation sections, you can help us, maintainers, and the community by
proposing an improvement. You can sketch out rough ideas or write a concrete
proposal. This field is optional but very helpful.
!!! note "__Why we need this__"
An improvement proposal can be beneficial for other users who encounter
the same issue, as they offer solutions before we maintainers can update
the documentation.
### Checklist
Thanks for following the guide and providing valuable feedback for our
documentation you are almost done. The checklist ensures that you have read
this guide and have worked to your best knowledge to provide us with every piece
of information we need to improve it.
- [ ] I have provided a clear and descriptive title for the documentation issue.
- [ ] I have summarized the inconsistency or issue concisely in the description.
- [ ] I have included links to the specific documentation section(s) that need
adjustments.
- [ ] (Optional) I have proposed a change or improvement to the documentation.
- [ ] I have followed this guide and ensured all necessary information is included.
__We'll take it from here.__
-24
View File
@@ -1,24 +0,0 @@
---
title: Auto Lane Change
description: Detailed documentation on the Auto Lane Change feature in sunnypilot.
---
# Auto Lane Change
sunnypilot's Auto Lane Change feature allows the vehicle to automatically change lanes.
## Key Setting and How to Use
- **Nudge to Confirm:** This is the default method. To perform a lane change, activate the turn signal in the desired direction and then gently turn the steering wheel (nudges) in the same direction to confirm the maneuver.
- **Nudge-less Lane Change:** For a more automated experience, users can enable a "nudge-less" option. With this setting, you only need to activate the turn signal to initiate a lane-change.
- **Nudge-less with Delay** This is same as Nudge-less mode, but with a fixed delay. Once the turn-indicator is activated, sunnypilot will wait for the selected delay before initiating the lane change.
### Additional Related Settings
- **Delay with Blind Spot:** This crucial safety feature adds a delay to the lane change if the vehicle's blind spot monitoring (BSM) system detects an object. The lane change will only proceed after the blind spot is clear.
## Important Considerations
- **Manual Override:** The driver can regain control at any time by taking control of the steering wheel.
- **Driver Monitoring:** sunnypilot utilizes driver monitoring to ensure the driver remains attentive.
- **Object Detection:** The system is primarily designed to follow lane lines and may not detect all objects. The driver must always be prepared to take control.
- **Lane Markings:** The feature's performance is dependent on clear and visible lane markings.
-13
View File
@@ -1,13 +0,0 @@
---
title: Custom ACC Increments
description: Detailed documentation on the Custom ACC Increments feature in sunnypilot.
---
# Custom ACC Increments
sunnypilot offers customization to the set speed increments for Adaptive Cruise Control (ACC) when sunnypilot is controlling the vehicle's longitudinal control. This allows for more precise speed adjustments compared to the default behavior of many vehicles.
- **Short press**: This controls the speed adjustment when the "RES+" or "SET-" button is pressed for a short period of time.
- Allowed values: 1 through 10
- **Long press**: This controls the speed adjustment when the "RES+" or "SET-" button is pressed for a longer duration.
- Allowed values: 1, 5, 10
@@ -1,14 +0,0 @@
---
title: Dynamic Experimental Control
description: Detailed documentation on the Dynamic Experimental Control feature in sunnypilot.
---
# Dynamic Experimental Control (DEC)
Dynamic Experimental Control (DEC) intelligently switches between the standard adaptive cruise control (ACC) and the end-to-end longitudinal control of Experimental Mode based on the driving conditions.
**Chill Mode** is the standard adaptive cruise control method. It is designed to provide a smooth, predictable driving experience. However, it does not provide advanced driving capabilities like stopping at red lights and stop signs.
**Experimental Mode** allows the system to control the vehicle's speed and tries to drive like a human, enabling it to slow down for turns, stop at red lights, and stop signs. While capable and experimental, this mode can sometimes be overly cautious, especially on highways.
***Dynamic Experimental Control*** aims to provide the best of both worlds: the advanced capabilities of Experimental Mode when needed, and the smooth, predictable behavior of the standard system for less complex driving scenarios. This allows for a more natural driving experience by using Experimental Mode in situations where it excels, such as city driving and tight turns, while reverting to the default behavior for highway driving.
@@ -1,97 +0,0 @@
# **How custom longitudinal tuning works for Hyundai/Kia/Genesis vehicles in sunnypilot.**
To begin this documentation, I would like to first present the safety guidelines followed to create the tune:
Our main safety guideline considered is [ISO 15622:2018](https://www.iso.org/obp/ui/en/#iso:std:iso:15622:ed-3:v1:en)
This provides the groundwork of safety limits this tune must adhere too, and therefore, must be followed.
For example, in our jerk calculations throughout this tune, you will see how maximum jerk is clipped using the equation provided.
In the tuning you will see a set of equations, the first being jerk, **but what exactly is jerk?**
Jerk is calculated by taking current acceleration (in the form of m/s^2), subtracting that by previous acceleration, and
dividing that by time. In our tune you will see the following equation:
planned_accel = CC.actuators.accel
current_accel = CS.out.aEgo
blended_value = 0.67 * planned_accel + 0.33 * current_accel
delta = blended_value - self.state.accel_last_jerk
self.state.jerk = math.copysign(delta * delta, delta)
self.state.accel_last_jerk = blended_value
Instead of using a hardcoded time, we are focused on making jerk parabolic. First we have our planned acceleration from longitudinal_planner.
Then we have our current carstate acceleration. These are then blended together 67:33 = 100% to form our blended value.
Following this, we have our delta which subtracts our blended_value from our previous acceleration `self.state.accel_last_jerk`
Lastly, we have our finalized jerk calculation, which squares the delta to create a parabolic response while retaining the original sign,
which could be positive or negative (e.g., 5.0 or -5.0). This then goes through our minimum and maximum clipping
which forces a value between our set min and max, which I discuss later in this readme.
Moving on, the accel_last_jerk, stores current accel after each iteration and uses that in the calculation as previous accel for
our jerk calculations. Now we see the calculation of jerk max and jerk min.
### Let's dive into how jerk lower limit max is calculated:
velocity = CS.out.vEgo
if velocity < 5.0:
decel_jerk_max = self.car_config.jerk_limits[1]
elif velocity > 20.0:
decel_jerk_max = 2.5
else:
decel_jerk_max = 3.64284 - 0.05714 * velocity
This equation above is set by ISO 15622, and dictates that jerk lower limit can only be five when below 5 m/s. In our equation,
self.car_config.jerk_limits[1]
Jerk_limits[1] represents a jerk value of 3.3 m/s^3, which is the maximum analyzed lower jerk rate seen on stock SCC CAN.
Between 5 m/s and 20 m/s jerk is capped using the calculation:
decel_jerk_max = 3.64284 - 0.05714 * velocity
This equation calculates the linear jerk from 6m/s to 19m/s, scaling down from 3.3 to 2.5 m/s^3.
This means that if current velocity is say, 15 m/s the final jerk max value would be capped at 2.78 m/s^3.
Anything above 20 m/s is capped to a lower jerk max of 2.5 m/s^3. This allows for a smoother jerk range, while complying to ISO standards to a tee.
The current jerk Lower Limit you will see in openpilot before this tune, is 5.0 m/s^3; Which as you can see from using the above calculation,
the 5.0 m/s^3 technically does not comply with ISO standards at any speed above 5.0 m/s^3.
Having our jerk max be clipped to these values not only allows for better consistency with ISO standards,
but also enables us to have a much smoother braking experience.
### Getting into our next topic, I would like to explain how our minimum jerk was chosen.
Minimum jerk was chosen based off of the following guideline proposed by Handbook of Intellegent Vehicles (2012):
`Ride comfort may be sacrificed only under emergency conditions when vehicle and occupant safety consideration may preclude comfort.`
### What the value of 0.53 m/s^3 of the jerk lower limit was chosen based off of
[Carlowitz et al. (2024).](https://www.researchgate.net/publication/382274551_User_evaluation_of_comfortable_deceleration_profiles_for_highly_automated_driving_Findings_from_a_test_track_study)
This research study identified the average lower jerk used in comfortable driving settings, which is 0.53 m/s^3.
This is then inputted to jerk_limits[0] as 0.53 m/s^3 represents the value used in upper jerk absolute minimum.
min_lower_jerk = self.car_config.jerk_limits[0]
As shown above, lower jerk minimum of 0.53 is used for our lower_jerk minimum bounds.
### Why our minimum upper jerk is conditional
Our minimum upper band jerk is conditional as well and is denoted below:
min_upper_jerk = self.car_config.jerk_limits[0] if (velocity > 3.611) else 0.60
This means that for speeds under 3.611 m/s (8.077 mph/ 13 kph) we have a minimum jerk of 0.60. This allows for smooth
takeoffs while not causing lag. For all other speeds, we use our normal jerk_limit for minimum, which is 0.53.
### Next, we have our acceleration limiting
For acceleration limiting, we use TCS signal brakeLightsDEPRECATED to measure when to enact the standstill delay
which stock SCC uses to allow smoother transitions in acceleration.
### Lastly, we have our accel value calculations for hyundaican.py
For our accel value calculations we have the following:
`self.accel_value = np.clip(self.accel_raw, self.state.accel_last - jerk_number, self.state.accel_last + jerk_number)`
This essentially means that we have our accel_raw, which is acceleration (m/s^2), followed by our clipping variables.
jerk_number in this equation represents exactly `0.1`, which is subtracted or added by self.state.accel_last, which is
previous calculated accel_value. Furthermore, we have `self.state.accel_last`, which is calculated as the stored accel from
the above calculations.
-17
View File
@@ -1,17 +0,0 @@
---
title: ICBM (Intelligent Cruise Button Management)
description: Detailed documentation on the ICBM feature in sunnypilot.
---
# ICBM (Intelligent Cruise Button Management)
Intelligent Cruise Button Management (ICBM) is a system designed to manage the vehicle's cruise control set speed by sending cruise control button commands via CAN bus to the car.
ICBM is particularly useful in vehicles openpilot Longitudinal Control is not available or not desirable to use. By simulating button presses to adjust the stock cruise control set speed, sunnypilot's ICBM can manage the car's speed while keeping native safety features active, such as Forward Collision Warning (FCA) and Automatic Emergency Braking (AEB).
ICBM also allows the vehicle to use the following features:
- **[Smart Cruise Control - Vision (SCC-V)]()**
- **[Smart Cruise Control - Map (SCC-M)]()**
- **[Speed Limit Assist (SLA)]()**
- **[Custom ACC Increments]()**
-17
View File
@@ -1,17 +0,0 @@
# Modular Assistive Driving System (M.A.D.S.)
Modular Assistive Driving System (MADS) aims to elevate the user's driving experience by modifying the behaviors of
driving assist engagements.
!!! note
This feature aligns closely with comma.ai's safety rules.
## Independent Engagement
MADS allows users to engage sunnypilot Automatic Lane Centering (ALC) for lateral control and Adaptive Cruise Control
(ACC) or Smart Cruise Control (SCC) for longitudinal control independently.
!!! note "Why This Feature Exists"
While newer car models allow for independent engagement of lateral (steering) and longitudinal (speed) control,
many older vehicle models and stock openpilot enforce engaging both controls together. MADS introduces this modern
convenience to older vehicle models, effectively backporting a feature found in newer cars and providing users more flexibility.
-15
View File
@@ -1,15 +0,0 @@
---
title: Neural Network Lateral Control (NNLC)
description: Detailed documentation on the NNLC feature in sunnypilot.
---
# Neural Network Lateral Control (NNLC)
sunnypilot's Neural Network Lateral Control (NNLC) is a feature that enhances the system's ability to steer a vehicle. It enhances the standard lateral controller with one based on a neural network trained on the vehicle's torque data, aiming for smoother and more precise steering adjustments.
## Key Aspects of NNLC
- **Improved Accuracy:** The neural network is trained using driving data specific to each vehicle, which allows for more accurate control.
- **Smoother Turns:** NNLC inputs past curvature data into its driving model to achieve smoother and more precise lateral control, especially noticeable when taking curves on a highway. Users report that it reduces the oversteering and understeering corrections.
Formerly known as "NNFF" (Neural Network Feedforward), NNLC aims to make the driving experience feel more natural and less "jittery" in turns.
-9
View File
@@ -1,9 +0,0 @@
# Smart Cruise Control - Map (SCC-M)
Smart Cruise Control - Map (SCC-M) leverages map data to proactively adjust your vehicle's speed by calculating curvature in the road ahead.
!!! note
This feature is only available when sunnypilot is actively controlling the vehicle's longitudinal control.
!!! note
This feature requires OpenStreetMap data for the current location to be downloaded.
-6
View File
@@ -1,6 +0,0 @@
# Smart Cruise Control - Vision (SCC-V)
Smart Cruise Control - Vision (SCC-V) leverages camera vision data to proactively adjust your vehicle's speed by calculating curvature in the road ahead.
!!! note
This feature is only available when sunnypilot is actively controlling the vehicle's longitudinal control.
-26
View File
@@ -1,26 +0,0 @@
---
title: Speed Limit Assist
description: Detailed documentation on the Speed Limit Assist feature in sunnypilot.
---
# Speed Limit Assist (SLA)
Speed Limit Assist (SLA) is a comprehensive framework in sunnypilot that adjusts the vehicle's set cruise speed according to detected speed limits. It reconciles data from multiple sources to determine the current speed limit.
## Core Functionality
SLA utilizes various data sources to determine the speed limit for the current road:
- **OpenStreetMap (OSM):** Utilizes map data to fetch speed limits. sunnypilot has a refactored OSM implementation for lower resource usage and provides weekly updates.
- **Car's Stock System:** On some compatible vehicles, it can pull speed limit data directly from the car's native system.
## Key Features and Customization
sunnypilot offers extensive customization for its speed control features:
- **Selectable Speed Limit Source:** Users can define the priority of data sources (e.g., OSM, Navigation, Vision) for determining the speed limit.
- **Configurable Offsets:** You can set an offset above the detected speed limit, either as a fixed value (e.g., +5 mph) or a percentage.
- **Engagement Modes:**
- **Auto:** Automatically adjusts the cruise speed when a new speed limit is detected.
- **User Confirm:** Informs the driver of the new speed limit and waits for them to confirm the change before adjusting the speed.
- **Alerts and Warnings:** The system provides alerts to inform the driver before a speed adjustment occurs.
@@ -1,9 +0,0 @@
# To start developing sunnypilot
sunnypilot is a fork of [commaai's openpilot](https://github.com/commaai/openpilot), developed by [sunnypilot](https://sunnypilot.ai) and by users like you.
We welcome both pull requests and issues on [GitHub](http://github.com/sunnypilot/sunnypilot).
* Join the [community Discord](https://discord.sunnypilot.ai)
* Check out [the contributing docs](../community/CONTRIBUTING.md)
* Check out the [openpilot tools](https://github.com/sunnypilot/sunnypilot/tree/master/tools)
* Read about the [development workflow](../community/WORKFLOW.md)
@@ -1,16 +0,0 @@
# To start using sunnypilot in a car
To use sunnypilot in a car, you need four things:
1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x).
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `release-c3.sunnypilot.ai` to install the release version.
3. **Supported Car:** Ensure that you have one of [the 275+ supported cars](https://github.com/sunnypilot/sunnypilot/blob/master/docs/CARS.md).
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car.
[comma.ai](https://comma.ai) have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup).
!!! note
It's possible to run sunnypilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play.
@@ -1,11 +0,0 @@
# What is sunnypilot?
sunnypilot is a fork of [comma.ai's openpilot](https://github.com/commaai/openpilot), an open source driver assistance system. sunnypilot offers the user a unique driving experience for over 250+ supported car makes and models with modified behaviors of driving assist engagements. sunnypilot complies with comma.ai's safety rules as accurately as possible.
## How do I use it?
sunnypilot is designed to be used on the comma 3/3X.
## How does it work?
In short, sunnypilot uses the car's existing APIs for the built-in [ADAS](https://en.wikipedia.org/wiki/Advanced_driver-assistance_system) system and simply provides better acceleration, braking, and steering inputs than the stock system.
-3
View File
@@ -1,3 +0,0 @@
The documentation here is as best-effort sync from the official https://sunnypilot.github.io/ for ease of access and for AI enhancement when users asks on the forum.
@@ -1,14 +0,0 @@
# Prohibited Safety Modifications
All [official sunnypilot branches](https://github.com/sunnyhaibin/sunnypilot/branches) strictly adhere to [comma.ai's safety policy](https://github.com/commaai/openpilot/blob/master/docs/SAFETY.md). Any changes that go against
this policy will result in your fork and your device being banned from both comma.ai and sunnypilot channels.
The following changes are **VIOLATIONS** of the safety policy and **ARE NOT** supported in any official sunnypilot branches:
!!! danger "Driver Monitoring"
- "Nerfing" or reducing monitoring parameters.
!!! danger "Panda Safety"
- No preventing disengaging of <ins>**longitudinal control**</ins> (positive/negative acceleration) on brake pedal press.
- No auto re-engaging of <ins>**longitudinal control**</ins> (positive/negative acceleration) on brake pedal release.
- No disengaging on `CRUISE MAIN` in `OFF` state.
-20
View File
@@ -1,20 +0,0 @@
# 🚨 Read Before Installing
It is recommended to read the <u>**entire documentation**</u> before proceeding. This will ensure that you fully understand each added feature in sunnypilot. This also ensures that you are choosing the correct settings and branch for your car to have the best driving experience.
!!! warning
By installing this software, you accept all responsibility for anything that might occur while you use it. sunnypilot and all contributors to sunnypilot are not liable.
**Use at your own risk.**
## Installation
Please refer to the [Recommended Branches](../branches/recommended-branches.md) to find your preferred/supported branch. This guide will assume you want to install the latest `release-c3` branch.
You can install sunnypilot on your comma 3/3X using one of the following methods:
- ### [URL Method (Directly on Device)](url-method.md)
This method allows you to install sunnypilot directly from your device's screen using a provided URL. It's simple and user-friendly, requiring no additional tools or external devices.
- ### [SSH Method (Command Line)](ssh-method.md)
This method is for advanced users who prefer to use SSH to clone the sunnypilot repository and install it manually via the command line. It offeres greater control over the installation process.
-28
View File
@@ -1,28 +0,0 @@
# SSH Method
If you are looking to install sunnypilot via SSH, run the following commands in an SSH terminal after connecting to your comma 3/3X:
1. Navigate to `data` directory
```sh
cd /data
rm -rf openpilot
```
2. Clone sunnypilot
!!! example ""
`staging` branch is used in this step as an example.
```sh
git clone -b staging --recurse-submodules https://github.com/sunnypilot/sunnypilot.git openpilot
```
3. Git LFS
```sh
cd openpilot
git lfs pull
```
4. Reboot
```sh
sudo reboot
```
-18
View File
@@ -1,18 +0,0 @@
# URL Method
The URL installation method can be done in two ways, depending on your device & if you already have sunnypilot installed.
=== "sunnypilot not installed"
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
2. After factory reset/uninstall, upon reboot, select `Custom Software` when given the option.
3. Input the **Installation URL** per [Recommended Branches](../branches/recommended-branches.md).
4. Complete the rest of the installation by following the onscreen instructions.
=== "sunnypilot already installed"
1. On the comma 3/3X, go to `Settings``Software`.
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from the sunnypilot repository on GitHub.
3. At the `Target Branch` option, press `SELECT` to open the `Target Branch` selector.
4. Scroll and select the **Desired Branch** per Recommended Branches.
-6
View File
@@ -1,6 +0,0 @@
/**
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
*
* This file is part of sunnypilot and is licensed under the MIT License.
* See the LICENSE.md file in the root directory for more details.
*/
-150
View File
@@ -1,150 +0,0 @@
site_name: sunnypilot docs
repo_name: sunnypilot/sunnypilot
repo_url: https://github.com/sunnypilot/sunnypilot/
site_description: sunnypilot Documentation
site_url: https://docs.sunnypilot.ai
edit_uri: blob/new-docs/docs_sp
exclude_docs: README.md
strict: true
docs_dir: docs_sp
site_dir: docs_sp_site/
theme:
name: material
palette:
- media: "(prefers-color-scheme)"
toggle:
icon: material/brightness-auto
name: Switch to light mode
- scheme: default
media: "(prefers-color-scheme: light)"
primary: deep purple
accent: teal
toggle:
icon: material/brightness-7
name: Switch to dark mode
- scheme: slate
media: "(prefers-color-scheme: dark)"
primary: deep purple
accent: teal
toggle:
icon: material/brightness-4
name: Switch to system preference
font:
text: Open Sans
code: Fira Code
logo: assets/sp_logo.svg
favicon: assets/sp_logo.svg
features:
- content.code.copy
- navigation.tabs
- navigation.tabs.sticky
extra_css:
- stylesheets/style.css
markdown_extensions:
- admonition
- attr_list
- def_list
- footnotes
- md_in_html
- tables
- pymdownx.details
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.magiclink:
normalize_issue_symbols: true
repo_url_shorthand: true
user: sunnypilot
repo: sunnypilot
- pymdownx.snippets
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true
- pymdownx.tasklist:
custom_checkbox: true
clickable_checkbox: true
- toc:
permalink: true
plugins:
- git-authors:
show_email_address: false
- git-committers:
repository: sunnypilot/sunnypilot
branch: master
enabled: !ENV [CI, false]
- git-revision-date-localized:
enable_creation_date: true
- search
- redirects:
redirect_maps:
'index.md': 'getting-started/what-is-sunnypilot.md'
extra:
social:
- icon: fontawesome/brands/github
link: https://github.com/sunnypilot/sunnypilot
- icon: fontawesome/brands/discord
link: https://discord.sunnypilot.ai
# analytics:
# provider: google
# property: !ENV GOOGLE_ANALYTICS_KEY
# feedback:
# title: Was this page helpful?
# ratings:
# - icon: material/emoticon-happy-outline
# name: This page was helpful
# data: 1
# note: >-
# Thanks for your feedback!
# - icon: material/emoticon-sad-outline
# name: This page could be improved
# data: 0
# note: >-
# Thanks for your feedback! Help us improve this page by
# using our <a href="..." target="_blank" rel="noopener">feedback form</a>.
nav:
- Getting Started:
- What is sunnypilot?: getting-started/what-is-sunnypilot.md
- Use sunnypilot in a car: getting-started/use-sunnypilot-in-a-car.md
- Develop sunnypilot: getting-started/develop-sunnypilot.md
- Setup:
- 🚨 Read before installing 🚨: setup/read-before-installing.md
- Installation:
- URL Method: setup/url-method.md
- SSH Method: setup/ssh-method.md
- Features:
- Auto Lane Change: features/auto-lane-change.md
- Custom ACC Increments: features/custom-acc-increments.md
- Dynamic Experimental Control: features/dynamic-experimental-control.md
- Hyundai Longitudinal Tuning: features/hyundai-longitudinal-tuning.md
- Intelligent Cruise Button Management: features/icbm.md
- Modular Assistive Driving System: features/mads.md
- Neutral Network Lateral Control: features/nnlc.md
- Smart Cruise Control - Map: features/scc-m.md
- Smart Cruise Control - Vision: features/scc-v.md
- Speed Limit - Assist: features/speed-limit-assist.md
- Community:
- Contributing: community/CONTRIBUTING.md
- Workflow: community/WORKFLOW.md
- Reporting a bug: community/reporting-a-bug.md
- Reporting a docs issue: community/reporting-a-docs-issue.md
- Discord Community: https://discord.sunnypilot.ai
- Safety Information:
- Safety: SAFETY.md
- Prohibited safety modifications: safety-information/prohibited-safety-modifications.md
- References:
- Branches:
- Recommended Branches: branches/recommended-branches.md
- Branch Definitions: branches/definitions.md
-7
View File
@@ -80,13 +80,6 @@ docs = [
"Jinja2",
"natsort",
"mkdocs",
"mkdocs-material",
"mkdocs-material-extensions",
"mkdocs-git-revision-date-localized-plugin",
"mkdocs-git-committers-plugin-2",
"mkdocs-git-authors-plugin",
"mkdocs-glightbox",
"mkdocs-redirects",
]
testing = [
+1 -1
View File
@@ -39,7 +39,7 @@ cd $BUILD_DIR
rm -f panda/board/obj/panda.bin.signed
rm -f panda/board/obj/panda_h7.bin.signed
VERSION=$(cat common/version.h | awk -F[\"-] '{print $2}')
VERSION=$(cat sunnypilot/common/version.h | awk -F[\"-] '{print $2}')
echo "[-] committing version $VERSION T=$SECONDS"
git add -f .
git commit -a -m "openpilot v$VERSION release"
+1 -1
View File
@@ -49,7 +49,7 @@ rm -f panda/board/obj/panda.bin.signed
GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD)
GIT_COMMIT_DATE=$(git --git-dir=$SOURCE_DIR/.git show --no-patch --format='%ct %ci' HEAD)
DATETIME=$(date '+%Y-%m-%dT%H:%M:%S')
VERSION=$(cat $SOURCE_DIR/common/version.h | awk -F\" '{print $2}')
VERSION=$(cat $SOURCE_DIR/sunnypilot/common/version.h | awk -F\" '{print $2}')
echo -n "$GIT_HASH" > git_src_commit
echo -n "$GIT_COMMIT_DATE" > git_src_commit_date
-5
View File
@@ -1,5 +0,0 @@
source "https://rubygems.org"
gem "faraday"
gem "faraday-retry"
gem "faraday-multipart"
gem "listen"
-112
View File
@@ -1,112 +0,0 @@
# frozen_string_literal: true
module API
def self.client
@client ||=
Faraday.new(url: DOCS_TARGET) do |conn|
conn.request :multipart
conn.request :url_encoded
conn.request :retry,
{
methods: %i[get post delete put],
retry_statuses: [429],
max: 3,
retry_block: ->(env:, options:, retry_count:, exception:, will_retry_in:) do
puts "Rate limited... will retry in #{will_retry_in}s"
end,
exceptions: [Faraday::TooManyRequestsError]
}
conn.response :json, content_type: "application/json"
conn.response :raise_error
conn.adapter Faraday.default_adapter
conn.headers["Api-Key"] = DOCS_API_KEY
end
end
def self.edit_post(post_id:, raw:, title: nil, category: nil)
if dry_run?
puts " DRY RUN: skipping PUT /posts/#{post_id}"
return
end
params = {
post: {
raw: raw,
edit_reason: "Synced from github.com/discourse/discourse-developer-docs"
}
}
params[:title] = title if title
params[:category] = category if category
client.put("/posts/#{post_id}", params)
end
def self.create_topic(external_id:, raw:, category:, title:)
if dry_run?
puts " DRY RUN: skipping POST /posts"
return
end
client.post("/posts", { title: title, raw: raw, external_id: external_id, category: category })
end
def self.trash_topic(topic_id:)
if dry_run?
puts " DRY RUN: skipping DELETE /t/#{topic_id}.json"
return
end
client.delete("/t/#{topic_id}.json")
end
def self.fetch_current_state
result =
client.post(
"/admin/plugins/explorer/queries/#{DATA_EXPLORER_QUERY_ID}/run",
{ params: { category_id: CATEGORY_ID.to_s }.to_json }
).body
raise "Data explorer query failed" if result["success"] != true
if result["columns"] != %w[t_id first_p_id external_id title raw deleted_at is_index_topic]
raise "Data explorer query returned unexpected columns: #{result["columns"].inspect}"
end
result["rows"].map do |row|
{
topic_id: row[0],
first_post_id: row[1],
external_id: row[2],
title: row[3],
raw: row[4],
deleted_at: row[5],
is_index_topic: row[6]
}
end
end
def self.restore_topic(topic_id:)
path = "/t/#{topic_id}/recover.json"
if dry_run?
puts " DRY RUN: skipping PUT #{path}"
return
end
client.put(path)
end
def self.upload_file(path)
if dry_run?
puts " DRY RUN: skipping POST /uploads.json"
return { "short_url" => "upload://placeholder" }
end
client.post(
"/uploads.json",
{ type: "composer", synchronous: true, file: Faraday::UploadIO.new(path, "image/png") }
).body
end
def self.dry_run?
[nil, true].include?(DRY_RUN)
end
end
-108
View File
@@ -1,108 +0,0 @@
# frozen_string_literal: true
Asset = Struct.new(:local_path, :local_sha1, :remote_short_url, keyword_init: true)
class LocalDoc
attr_accessor :path,
:frontmatter,
:content,
:topic_id,
:first_post_id,
:remote_content,
:remote_title,
:remote_deleted,
:assets
def initialize(**kwargs)
kwargs.each { |k, v| send("#{k}=", v) }
self.assets ||= []
end
def external_id
"DOC-#{frontmatter["id"]}"
end
def section
path_segments = path.split("/")
path_segments[0] if path_segments.size > 1
end
def content_with_uploads
unused_assets = assets.dup
result =
content.gsub(/![^\]]+\]\(([^)]+)\)/) do |match|
path = $1
next match if !path.start_with?("/")
resolved = File.expand_path("#{__dir__}/../#{path}")
assets_dir = File.expand_path("#{__dir__}/../assets/")
raise "Invalid path: #{resolved}" if !resolved.start_with?(assets_dir)
digest = Digest::SHA1.file(resolved).hexdigest
asset = assets.find { |a| a.local_sha1 == digest }
unused_assets.delete(asset)
if !asset
puts " Uploading #{path}..."
result = API.upload_file(resolved)
raise "File upload failed: #{result.inspect}" if !result["short_url"]
asset =
Asset.new(local_path: path, local_sha1: digest, remote_short_url: result["short_url"])
assets.push(asset)
end
short_url = asset.remote_short_url
match.gsub(path, short_url)
end
unused_assets.each { |asset| assets.delete(asset) }
result = <<~MD
#{result}
---
<small>This document is version controlled - suggest changes [on github](https://github.com/sunnypilot/sunnypilot/blob/master/docs_sp/#{path}).</small>
MD
if assets.size == 0
result
else
<<~MD
#{result}
<!-- START DOCS ASSET MAP
#{serialized_assets}
END DOCS ASSET MAP -->
MD
end
end
def serialized_assets
JSON.pretty_generate(
assets.map do |asset|
{
local_path: asset.local_path,
local_sha1: asset.local_sha1,
remote_short_url: asset.remote_short_url
}
end
)
end
def remote_content=(value)
if value.match(/<!-- START DOCS ASSET MAP\n(.+?)\nEND DOCS ASSET MAP -->/m)
self.assets = JSON.parse($1).map { |raw_asset| Asset.new(**raw_asset) }
end
value.gsub!(/![^\]]+\]\(([^)]+)\)/) do |match|
url = $1
found_asset = assets.find { |a| a.remote_short_url == url }
match.sub!(path, found_asset.local_path) if found_asset
match
end
@remote_content = value
end
end
-15
View File
@@ -1,15 +0,0 @@
# frozen_string_literal: true
module Util
def self.parse_md(raw)
if match = raw.match(/\A---\s*\n(.+?)\n---\n?(.*)\z/m)
raw_frontmatter, content = match.captures
frontmatter = YAML.safe_load(raw_frontmatter)
else
content = raw
frontmatter = {}
end
[frontmatter, content]
end
end
+2 -2
View File
@@ -30,7 +30,7 @@ if [ -z "$GIT_ORIGIN" ]; then
fi
# "Tagging"
echo "#define COMMA_VERSION \"$VERSION\"" > ${OUTPUT_DIR}/common/version.h
echo "#define SUNNYPILOT_VERSION \"$VERSION\"" > ${OUTPUT_DIR}/sunnypilot/common/version.h
## set git identity
#source $DIR/identity.sh
@@ -55,7 +55,7 @@ git add -f .
# include source commit hash and build date in commit
GIT_HASH=$(git --git-dir=$SOURCE_DIR/.git rev-parse HEAD)
DATETIME=$(date '+%Y-%m-%dT%H:%M:%S')
SP_VERSION=$(awk -F\" '{print $2}' $SOURCE_DIR/common/version.h)
SP_VERSION=$(awk -F\" '{print $2}' $SOURCE_DIR/sunnypilot/common/version.h)
# Commit with detailed message
git commit -a -m "sunnypilot v$VERSION
-762
View File
@@ -1,762 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require "yaml"
require "faraday"
require "faraday/retry"
require "faraday/multipart"
require "listen"
require "json"
require "digest"
CATEGORY_ID = ENV["DOCS_CATEGORY_ID"].to_i
DATA_EXPLORER_QUERY_ID = ENV["DOCS_DATA_EXPLORER_QUERY_ID"].to_i
DOCS_TARGET = ENV["DOCS_TARGET"]
DOCS_API_KEY = ENV["DOCS_API_KEY"]
GEMINI_API_KEY = ENV["GEMINI_API_KEY"]
VERBOSE = ARGV.include?("-v")
WATCH = ARGV.include?("--watch")
DRY_RUN = ARGV.include?("--dry-run")
require_relative "lib/local_doc"
require_relative "lib/api"
require_relative "lib/util"
# Gemini API client for title generation
class GeminiClient
GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent"
#GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent"
# MAX_REQUESTS_PER_MINUTE = 15
MAX_REQUESTS_PER_MINUTE = 9
RATE_LIMIT_WINDOW = 60 # seconds
def initialize(api_key)
@api_key = api_key
@request_timestamps = []
@mutex = Mutex.new
end
def generate_titles(file_path, content)
return nil unless @api_key
wait_for_rate_limit
prompt = build_prompt(file_path, content)
response = Faraday.post(
"#{GEMINI_API_URL}?key=#{@api_key}",
{ contents: [{ parts: [{ text: prompt }] }] }.to_json,
"Content-Type" => "application/json"
)
parse_response(response)
rescue => e
puts "Error calling Gemini API: #{e.message}"
nil
end
private
def wait_for_rate_limit
@mutex.synchronize do
now = Time.now
# Remove timestamps older than the rate limit window
@request_timestamps.reject! { |ts| now - ts > RATE_LIMIT_WINDOW }
# If we've hit the limit, wait until the oldest request expires
if @request_timestamps.length >= MAX_REQUESTS_PER_MINUTE
oldest_request = @request_timestamps.first
sleep_time = RATE_LIMIT_WINDOW - (now - oldest_request) + 0.1 # Add small buffer
if sleep_time > 0
puts "Rate limit reached (#{MAX_REQUESTS_PER_MINUTE}/min). Waiting #{sleep_time.round(1)}s..."
sleep(sleep_time)
# Clean up again after waiting
now = Time.now
@request_timestamps.reject! { |ts| now - ts > RATE_LIMIT_WINDOW }
end
end
# Record this request
@request_timestamps << Time.now
end
end
def build_prompt(file_path, content)
<<~PROMPT
You are helping to generate documentation metadata. Given a markdown file path and its content, generate appropriate titles.
File path: #{file_path}
Content preview:
#{content[0..500]}
Please analyze the file path and content, then provide:
1. A full title (3-8 words, descriptive and professional, MUST be at least 15 characters long)
2. A short title (1-3 words, concise, MUST be at least 15 characters long)
CRITICAL: Both titles MUST be at least 15 characters long. If a title would be shorter, expand it with relevant context.
Respond ONLY with valid JSON in this exact format:
{
"title": "Your Full Title Here",
"short_title": "Short Title Here"
}
Do not include any other text, explanation, or markdown formatting.
PROMPT
end
def parse_response(response)
body = JSON.parse(response.body)
text = body.dig("candidates", 0, "content", "parts", 0, "text")
return nil unless text
# Extract JSON from potential markdown code blocks
json_text = text.strip.gsub(/^```json\n/, "").gsub(/\n```$/, "").strip
parsed = JSON.parse(json_text)
# Validate minimum length
if parsed["title"] && parsed["title"].length < 15
parsed["title"] = parsed["title"].ljust(15)
end
if parsed["short_title"] && parsed["short_title"].length < 15
parsed["short_title"] = parsed["short_title"].ljust(15)
end
parsed
rescue => e
puts "Error parsing Gemini response: #{e.message}"
nil
end
end
# Convert MkDocs "=== Tabs" sections to Obsidian callouts
def convert_mkdocs_tabs_to_callouts(content, debug: false)
lines = content.lines
result = []
i = 0
match_count = 0
while i < lines.length
line = lines[i]
# Detect a MkDocs tab start, e.g., === "sunnypilot not installed"
if line =~ /^===\s+"([^"]+)"\s*$/
match_count += 1
tab_title = $1.strip
# Collect all indented lines following the tab
body_lines = []
i += 1
while i < lines.length
current_line = lines[i]
# Check if line is indented (4+ spaces or tab)
if current_line =~ /^(?: |\t)/
body_lines << current_line
i += 1
# Check if it's a blank line - peek ahead like we do for callouts
elsif current_line =~ /^\s*$/
peek_index = i + 1
has_more_indented = false
while peek_index < lines.length
if lines[peek_index] =~ /^(?: |\t)/
has_more_indented = true
break
elsif lines[peek_index] =~ /^\s*$/
peek_index += 1
else
break
end
end
if has_more_indented
body_lines << current_line
i += 1
else
break
end
else
# Non-indented, non-blank line (could be next tab!) - stop
break
end
end
puts "DEBUG: Tab '#{tab_title}', lines: #{body_lines.length}" if debug
# Convert the tab section to a callout
result << "> [!note] #{tab_title}\n"
body_lines.each do |body_line|
# Remove the first level of indentation (4 spaces or 1 tab) and add > prefix
stripped = body_line.sub(/^(?: |\t)/, '')
if stripped.strip.empty?
result << ">\n"
else
result << ">#{stripped}"
end
end
else
result << line
i += 1
end
end
puts "DEBUG: Total tab matches: #{match_count}" if debug
result.join
end
# New implementation of MkDocs Material callout to Obsidian converter
def convert_mkdocs_to_obsidian_callouts(content, debug: false)
# Map of MkDocs callout types to Obsidian equivalents
callout_map = {
'note' => 'note',
'tip' => 'tip',
'important' => 'important',
'warning' => 'warning',
'caution' => 'caution',
'info' => 'info',
'success' => 'success',
'question' => 'question',
'failure' => 'failure',
'danger' => 'danger',
'bug' => 'bug',
'example' => 'example',
'quote' => 'quote',
'abstract' => 'abstract',
'summary' => 'summary',
'tldr' => 'tldr'
}
lines = content.lines
result = []
i = 0
match_count = 0
while i < lines.length
line = lines[i]
# Check if this line starts a callout (can be indented or not)
# Capture any leading indentation
if line =~ /^(\s*)!!!\s+(#{callout_map.keys.map { |k| Regexp.escape(k) }.join('|')})(?:\s+"([^"]*)")?\s*$/
leading_indent = $1
mkdocs_type = $2
custom_title = $3
match_count += 1
obsidian_type = callout_map[mkdocs_type]
# Determine the base indentation level (number of spaces/tabs before !!!)
base_indent_size = leading_indent.length
# Collect all lines that have MORE indentation than the base
body_lines = []
i += 1
while i < lines.length
current_line = lines[i]
# Check if line has the required base indentation plus more (for body content)
# Body content should be indented relative to the !!! line
required_indent = leading_indent + " " # base + 4 more spaces
alt_required_indent = leading_indent + "\t" # base + 1 tab
if current_line.start_with?(required_indent) || current_line.start_with?(alt_required_indent)
body_lines << current_line
i += 1
# Check if line is blank - might be between paragraphs
elsif current_line =~ /^\s*$/
peek_index = i + 1
has_more_indented = false
while peek_index < lines.length
peek_line = lines[peek_index]
if peek_line.start_with?(required_indent) || peek_line.start_with?(alt_required_indent)
has_more_indented = true
break
elsif peek_line =~ /^\s*$/
peek_index += 1
else
break
end
end
if has_more_indented
body_lines << current_line
i += 1
else
break
end
else
# Line doesn't have required indentation - stop
break
end
end
puts "DEBUG: Match #{match_count} - indent: #{base_indent_size} spaces, type: #{mkdocs_type}, title: #{custom_title.inspect}, body lines: #{body_lines.length}" if debug
# Build the converted callout, preserving the base indentation
if body_lines.empty?
if custom_title && !custom_title.empty?
result << "#{leading_indent}> [!#{obsidian_type}] \"#{custom_title}\"\n"
else
result << "#{leading_indent}> [!#{obsidian_type}]\n"
end
else
if custom_title && !custom_title.empty?
result << "#{leading_indent}> [!#{obsidian_type}] \"#{custom_title}\"\n"
else
result << "#{leading_indent}> [!#{obsidian_type}]\n"
end
# Add > prefix to each body line, removing the extra level of indentation
body_lines.each do |body_line|
# Remove the base indent + one level (4 spaces or tab)
stripped = body_line.sub(/^#{Regexp.escape(leading_indent)}(?: |\t)/, '')
result << "#{leading_indent}>#{stripped}"
end
end
else
result << line
i += 1
end
end
puts "DEBUG: Total matches found: #{match_count}" if debug
result.join
end
# Convert MkDocs Material icons to standard emojis
def convert_material_icons_to_emojis(content)
# Map of common Material icons to emoji equivalents
icon_map = {
# Check/success icons
':material-check:' => '✅',
':material-check-circle:' => '✅',
':material-check-bold:' => '✅',
# Close/error icons
':material-close:' => '❌',
':material-close-circle:' => '❌',
':material-alert-circle:' => '⚠️',
# Info icons
':material-information:' => '️',
':material-information-outline:' => '️',
':material-help-circle:' => '❓',
# Arrow icons
':material-arrow-right:' => '→',
':material-arrow-left:' => '←',
':material-arrow-up:' => '↑',
':material-arrow-down:' => '↓',
# Other common icons
':material-lightbulb:' => '💡',
':material-star:' => '⭐',
':material-heart:' => '❤️',
':material-fire:' => '🔥',
':material-flag:' => '🚩',
':material-link:' => '🔗',
':material-pencil:' => '✏️',
':material-delete:' => '🗑️',
':material-calendar:' => '📅',
':material-clock:' => '🕐',
':material-email:' => '📧',
':material-phone:' => '📞',
}
# Replace material icons with emojis, ignoring any style attributes
icon_map.each do |material_icon, emoji|
# Match the icon with optional style attributes like { style="color: #EF5350" }
content.gsub!(/#{Regexp.escape(material_icon)}\{\s*style="[^"]*"\s*\}/, emoji)
# Also match without style attributes
content.gsub!(material_icon, emoji)
end
content
end
# Helper method to generate frontmatter from file path
def generate_frontmatter_from_path(path, content = nil, gemini_client = nil)
# Remove .md extension and get the base name
base_name = File.basename(path, ".md")
# Generate id from the full path (without extension)
# Replace / with -
# IMPORTANT: The LocalDoc#external_id method adds "DOC-" prefix (4 chars)
# So we need to limit the base ID to 46 chars to stay under the 50 char API limit
full_id = path.sub(/\.md$/, "").gsub("/", "-")
# Maximum length for the base ID (50 char API limit - 4 char "DOC-" prefix)
max_base_id_length = 46
if full_id.length > max_base_id_length
# Take first 37 chars and append an 8-char hash for uniqueness (37 + 1 dash + 8 = 46)
hash_suffix = Digest::MD5.hexdigest(path)[0..7]
id = "#{full_id[0..36]}-#{hash_suffix}"
else
id = full_id
end
# Try to use Gemini for title generation
if gemini_client && content
gemini_titles = gemini_client.generate_titles(path, content)
if gemini_titles
return {
"id" => id,
"title" => gemini_titles["title"],
"short_title" => gemini_titles["short_title"]
}
end
end
# Fallback to original logic if Gemini fails or is not available
title = base_name.split(/[-_]/).map(&:capitalize).join(" ")
short_title = base_name.split(/[-_]/).map(&:capitalize).join(" ")
# Ensure minimum length
title = title.ljust(15) if title.length < 15
short_title = short_title.ljust(15) if short_title.length < 15
{
"id" => id,
"title" => title,
"short_title" => short_title
}
end
# Helper method to generate index.md content for a folder
def generate_folder_index(folder_name)
# Convert folder name to a nice title (e.g., "my-folder" -> "My Folder")
title = folder_name.split(/[-_]/).map(&:capitalize).join(" ")
"---\ntitle: #{title}\n---\n"
end
# Convert internal markdown links (.md) to Discourse topic links
def rewrite_internal_links(content, docs)
require "uri"
content.gsub(/\]\(([^)]+\.md)(#[^)]+)?\)/) do |match|
raw_link = $1
anchor = $2 || ""
# Strip any ./ or ../ from the beginning, but preserve subfolders
normalized = raw_link.gsub(%r{^\./}, "").gsub(%r{^\.\./}, "")
# Remove trailing .md
normalized = normalized.gsub(/\.md$/, "")
# Try percent-decoding (handles %20 etc)
begin
normalized_decoded = URI.decode_www_form_component(normalized)
rescue
normalized_decoded = normalized
end
candidates = []
# Strategy 1: exact match against doc.path without .md
candidates += docs.select { |d| d.path.sub(/\.md$/, "") == normalized_decoded }
# Strategy 2: ends_with (useful if docs have a different root)
if candidates.empty?
candidates += docs.select { |d| d.path.end_with?("#{normalized_decoded}.md") }
end
# Strategy 3: match by basename (e.g., linking to index.md or same-named file in subfolder)
if candidates.empty?
basename = File.basename(normalized_decoded)
candidates += docs.select { |d| File.basename(d.path, ".md") == basename }
end
# Strategy 4: index.md handling — if link pointed to a folder/index.md, allow folder match
if candidates.empty? && normalized_decoded.end_with?("/index")
folder = normalized_decoded.sub(/\/index$/, "")
candidates += docs.select { |d| File.dirname(d.path) == folder && File.basename(d.path, ".md") == "index" }
end
# Pick the best candidate (prefer exact match)
target_doc =
if candidates.any?
# prefer exact equality if present
exact = candidates.find { |d| d.path.sub(/\.md$/, "") == normalized_decoded }
exact || candidates.first
else
nil
end
if target_doc && target_doc.topic_id
# Return a Discourse link preserving the anchor
"](/t/-/#{target_doc.topic_id}?silent=true#{anchor})"
else
if VERBOSE
puts "⚠️ rewrite_internal_links: unresolved '#{raw_link}' -> normalized='#{normalized_decoded}'"
# show up to 10 possible docs to help debugging
sample = docs.first(10).map(&:path).join(", ")
puts " sample docs: #{sample}"
end
# Return original match unchanged so the link doesn't become invalid text
match
end
end
end
# Initialize Gemini client if API key is available
gemini_client = GEMINI_API_KEY ? GeminiClient.new(GEMINI_API_KEY) : nil
if gemini_client
puts "✓ Gemini API configured for title generation"
else
puts "⚠ GEMINI_API_KEY not set - using fallback title generation"
end
docs = []
puts "Reading local docs..."
BASE = "#{__dir__}/../../docs_sp/"
# Generate index.md for each folder that doesn't have one
folders_needing_index = Set.new
Dir.glob("**/", base: BASE).each do |folder|
next if folder == "./" || folder.empty?
folder_path = folder.chomp("/")
index_path = File.join(BASE, folder_path, "index.md")
unless File.exist?(index_path)
folders_needing_index.add(folder_path)
# Get the folder name (last component of the path)
folder_name = File.basename(folder_path)
# Generate the index.md content
index_content = generate_folder_index(folder_name)
# Write the index.md file
File.write(index_path, index_content)
puts "Generated index.md for folder: #{folder_path}" if VERBOSE
end
end
puts "Generated #{folders_needing_index.size} index.md files" if folders_needing_index.any?
Dir
.glob("**/*.md", base: BASE)
.each do |path|
next if path.end_with?("index.md")
next if path.include?("SAFETY")
content = File.read(File.join(BASE, path))
frontmatter, content = Util.parse_md(content)
# Convert MkDocs Material callouts to Obsidian format
content = convert_mkdocs_tabs_to_callouts(content)
content = convert_mkdocs_to_obsidian_callouts(content)
content = convert_material_icons_to_emojis(content)
# Generate missing frontmatter fields dynamically
generated = generate_frontmatter_from_path(path, content, gemini_client)
# Apply the generated values, ensuring ID is limited to 50 chars
frontmatter["id"] = generated["id"]
frontmatter["title"] ||= generated["title"]
frontmatter["short_title"] ||= generated["short_title"]
puts "Generated frontmatter for '#{path}': id='#{frontmatter["id"]}', title='#{frontmatter["title"]}'" if VERBOSE
docs.push(LocalDoc.new(frontmatter:, path:, content:))
end
puts "Rewriting internal links..."
docs.each do |doc|
doc.content = rewrite_internal_links(doc.content, docs)
end
puts "Validating local docs..."
docs
.group_by { |doc| doc.external_id }
.each do |id, docs|
if docs.size > 1
puts "- duplicate external_id '#{id}' found in:"
docs.each { |doc| puts "- #{doc.path}" }
exit 1
end
end
exit 0 if !DOCS_API_KEY
puts "Fetching remote info via data-explorer..."
remote_topics = API.fetch_current_state
puts "Mapping to existing topics..."
map_to_remote =
lambda do
docs.each do |doc|
puts "- checking '#{doc.external_id}'..." if VERBOSE
if topic_info = remote_topics.find { |t| t[:external_id] == doc.external_id }
doc.topic_id = topic_info[:topic_id]
doc.first_post_id = topic_info[:first_post_id]
doc.remote_title = topic_info[:title]
doc.remote_content = topic_info[:raw]
doc.remote_deleted = topic_info[:deleted_at]
puts " found topic_id: #{doc.topic_id}" if VERBOSE
else
puts " not found" if VERBOSE
end
end
end
map_to_remote.call
puts "Deleting topics if necessary..."
cat_desc_topic = remote_topics.find { |t| t[:is_index_topic] }
if cat_desc_topic.nil?
puts "Docs category is missing an index topic"
exit 1
end
cat_desc_topic_id = cat_desc_topic[:topic_id]
remote_topics
.reject { |remote_doc| remote_doc[:deleted_at] }
.reject { |remote_doc| docs.any? { |doc| doc.topic_id == remote_doc[:topic_id] } }
.reject { |remote_doc| remote_doc[:topic_id] == cat_desc_topic_id }
.each do |remote_doc|
id = remote_doc[:topic_id]
puts "- deleting topic #{id}..."
API.trash_topic(topic_id: id)
end
puts "Restoring topics if necessary..."
docs
.filter(&:remote_deleted)
.each do |doc|
puts "- restoring '#{doc.external_id}'..."
API.restore_topic(topic_id: doc.topic_id)
end
puts "Creating missing topics..."
created_any = false
docs.each do |doc|
next if doc.topic_id
created_any = true
puts "- creating '#{doc.external_id} with title '#{doc.frontmatter["title"]}'..."
converted_content = convert_mkdocs_to_obsidian_callouts(doc.content_with_uploads)
API.create_topic(
external_id: doc.external_id,
raw: converted_content,
category: CATEGORY_ID,
title: doc.frontmatter["title"]
)
rescue Faraday::UnprocessableEntityError => e
puts " 422 error: #{e.response[:body]}"
raise e
end
if created_any
puts "Re-fetching remote info..."
remote_topics = API.fetch_current_state
map_to_remote.call
end
puts "Updating content..."
docs.each do |doc|
if doc.topic_id.nil?
next if DRY_RUN
raise "Topic ID not found for '#{doc.external_id}'. Something went wrong with creating it?"
end
# Convert callouts in the content before comparison and upload
converted_content = convert_mkdocs_to_obsidian_callouts(doc.content_with_uploads)
if converted_content.strip == doc.remote_content.strip &&
doc.frontmatter["title"] == doc.remote_title
puts "- no changes required for '#{doc.external_id}' (topic_id: #{doc.topic_id})" if VERBOSE
next
end
puts "- updating '#{doc.external_id}' (topic_id: #{doc.topic_id})... new title: '#{doc.frontmatter["title"]}'"
API.edit_post(
post_id: doc.first_post_id,
raw: converted_content,
title: doc.frontmatter["title"],
category: CATEGORY_ID
)
rescue Faraday::UnprocessableEntityError => e
puts " 422 error: #{e.response[:body]}"
raise e
end
puts "Building index..."
_, index_content = Util.parse_md(File.read("#{BASE}index.md"))
index_content += "\n\n"
docs
.group_by { |doc| doc.section }
.each do |section, section_docs|
if section
section_frontmatter, _ = Util.parse_md(File.read("#{BASE}#{section}/index.md"))
index_content += "## #{section_frontmatter["title"]}\n\n"
end
section_docs.each do |doc|
index_content +=
"- #{doc.frontmatter["short_title"]}: [#{doc.frontmatter["title"]}](/t/-/#{doc.topic_id}?silent=true)\n"
end
index_content += "\n"
end
index_post_info = remote_topics.find { |t| t[:topic_id] == cat_desc_topic_id }
if index_post_info[:raw].strip == index_content.strip
puts "- no changes required for index"
else
puts "- updating index..."
API.edit_post(post_id: index_post_info[:first_post_id], raw: index_content)
end
if WATCH
puts "Watching for changes to files..."
Listen
.to("#{__dir__}/docs") do |modified, added, removed|
if added.size > 0 || removed.size > 0
puts "Files added/removed. Restarting sync..."
exec("ruby", "#{__dir__}/sync_docs", *ARGV)
end
modified.each do |path|
relative = path.sub(BASE, "")
doc = docs.find { |d| d.path == relative }
raise "Modified file not recognized: #{relative}" if doc.nil?
print "- updating '#{doc.external_id}' (topic_id: #{doc.topic_id})..."
new_frontmatter, new_content = Util.parse_md(File.read(path))
if %w[id short_title].any? { |key| doc.frontmatter[key] != new_frontmatter[key] }
puts "Frontmatter changed. Restarting sync..."
exec("ruby", "#{__dir__}/sync_docs", *ARGV)
end
doc.content, doc.frontmatter = new_content, new_frontmatter
# Convert callouts before uploading
converted_content = convert_mkdocs_to_obsidian_callouts(doc.content_with_uploads)
API.edit_post(
post_id: doc.first_post_id,
raw: converted_content,
title: doc.frontmatter["title"]
)
puts " done"
end
end
.start
sleep
else
puts "Done."
end
+1 -1
View File
@@ -13,7 +13,7 @@ cd $ROOT
FAILED=0
IGNORED_FILES="uv\.lock|docs\/CARS.md|LICENSE\.md"
IGNORED_FILES="uv\.lock|docs\/CARS.md|LICENSE\.md|layouts\/.*\.xml|.*\.ipynb"
IGNORED_DIRS="^third_party.*|^msgq.*|^msgq_repo.*|^opendbc.*|^opendbc_repo.*|^cereal.*|^panda.*|^rednose.*|^rednose_repo.*|^tinygrad.*|^tinygrad_repo.*|^teleoprtc.*|^teleoprtc_repo.*"
function run() {
+2 -1
View File
@@ -88,6 +88,7 @@ class Car:
self.can_callbacks = can_comm_callbacks(self.can_sock, self.pm.sock['sendcan'])
is_release = self.params.get_bool("IsReleaseBranch")
is_release_sp = self.params.get_bool("IsReleaseSpBranch")
if CI is None:
# wait for one pandaState and one CAN packet
@@ -110,7 +111,7 @@ class Car:
init_params_list_sp = sunnypilot_interfaces.initialize_params(self.params)
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, cached_params,
fixed_fingerprint, init_params_list_sp)
fixed_fingerprint, init_params_list_sp, is_release_sp)
sunnypilot_interfaces.setup_interfaces(self.CI, self.params)
self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP, self.CI.CP_SP)
self.CP = self.CI.CP
+1 -1
View File
@@ -151,7 +151,7 @@ class TestCarModelBase(unittest.TestCase):
cls.CarInterface = interfaces[cls.platform]
cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, alpha_long, False, docs=False)
cls.CP_SP = cls.CarInterface.get_params_sp(cls.CP, cls.platform, cls.fingerprint, car_fw, alpha_long, docs=False)
cls.CP_SP = cls.CarInterface.get_params_sp(cls.CP, cls.platform, cls.fingerprint, car_fw, alpha_long, False, docs=False)
assert cls.CP
assert cls.CP_SP
assert cls.CP.carFingerprint == cls.platform
+4 -2
View File
@@ -99,7 +99,6 @@ class Controls(ControlsExt, ModelStateBase):
self.LaC.extension.update_model_v2(self.sm['modelV2'])
self.lat_delay = get_lat_delay(self.params, self.sm["liveDelay"].lateralDelay)
self.LaC.extension.update_lateral_lag(self.lat_delay)
long_plan = self.sm['longitudinalPlan']
@@ -133,7 +132,7 @@ class Controls(ControlsExt, ModelStateBase):
self.LoC.reset()
# accel PID loop
pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, CS.vEgo, CS.vCruise * CV.KPH_TO_MS)
pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, self.CP_SP, CS.vEgo, CS.vCruise * CV.KPH_TO_MS)
actuators.accel = float(self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits))
# Steering PID loop and lateral MPC
@@ -234,6 +233,9 @@ class Controls(ControlsExt, ModelStateBase):
while not evt.is_set():
self.get_params_sp()
if self.CP.lateralTuning.which() == 'torque':
self.lat_delay = get_lat_delay(self.params, self.sm["liveDelay"].lateralDelay)
time.sleep(0.1)
def run(self):
@@ -51,12 +51,12 @@ def limit_accel_in_turns(v_ego, angle_steers, a_target, CP):
class LongitudinalPlanner(LongitudinalPlannerSP):
def __init__(self, CP, init_v=0.0, init_a=0.0, dt=DT_MDL):
def __init__(self, CP, CP_SP, init_v=0.0, init_a=0.0, dt=DT_MDL):
self.CP = CP
self.mpc = LongitudinalMpc(dt=dt)
# TODO remove mpc modes when TR released
self.mpc.mode = 'acc'
LongitudinalPlannerSP.__init__(self, self.CP, self.mpc)
LongitudinalPlannerSP.__init__(self, self.CP, CP_SP, self.mpc)
self.fcw = False
self.dt = dt
self.allow_throttle = True
+6 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
from cereal import car
from cereal import car, custom
from openpilot.common.gps import get_gps_location_service
from openpilot.common.params import Params
from openpilot.common.realtime import Priority, config_realtime_process
@@ -17,10 +17,14 @@ def main():
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
cloudlog.info("plannerd got CarParams: %s", CP.brand)
cloudlog.info("plannerd is waiting for CarParamsSP")
CP_SP = messaging.log_from_bytes(params.get("CarParamsSP", block=True), custom.CarParamsSP)
cloudlog.info("plannerd got CarParamsSP")
gps_location_service = get_gps_location_service(params)
ldw = LaneDepartureWarning()
longitudinal_planner = LongitudinalPlanner(CP)
longitudinal_planner = LongitudinalPlanner(CP, CP_SP)
pm = messaging.PubMaster(['longitudinalPlan', 'driverAssistance', 'longitudinalPlanSP'])
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState',
'liveMapDataSP', 'carStateSP', gps_location_service],
@@ -51,7 +51,9 @@ class Plant:
from opendbc.car.honda.values import CAR
from opendbc.car.honda.interface import CarInterface
self.planner = LongitudinalPlanner(CarInterface.get_non_essential_params(CAR.HONDA_CIVIC), init_v=self.speed)
CP = CarInterface.get_non_essential_params(CAR.HONDA_CIVIC)
CP_SP = CarInterface.get_non_essential_params_sp(CP, CAR.HONDA_CIVIC)
self.planner = LongitudinalPlanner(CP, CP_SP, init_v=self.speed)
@property
def current_time(self):
+4 -4
View File
@@ -32,11 +32,11 @@ DeveloperPanel::DeveloperPanel(SettingsWindow *parent) : ListWidget(parent) {
experimentalLongitudinalToggle = new ParamControl(
"AlphaLongitudinalEnabled",
tr("openpilot Longitudinal Control (Alpha)"),
tr("sunnypilot Longitudinal Control (Alpha)"),
QString("<b>%1</b><br><br>%2")
.arg(tr("WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB)."))
.arg(tr("On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. "
"Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.")),
.arg(tr("WARNING: sunnypilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB)."))
.arg(tr("On this car, sunnypilot defaults to the car's built-in ACC instead of sunnypilot's longitudinal control. "
"Enable this to switch to sunnypilot longitudinal control. Enabling Experimental mode is recommended when enabling sunnypilot longitudinal control alpha.")),
""
);
experimentalLongitudinalToggle->setConfirmation(true, false);
+1 -1
View File
@@ -12,7 +12,7 @@ public:
explicit DeveloperPanel(SettingsWindow *parent);
void showEvent(QShowEvent *event) override;
private:
protected:
Params params;
ParamControl* adbToggle;
ParamControl* joystickToggle;
+1 -1
View File
@@ -188,7 +188,7 @@ void TogglesPanel::updateToggles() {
const QString unavailable = tr("Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control.");
QString long_desc = unavailable + " " + \
tr("openpilot longitudinal control may come in a future update.");
tr("sunnypilot longitudinal control may come in a future update.");
if (CP.getAlphaLongitudinalAvailable()) {
if (is_release) {
long_desc = unavailable + " " + tr("An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches.");
+6 -5
View File
@@ -11,17 +11,18 @@ WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) {
main_layout->setContentsMargins(56, 40, 56, 40);
main_layout->setSpacing(42);
QLabel *title = new QLabel(tr("<span style='font-family: \"Noto Color Emoji\";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span>"));
title->setStyleSheet("font-size: 64px; font-weight: 500;");
community_popup = new SunnylinkCommunityPopup(this);
QLabel *title = new QLabel(tr("sunnypilot Community"));
title->setStyleSheet("font-size: 56px; font-weight: 500;");
main_layout->addWidget(title);
QLabel *desc = new QLabel(tr("Maximize your training data uploads to improve openpilot's driving models."));
QLabel *desc = new QLabel(tr("Need help or have ideas?<br><b>Join</b> our community now!"));
desc->setStyleSheet("font-size: 40px; font-weight: 400;");
desc->setWordWrap(true);
main_layout->addWidget(desc);
QPushButton *settings_btn = new QPushButton(tr("Open"));
connect(settings_btn, &QPushButton::clicked, [=]() { emit openSettings(1, "FirehosePanel"); });
QPushButton *settings_btn = new QPushButton(tr("Learn More"));
connect(settings_btn, &QPushButton::clicked, [=]() { community_popup->exec(); });
settings_btn->setStyleSheet(R"(
QPushButton {
font-size: 48px;
+5
View File
@@ -3,12 +3,17 @@
#include <QFrame>
#include <QWidget>
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.h"
class WiFiPromptWidget : public QFrame {
Q_OBJECT
public:
explicit WiFiPromptWidget(QWidget* parent = 0);
private:
SunnylinkCommunityPopup *community_popup;
signals:
void openSettings(int index = 0, const QString &param = "");
};
+2
View File
@@ -35,6 +35,7 @@ qt_src = [
"sunnypilot/qt/offroad/settings/software_panel.cc",
"sunnypilot/qt/offroad/settings/sunnylink_panel.cc",
"sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.cc",
"sunnypilot/qt/offroad/settings/sunnylink/community_widget.cc",
"sunnypilot/qt/offroad/settings/trips_panel.cc",
"sunnypilot/qt/offroad/settings/vehicle_panel.cc",
"sunnypilot/qt/offroad/settings/visuals_panel.cc",
@@ -51,6 +52,7 @@ lateral_panel_qt_src = [
"sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.cc",
"sunnypilot/qt/offroad/settings/lateral/lane_change_settings.cc",
"sunnypilot/qt/offroad/settings/lateral/mads_settings.cc",
"sunnypilot/qt/offroad/settings/lateral/angle_tuning_settings.cc",
"sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.cc",
"sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_custom_params.cc",
"sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.cc",
@@ -60,7 +60,7 @@ DeveloperPanelSP::DeveloperPanelSP(SettingsWindow *parent) : DeveloperPanel(pare
void DeveloperPanelSP::updateToggles(bool offroad) {
bool disable_updates = params.getBool("DisableUpdates");
bool is_release = params.getBool("IsReleaseBranch");
bool is_release = params.getBool("IsReleaseBranch") || params.getBool("IsReleaseSpBranch");
bool is_tested = params.getBool("IsTestedBranch");
bool is_development = params.getBool("IsDevelopmentBranch");
@@ -79,6 +79,9 @@ void DeveloperPanelSP::updateToggles(bool offroad) {
enableGithubRunner->setVisible(!is_release);
errorLogBtn->setVisible(!is_release);
showAdvancedControls->setEnabled(true);
joystickToggle->setVisible(!is_release);
longManeuverToggle->setVisible(!is_release);
}
void DeveloperPanelSP::showEvent(QShowEvent *event) {
@@ -0,0 +1,87 @@
/**
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
*
* This file is part of sunnypilot and is licensed under the MIT License.
* See the LICENSE.md file in the root directory for more details.
*/
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/angle_tuning_settings.h"
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
AngleTunningSettings::AngleTunningSettings(QWidget *parent) : QWidget(parent) {
QVBoxLayout *main_layout = new QVBoxLayout(this);
main_layout->setContentsMargins(50, 20, 50, 20);
main_layout->setSpacing(20);
// Back button
PanelBackButton *back = new PanelBackButton();
connect(back, &QPushButton::clicked, [=]() { emit backPress(); });
main_layout->addWidget(back, 0, Qt::AlignLeft);
auto *list = new ListWidgetSP(this, false);
main_layout->addWidget(new QWidget());
enableHkgAngleSmoothingFactor = new ExpandableToggleRow("EnableHkgTuningAngleSmoothingFactor", tr("HKG Angle Smoothing Factor"), tr("Applies EMA (Exponential Moving Average) to the desired angle steering and avoid overcorrections."), "../assets/offroad/icon_blank.png");
list->addItem(enableHkgAngleSmoothingFactor);
auto first_row = new QHBoxLayout();
hkgTuningOverridingCycles = new OptionControlSP("HkgTuningOverridingCycles", tr("Override Ramp-Down Cycles"), tr("Number of cycles to ramp down the current amount of torque on the steering wheel.<br/>A smaller value means a faster override by the user (less effort)"), "../assets/offroad/icon_blank.png", {10, 30}, 1);
connect(hkgTuningOverridingCycles, &OptionControlSP::updateLabels, hkgTuningOverridingCycles, [=]() {
this->updateToggles(offroad);
});
first_row->addWidget(hkgTuningOverridingCycles);
hkgAngleMinTorque = new OptionControlSP("HkgTuningAngleMinTorqueReductionGain", tr("Override Steering Effort"), tr("Sets the steering effort percentage used when the driver is overriding lateral control.<br/>Higher values increase resistance and make the wheel feel stiffer."), "../assets/offroad/icon_blank.png", {5, 60}, 1);
connect(hkgAngleMinTorque, &OptionControlSP::updateLabels, hkgAngleMinTorque, [=]() {
this->updateToggles(offroad);
});
first_row->addWidget(hkgAngleMinTorque);
list->addItem(first_row);
auto second_row = new QHBoxLayout();
hkgAngleActiveTorque = new OptionControlSP("HkgTuningAngleActiveTorqueReductionGain", tr("Min Active Torque"), tr("Torque applied when lateral control is active but the vehicle is not turning.<br/>Used to maintain lane centering on straight paths when no user input is detected."), "../assets/offroad/icon_blank.png", {10, 100}, 1);
connect(hkgAngleActiveTorque, &OptionControlSP::updateLabels, hkgAngleActiveTorque, [=]() {
this->updateToggles(offroad);
});
second_row->addWidget(hkgAngleActiveTorque);
hkgAngleMaxTorque = new OptionControlSP("HkgTuningAngleMaxTorqueReductionGain", tr("Max Torque Allowance"), tr("Sets the maximum torque reduction percentage the controller can apply during normal lateral control.<br/>"), "../assets/offroad/icon_blank.png", {10, 100}, 1);
connect(hkgAngleMaxTorque, &OptionControlSP::updateLabels, hkgAngleMaxTorque, [=]() {
this->updateToggles(offroad);
});
second_row->addWidget(hkgAngleMaxTorque);
list->addItem(second_row);
QObject::connect(uiState(), &UIState::offroadTransition, this, &AngleTunningSettings::updateToggles);
main_layout->addWidget(new ScrollViewSP(list, this));
auto *warning = new QLabel(tr("Reboot required for settings to apply; Tap on each setting to see more details."));
warning->setStyleSheet("font-size: 30px; font-weight: 500; font-family: 'Noto Color Emoji'; color: orange;");
main_layout->addWidget(warning, 0, Qt::AlignCenter);
}
void AngleTunningSettings::showEvent(QShowEvent *event) {
updateToggles(offroad);
}
void AngleTunningSettings::updateToggles(bool _offroad) {
auto HkgAngleSmoothingFactorValue = params.getBool("EnableHkgTuningAngleSmoothingFactor");
enableHkgAngleSmoothingFactor->toggleFlipped(HkgAngleSmoothingFactorValue);
auto HkgAngleMinTorqueValue = QString::fromStdString(params.get("HkgTuningAngleMinTorqueReductionGain")).toInt();
hkgAngleMinTorque->setLabel(QString::number(HkgAngleMinTorqueValue)+"%");
auto HkgAngleActiveTorqueValue = QString::fromStdString(params.get("HkgTuningAngleActiveTorqueReductionGain")).toInt();
hkgAngleActiveTorque->setLabel(QString::number(HkgAngleActiveTorqueValue)+"%");
auto HkgAngleMaxTorqueValue = QString::fromStdString(params.get("HkgTuningAngleMaxTorqueReductionGain")).toInt();
hkgAngleMaxTorque->setLabel(QString::number(HkgAngleMaxTorqueValue)+"%");
auto HkgTuningOverridingCyclesValue = QString::fromStdString(params.get("HkgTuningOverridingCycles")).toInt();
hkgTuningOverridingCycles->setLabel(QString::number(HkgTuningOverridingCyclesValue));
offroad = _offroad;
}
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
*
* This file is part of sunnypilot and is licensed under the MIT License.
* See the LICENSE.md file in the root directory for more details.
*/
#pragma once
#include "selfdrive/ui/qt/util.h"
#include "selfdrive/ui/sunnypilot/ui.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
#include "selfdrive/ui/sunnypilot/qt/widgets/expandable_row.h"
class AngleTunningSettings : public QWidget {
Q_OBJECT
public:
explicit AngleTunningSettings(QWidget *parent = nullptr);
void showEvent(QShowEvent *event) override;
signals:
void backPress();
public slots:
void updateToggles(bool _offroad);
private:
Params params;
bool offroad;
ExpandableToggleRow* enableHkgAngleSmoothingFactor;
OptionControlSP* hkgAngleMinTorque;
OptionControlSP* hkgAngleActiveTorque;
OptionControlSP* hkgAngleMaxTorque;
OptionControlSP* hkgTuningOverridingCycles;
};
@@ -120,6 +120,36 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
updateToggles(offroad);
});
#pragma region hkg angle tuning
list->addItem(vertical_space());
list->addItem(horizontal_line());
list->addItem(vertical_space());
// HKG Angle Tuning
// angleTuningToggle = new ParamControl(
// "AngleTuning",
// tr("Modular Assistive Driving System (MADS)"),
// tr("Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement."),
// "");
// angleTuningToggle->setConfirmation(true, false);
// list->addItem(angleTuningToggle);
angleTuningSettingsButton = new PushButtonSP(tr("Customize ANGLE Tuning"));
angleTuningSettingsButton->setObjectName("angle_btn");
connect(angleTuningSettingsButton, &QPushButton::clicked, [=]() {
sunnypilotScroller->setLastScrollPosition();
main_layout->setCurrentWidget(angleTuningWidget);
});
// QObject::connect(angleTuningToggle, &ToggleControl::toggleFlipped, angleTuningSettingsButton, &PushButtonSP::setEnabled);
angleTuningWidget = new AngleTunningSettings(this);
connect(angleTuningWidget, &AngleTunningSettings::backPress, [=]() {
sunnypilotScroller->restoreScrollPosition();
main_layout->setCurrentWidget(sunnypilotScreen);
});
list->addItem(angleTuningSettingsButton);
#pragma endregion
QObject::connect(uiState(), &UIState::offroadTransition, this, &LateralPanel::updateToggles);
sunnypilotScroller = new ScrollViewSP(list, this);
@@ -127,6 +157,7 @@ LateralPanel::LateralPanel(SettingsWindowSP *parent) : QFrame(parent) {
main_layout->addWidget(sunnypilotScreen);
main_layout->addWidget(madsWidget);
main_layout->addWidget(angleTuningWidget);
main_layout->addWidget(laneChangeWidget);
main_layout->addWidget(torqueLateralControlWidget);
@@ -188,6 +219,7 @@ void LateralPanel::updateToggles(bool _offroad) {
madsToggle->setEnabled(_offroad);
madsSettingsButton->setEnabled(madsToggle->isToggled());
// angleTuningSettingsButton->setEnabled(angleTuningToggle->isToggled());
torqueLateralControlToggle->setEnabled(_offroad && torque_allowed && !nnlcToggle->isToggled());
torqueLateralControlSettingsButton->setEnabled(torqueLateralControlToggle->isToggled());
@@ -13,6 +13,7 @@
#include "selfdrive/ui/sunnypilot/ui.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/blinker_pause_lateral_settings.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/mads_settings.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/angle_tuning_settings.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/neural_network_lateral_control.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/lane_change_settings.h"
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral/torque_lateral_control_settings.h"
@@ -39,8 +40,11 @@ private:
bool offroad;
ParamControl *madsToggle;
// ParamControl *angleTuningToggle;
PushButtonSP *madsSettingsButton;
PushButtonSP *angleTuningSettingsButton;
MadsSettings *madsWidget = nullptr;
AngleTunningSettings *angleTuningWidget = nullptr;
PushButtonSP *laneChangeSettingsButton;
LaneChangeSettings *laneChangeWidget = nullptr;
NeuralNetworkLateralControl *nnlcToggle = nullptr;
@@ -7,6 +7,8 @@
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.h"
#include "selfdrive/ui/sunnypilot/qt/util.h"
SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent) {
subPanelFrame = new QFrame();
QVBoxLayout *subPanelLayout = new QVBoxLayout(subPanelFrame);
@@ -103,13 +105,13 @@ SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent)
}
void SpeedLimitSettings::refresh() {
bool is_release = params.getBool("IsReleaseSpBranch");
bool is_metric_param = params.getBool("IsMetric");
SpeedLimitMode speed_limit_mode_param = static_cast<SpeedLimitMode>(std::atoi(params.get("SpeedLimitMode").c_str()));
SpeedLimitOffsetType offset_type_param = static_cast<SpeedLimitOffsetType>(std::atoi(params.get("SpeedLimitOffsetType").c_str()));
QString offsetLabel = QString::fromStdString(params.get("SpeedLimitValueOffset"));
bool has_longitudinal_control;
bool intelligent_cruise_button_management_available;
bool sla_available;
auto cp_bytes = params.get("CarParamsPersistent");
auto cp_sp_bytes = params.get("CarParamsSPPersistent");
if (!cp_bytes.empty() && !cp_sp_bytes.empty()) {
@@ -120,17 +122,24 @@ void SpeedLimitSettings::refresh() {
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
cereal::CarParamsSP::Reader CP_SP = cmsg_sp.getRoot<cereal::CarParamsSP>();
has_longitudinal_control = hasLongitudinalControl(CP);
intelligent_cruise_button_management_available = CP_SP.getIntelligentCruiseButtonManagementAvailable();
bool has_longitudinal_control = hasLongitudinalControl(CP);
bool has_icbm = hasIntelligentCruiseButtonManagement(CP_SP);
if (!has_longitudinal_control && CP_SP.getPcmCruiseSpeed()) {
if (speed_limit_mode_param == SpeedLimitMode::ASSIST) {
params.put("SpeedLimitMode", std::to_string(static_cast<int>(SpeedLimitMode::WARNING)));
}
/*
* Speed Limit Assist is available when:
* - has_longitudinal_control or has_icbm, and
* - is not a release branch or not a disallowed brand, and
* - is not always disallowed
*/
bool sla_disallow_in_release = CP.getBrand() == "tesla" && is_release;
bool sla_always_disallow = CP.getBrand() == "rivian";
sla_available = (has_longitudinal_control || has_icbm) && !sla_disallow_in_release && !sla_always_disallow;
if (!sla_available && speed_limit_mode_param == SpeedLimitMode::ASSIST) {
params.put("SpeedLimitMode", std::to_string(static_cast<int>(SpeedLimitMode::WARNING)));
}
} else {
has_longitudinal_control = false;
intelligent_cruise_button_management_available = false;
sla_available = false;
}
speed_limit_mode_settings->setDescription(modeDescription(speed_limit_mode_param));
@@ -150,13 +159,14 @@ void SpeedLimitSettings::refresh() {
speed_limit_offset->showDescription();
}
if (has_longitudinal_control || intelligent_cruise_button_management_available) {
if (sla_available) {
speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues(getSpeedLimitModeValues()));
} else {
speed_limit_mode_settings->setEnableSelectedButtons(true, convertSpeedLimitModeValues(
{SpeedLimitMode::OFF, SpeedLimitMode::INFORMATION, SpeedLimitMode::WARNING}));
}
speed_limit_mode_settings->refresh();
speed_limit_mode_settings->showDescription();
speed_limit_offset->showDescription();
}
@@ -35,6 +35,7 @@ private:
SpeedLimitPolicy *speedLimitPolicyScreen;
ButtonParamControlSP *speed_limit_offset_settings;
OptionControlSP *speed_limit_offset;
bool icbm_available = false;
static QString offsetDescription(SpeedLimitOffsetType type = SpeedLimitOffsetType::NONE) {
QString none_str = tr("⦿ None: No Offset");
@@ -7,6 +7,8 @@
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h"
#include "selfdrive/ui/sunnypilot/qt/util.h"
LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) {
setStyleSheet(R"(
#back_btn {
@@ -36,11 +38,13 @@ LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) {
intelligentCruiseButtonManagement = new ParamControlSP(
"IntelligentCruiseButtonManagement",
tr("Intelligent Cruise Button Management (ICBM) (Alpha)"),
tr("When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control."),
"",
"",
this
);
intelligentCruiseButtonManagement->setConfirmation(true, false);
QObject::connect(intelligentCruiseButtonManagement, &ParamControlSP::toggleFlipped, this, [=](bool) {
refresh(offroad);
});
list->addItem(intelligentCruiseButtonManagement);
dynamicExperimentalControl = new ParamControlSP(
@@ -100,6 +104,8 @@ void LongitudinalPanel::hideEvent(QHideEvent *event) {
}
void LongitudinalPanel::refresh(bool _offroad) {
const QString icbm_description = tr("When enabled, sunnypilot will attempt to manage the built-in cruise control buttons by emulating button presses for limited longitudinal control.");
auto cp_bytes = params.get("CarParamsPersistent");
auto cp_sp_bytes = params.get("CarParamsSPPersistent");
if (!cp_bytes.empty() && !cp_sp_bytes.empty()) {
@@ -112,26 +118,61 @@ void LongitudinalPanel::refresh(bool _offroad) {
has_longitudinal_control = hasLongitudinalControl(CP);
is_pcm_cruise = CP.getPcmCruise();
intelligent_cruise_button_management_available = CP_SP.getIntelligentCruiseButtonManagementAvailable();
has_icbm = hasIntelligentCruiseButtonManagement(CP_SP);
if (!intelligent_cruise_button_management_available || has_longitudinal_control) {
if (CP_SP.getIntelligentCruiseButtonManagementAvailable() && !has_longitudinal_control) {
intelligentCruiseButtonManagement->setEnabled(offroad);
intelligentCruiseButtonManagement->setDescription(icbm_description);
} else {
params.remove("IntelligentCruiseButtonManagement");
intelligentCruiseButtonManagement->setEnabled(false);
const QString icbm_unavaialble = tr("Intelligent Cruise Button Management is currently unavailable on this platform.");
QString long_desc = icbm_unavaialble;
if (has_longitudinal_control) {
if (CP.getAlphaLongitudinalAvailable()) {
long_desc = icbm_unavaialble + " " + tr("Disable the sunnypilot Longitudinal Control (alpha) toggle to allow Intelligent Cruise Button Management.");
} else {
long_desc = icbm_unavaialble + " " + tr("sunnypilot Longitudinal Control is the default longitudinal control for this platform.");
}
}
intelligentCruiseButtonManagement->setDescription("<b>" + long_desc + "</b><br><br>" + icbm_description);
intelligentCruiseButtonManagement->showDescription();
}
if (!has_longitudinal_control && CP_SP.getPcmCruiseSpeed()) {
if (has_longitudinal_control || has_icbm) {
// enable Custom ACC Increments when long is available and is not PCM cruise
customAccIncrement->setEnabled(((has_longitudinal_control && !is_pcm_cruise) || has_icbm) && offroad);
dynamicExperimentalControl->setEnabled(has_longitudinal_control);
SmartCruiseControlVision->setEnabled(true);
SmartCruiseControlMap->setEnabled(true);
} else {
params.remove("CustomAccIncrementsEnabled");
params.remove("DynamicExperimentalControl");
params.remove("SmartCruiseControlVision");
params.remove("SmartCruiseControlMap");
customAccIncrement->setEnabled(false);
dynamicExperimentalControl->setEnabled(false);
SmartCruiseControlVision->setEnabled(false);
SmartCruiseControlMap->setEnabled(false);
}
intelligentCruiseButtonManagement->refresh();
customAccIncrement->refresh();
dynamicExperimentalControl->refresh();
SmartCruiseControlVision->refresh();
SmartCruiseControlMap->refresh();
} else {
has_longitudinal_control = false;
is_pcm_cruise = false;
intelligent_cruise_button_management_available = false;
has_icbm = false;
intelligentCruiseButtonManagement->setDescription("<b>" + tr("Start the vehicle to check vehicle compatibility.") + "</br><b><b>" + icbm_description);
}
QString accEnabledDescription = tr("Enable custom Short & Long press increments for cruise speed increase/decrease.");
QString accNoLongDescription = tr("This feature can only be used with openpilot longitudinal control enabled.");
QString accNoLongDescription = tr("This feature can only be used with sunnypilot longitudinal control enabled.");
QString accPcmCruiseDisabledDescription = tr("This feature is not supported on this platform due to vehicle limitations.");
QString onroadOnlyDescription = tr("Start the vehicle to check vehicle compatibility.");
@@ -139,32 +180,18 @@ void LongitudinalPanel::refresh(bool _offroad) {
customAccIncrement->setDescription(onroadOnlyDescription);
customAccIncrement->showDescription();
} else {
if (has_longitudinal_control || intelligent_cruise_button_management_available) {
if (is_pcm_cruise) {
if (has_longitudinal_control || has_icbm) {
if (has_longitudinal_control && is_pcm_cruise) {
customAccIncrement->setDescription(accPcmCruiseDisabledDescription);
customAccIncrement->showDescription();
} else {
customAccIncrement->setDescription(accEnabledDescription);
}
} else {
customAccIncrement->toggleFlipped(false);
customAccIncrement->setDescription(accNoLongDescription);
customAccIncrement->showDescription();
intelligentCruiseButtonManagement->toggleFlipped(false);
}
}
bool icbm_allowed = intelligent_cruise_button_management_available && !has_longitudinal_control;
intelligentCruiseButtonManagement->setEnabled(icbm_allowed && offroad);
// enable toggle when long is available and is not PCM cruise
bool cai_allowed = (has_longitudinal_control && !is_pcm_cruise) || icbm_allowed;
customAccIncrement->setEnabled(cai_allowed && !offroad);
customAccIncrement->refresh();
dynamicExperimentalControl->setEnabled(has_longitudinal_control);
SmartCruiseControlVision->setEnabled(has_longitudinal_control || icbm_allowed);
SmartCruiseControlMap->setEnabled(has_longitudinal_control || icbm_allowed);
offroad = _offroad;
}
@@ -25,7 +25,7 @@ private:
Params params;
bool has_longitudinal_control = false;
bool is_pcm_cruise = false;
bool intelligent_cruise_button_management_available = false;;
bool has_icbm = false;
bool offroad = false;
QStackedLayout *main_layout = nullptr;
@@ -310,9 +310,8 @@ void ModelsPanel::handleCurrentModelLblBtnClicked() {
QList<TreeNode> sortedModels;
QSet<QString> modelFolders;
QRegularExpression re("\\(([^)]*)\\)[^(]*$");
const auto bundles = model_manager.getAvailableBundles();
for (const auto &bundle : bundles) {
for (const auto &bundle : model_manager.getAvailableBundles()) {
auto overrides = bundle.getOverrides();
QString folder;
for (const auto &override : overrides) {
@@ -392,7 +391,7 @@ void ModelsPanel::handleCurrentModelLblBtnClicked() {
showResetParamsDialog();
} else {
// Find selected bundle and initiate download
for (const auto &bundle: bundles) {
for (const auto &bundle: model_manager.getAvailableBundles()) {
if (QString::fromStdString(bundle.getRef()) == selectedBundleRef) {
params.put("ModelManager_DownloadIndex", std::to_string(bundle.getIndex()));
if (bundle.getGeneration() != model_manager.getActiveBundle().getGeneration()) {
@@ -0,0 +1,139 @@
/**
* Copyright (c) 2025-, sunnypilot contributors.
*
* This file is part of sunnypilot and is licensed under the MIT License.
* See the LICENSE.md file in the root directory for more details.
*/
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.h"
#include "selfdrive/ui/sunnypilot/ui.h"
#include "selfdrive/ui/sunnypilot/qt/util.h"
using qrcodegen::QrCode;
// --- SunnylinkCommunityQRWidget ---
SunnylinkCommunityQRWidget::SunnylinkCommunityQRWidget(QWidget* parent)
: QWidget(parent) {}
void SunnylinkCommunityQRWidget::showEvent(QShowEvent *event) {
updateQrCode(SUNNYLINK_COMMUNITY_URL);
update();
}
void SunnylinkCommunityQRWidget::updateQrCode(const QString &text) {
QrCode qr = QrCode::encodeText(text.toUtf8().data(), QrCode::Ecc::LOW);
qint32 sz = qr.getSize();
QImage im(sz, sz, QImage::Format_RGB32);
QRgb black = qRgb(0, 0, 0);
QRgb white = qRgb(255, 255, 255);
for (int y = 0; y < sz; y++) {
for (int x = 0; x < sz; x++) {
im.setPixel(x, y, qr.getModule(x, y) ? black : white);
}
}
int final_sz = ((width() / sz) - 1) * sz;
img = QPixmap::fromImage(im.scaled(final_sz, final_sz, Qt::KeepAspectRatio), Qt::MonoOnly);
}
void SunnylinkCommunityQRWidget::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.fillRect(rect(), Qt::white);
if (!img.isNull()) {
QSize s = (size() - img.size()) / 2;
p.drawPixmap(s.width(), s.height(), img);
}
}
// --- SunnylinkCommunityPopup ---
QStringList SunnylinkCommunityPopup::getInstructions() {
QStringList instructions;
instructions << tr("Scan the QR code and join us!");
return instructions;
}
SunnylinkCommunityPopup::SunnylinkCommunityPopup(QWidget* parent)
: DialogBase(parent) {
auto *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
// Solarized Light base3 background
setStyleSheet("SunnylinkCommunityPopup { background-color: #FDF6E3; }");
// Header spanning full width
auto headerWidget = new QWidget(this);
auto headerLayout = new QHBoxLayout(headerWidget);
headerLayout->setContentsMargins(85, 50, 85, 30);
headerLayout->setSpacing(30);
auto close = new QPushButton(QIcon(":/icons/close.svg"), "", this);
close->setIconSize(QSize(80, 80));
close->setStyleSheet("border: none;");
connect(close, &QPushButton::clicked, this, &QDialog::reject);
headerLayout->addWidget(close, 0, Qt::AlignLeft | Qt::AlignVCenter);
const auto title = new QLabel(tr("Join the sunnypilot Community Forum"), this);
// Solarized base02 for text
title->setStyleSheet("font-size: 65px; color: #073642;");
title->setWordWrap(false);
title->setAlignment(Qt::AlignCenter);
headerLayout->addWidget(title, 1);
// Spacer to balance the close button on the right
auto spacer = new QWidget(this);
spacer->setFixedSize(80, 80);
headerLayout->addWidget(spacer, 0);
mainLayout->addWidget(headerWidget);
// Two-column content layout
auto contentLayout = new QHBoxLayout();
contentLayout->setContentsMargins(0, 0, 0, 0);
contentLayout->setSpacing(0);
mainLayout->addLayout(contentLayout, 66);
// Left side: description
auto leftLayout = new QVBoxLayout();
leftLayout->setContentsMargins(85, 40, 50, 70);
leftLayout->setSpacing(35);
contentLayout->addLayout(leftLayout, 40);
// Hype / intro paragraph
const auto desc = new QLabel(tr(
"We're excited to announce our <b>sunnypilot Community Forum</b><br><br>"
"Over the years, Discord just hasn't scaled well for our growing community.<br>"
"It's noisy, unsearchable, and great discussions disappear too easily.<br>"
"Our new community forum aims to fix that by making it easier to <b>find answers, share ideas, track feedback, report bugs, help newcomers</b> and more!<br><br>"
"<b>Here's what's waiting for you:</b><br>"
"• Fully <b>indexable</b> and discoverable through search engines 🔎<br>"
"• <b>AI-powered</b>🤖 topic and chat summaries, spam detection, and more<br>"
"• A <b>trust-level system</b>✅ that rewards meaningful contributions<br>"
"• Designed to work <b>on your own time</b>.🧘<br><br>"
"Scan the QR code on the right and join the discussion!"
), this);
// Solarized base01 for body text
desc->setStyleSheet("font-size: 40px; color: #586E75;");
desc->setWordWrap(true);
leftLayout->addWidget(desc);
leftLayout->addStretch();
// Right side: QR code and instructions
auto rightLayout = new QVBoxLayout();
rightLayout->setContentsMargins(50, 40, 85, 70);
rightLayout->setSpacing(40);
contentLayout->addLayout(rightLayout, 1);
// QR code (smaller, fixed size)
auto *qr = new SunnylinkCommunityQRWidget(this);
qr->setFixedSize(500, 500);
rightLayout->addStretch();
rightLayout->addWidget(qr, 0, Qt::AlignCenter);
rightLayout->addStretch();
}
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2025-, sunnypilot contributors.
*
* This file is part of sunnypilot and is licensed under the MIT License.
* See the LICENSE.md file in the root directory for more details.
*/
#pragma once
#include <QrCode.hpp>
#include <QtCore/qjsonobject.h>
#include "common/util.h"
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
const QString SUNNYLINK_COMMUNITY_URL = "https://community.sunnypilot.ai/sp-qr";
class SunnylinkCommunityQRWidget : public QWidget {
Q_OBJECT
public:
explicit SunnylinkCommunityQRWidget(QWidget* parent = nullptr);
void paintEvent(QPaintEvent*) override;
private:
QPixmap img;
void updateQrCode(const QString &text);
void showEvent(QShowEvent *event) override;
};
// Popup widget
class SunnylinkCommunityPopup : public DialogBase {
Q_OBJECT
public:
explicit SunnylinkCommunityPopup(QWidget* parent = nullptr);
private:
static QStringList getInstructions();
};
@@ -79,11 +79,11 @@ QStringList SunnylinkSponsorPopup::getInstructions(bool sponsor_pair) {
instructions << tr("Scan the QR code to login to your GitHub account")
<< tr("Follow the prompts to complete the pairing process")
<< tr("Re-enter the \"sunnylink\" panel to verify sponsorship status")
<< tr("If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot");
<< tr("If sponsorship status was not updated, please contact a moderator on our forum at https://community.sunnypilot.ai");
} else {
instructions << tr("Scan the QR code to visit sunnyhaibin's GitHub Sponsors page")
<< tr("Choose your sponsorship tier and confirm your support")
<< tr("Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status");
<< tr("Join our Community Forum at https://community.sunnypilot.ai and reach out to a moderator if you have issues");
}
return instructions;
}
@@ -90,7 +90,7 @@ SunnylinkPanel::SunnylinkPanel(QWidget *parent) : QFrame(parent) {
QString sunnylinkUploaderDesc = tr("Enable sunnylink uploader to allow sunnypilot to upload your driving data to sunnypilot servers. (only for highest tiers, and does NOT bring ANY benefit to you. We are just testing data volume.)");
sunnylinkUploaderEnabledBtn = new ParamControlSP(
"EnableSunnylinkUploader",
tr("[Don't use] Enable sunnylink uploader"),
tr("Enable sunnylink uploader (infrastructure test)"),
sunnylinkUploaderDesc,
"", nullptr, true);
list->addItem(sunnylinkUploaderEnabledBtn);
@@ -290,7 +290,10 @@ void SunnylinkPanel::updatePanel() {
pairSponsorBtn->setEnabled(!is_onroad && is_sunnylink_enabled);
pairSponsorBtn->setValue(is_paired ? tr("Paired") : tr("Not Paired"));
sunnylinkUploaderEnabledBtn->setEnabled(max_current_sponsor_rule.roleTier == SponsorTier::Guardian && is_sunnylink_enabled);
bool can_do_uploads = max_current_sponsor_rule.roleTier >= SponsorTier::Novice && is_sunnylink_enabled;
sunnylinkUploaderEnabledBtn->setVisible(can_do_uploads);
sunnylinkUploaderEnabledBtn->setEnabled(can_do_uploads);
if (!is_sunnylink_enabled) {
sunnylinkEnabledBtn->setValue("");
@@ -33,7 +33,7 @@ private:
static QString toggleDisableMsg(bool _offroad, bool _has_longitudinal_control) {
if (!_has_longitudinal_control) {
return tr("This feature can only be used with openpilot longitudinal control enabled.");
return tr("This feature can only be used with sunnypilot longitudinal control enabled.");
}
if (!_offroad) {
@@ -57,7 +57,7 @@ private:
}
return QString("%1<br><br>%2<br>%3<br>%4<br>")
.arg(tr("Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control."))
.arg(tr("Fine-tune your driving experience by adjusting acceleration smoothness with sunnypilot longitudinal control."))
.arg(off_str)
.arg(dynamic_str)
.arg(predictive_str);
@@ -8,7 +8,41 @@
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.h"
TeslaSettings::TeslaSettings(QWidget *parent) : BrandSettingsInterface(parent) {
constexpr int coopSteeringMinKmh = 23; // minimum speed for cooperative steering (enforced by Tesla firmware)
constexpr int oemSteeringMinKmh = 48; // minimum speed for OEM lane departure avoidance (enforced by Tesla firmware)
bool is_metric = params.getBool("IsMetric");
QString unit = is_metric ? "km/h" : "mph";
int display_value_coop;
int display_value_oem;
if (is_metric) {
display_value_coop = coopSteeringMinKmh;
display_value_oem = oemSteeringMinKmh;
} else {
display_value_coop = static_cast<int>(std::round(coopSteeringMinKmh * KM_TO_MILE));
display_value_oem = static_cast<int>(std::round(oemSteeringMinKmh * KM_TO_MILE));
}
const QString coop_desc = QString("<b>%1</b><br><br>"
"%2<br>"
"%3<br>")
.arg(tr("Warning: May experience steering oscillations below %5 %6 during turns, recommend disabling this feature if you experience these."))
.arg(tr("Allows the driver to provide limited steering input while openpilot is engaged."))
.arg(tr("Only works above %4 %6."))
.arg(display_value_coop)
.arg(display_value_oem)
.arg(unit);
coopSteeringToggle = new ParamControlSP(
"TeslaCoopSteering",
tr("Cooperative Steering (Beta)"),
coop_desc,
"",
this
);
list->addItem(coopSteeringToggle);
coopSteeringToggle->showDescription();
coopSteeringToggle->setConfirmation(true, false);
}
void TeslaSettings::updateSettings() {
coopSteeringToggle->setEnabled(offroad);
}
@@ -22,5 +22,5 @@ public:
void updateSettings() override;
private:
bool offroad = false;
ParamControlSP *coopSteeringToggle = nullptr;
};
@@ -119,7 +119,7 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
// Visuals: Display Metrics below Chevron
std::vector<QString> chevron_info_settings_texts{tr("Off"), tr("Distance"), tr("Speed"), tr("Time"), tr("All")};
chevron_info_settings = new ButtonParamControlSP(
"ChevronInfo", tr("Display Metrics Below Chevron"), tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control)."),
"ChevronInfo", tr("Display Metrics Below Chevron"), tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with sunnypilot longitudinal control)."),
"",
chevron_info_settings_texts,
200);
@@ -159,8 +159,8 @@ void VisualsPanel::refreshLongitudinalStatus() {
}
if (chevron_info_settings) {
QString chevronEnabledDescription = tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control).");
QString chevronNoLongDescription = tr("This feature requires openpilot longitudinal control to be available.");
QString chevronEnabledDescription = tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with sunnypilot longitudinal control).");
QString chevronNoLongDescription = tr("This feature requires sunnypilot longitudinal control to be available.");
if (has_longitudinal_control) {
chevron_info_settings->setDescription(chevronEnabledDescription);
+4
View File
@@ -122,3 +122,7 @@ std::optional<cereal::Event::Reader> loadCerealEvent(Params& params, const std::
return std::nullopt;
}
}
bool hasIntelligentCruiseButtonManagement(const cereal::CarParamsSP::Reader &car_params_sp) {
return car_params_sp.getIntelligentCruiseButtonManagementAvailable() && Params().getBool("IntelligentCruiseButtonManagement");
}
+1
View File
@@ -23,3 +23,4 @@ std::optional<QString> getParamIgnoringDefault(const std::string &param_name, co
QMap<QString, QVariantMap> loadPlatformList();
QStringList searchFromList(const QString &query, const QStringList &list);
std::optional<cereal::Event::Reader> loadCerealEvent(Params& params, const std::string& _param);
bool hasIntelligentCruiseButtonManagement(const cereal::CarParamsSP::Reader &car_params_sp);
@@ -390,7 +390,7 @@ class ButtonParamControlSP : public MultiButtonControlSP {
Q_OBJECT
public:
ButtonParamControlSP(const QString &param, const QString &title, const QString &desc, const QString &icon,
const std::vector<QString> &button_texts, const int minimum_button_width = 225, const bool inline_layout = false, bool advancedControl = false) : MultiButtonControlSP(title, desc, icon,
const std::vector<QString> &button_texts, const int minimum_button_width = 380, const bool inline_layout = false, bool advancedControl = false) : MultiButtonControlSP(title, desc, icon,
button_texts, minimum_button_width, inline_layout, advancedControl) {
key = param.toStdString();
int value = atoi(params.get(key).c_str());
+1 -1
View File
@@ -18,7 +18,7 @@ if __name__ == "__main__":
while True:
print("setting alert update")
params.put_bool("UpdateAvailable", True)
r = open(os.path.join(BASEDIR, "RELEASES.md")).read()
r = open(os.path.join(BASEDIR, "CHANGELOG.md")).read()
r = r[:r.find('\n\n')] # Slice latest release notes
params.put("UpdaterNewReleaseNotes", r + "\n")
+1 -1
View File
@@ -188,7 +188,7 @@ def setup_offroad_alert(click, pm: PubMaster, scroll=None):
def setup_update_available(click, pm: PubMaster, scroll=None):
Params().put_bool("UpdateAvailable", True)
release_notes_path = os.path.join(BASEDIR, "RELEASES.md")
release_notes_path = os.path.join(BASEDIR, "CHANGELOG.md")
with open(release_notes_path) as file:
release_notes = file.read().split('\n\n', 1)[0]
Params().put("UpdaterNewReleaseNotes", release_notes + "\n")
+1
View File
@@ -0,0 +1 @@
#define SUNNYPILOT_VERSION "2025.002.000"
+1 -1
View File
@@ -116,7 +116,7 @@ class ModelCache:
class ModelFetcher:
"""Handles fetching and caching of model data from remote source"""
MODEL_URL = "https://docs.sunnypilot.ai/driving_models_v7.json"
MODEL_URL = "https://docs.sunnypilot.ai/driving_models_v8.json"
def __init__(self, params: Params):
self.params = params
+1 -1
View File
@@ -37,7 +37,7 @@ class CarSpecificEventsSP:
# TODO-SP: add 1 m/s hysteresis
if CS.vEgo >= self.CP.minEnableSpeed:
self.low_speed_alert = False
if CS.gearShifter != GearShifter.drive:
if self.CP.minEnableSpeed >= 14.5 and CS.gearShifter != GearShifter.drive:
self.low_speed_alert = True
if self.low_speed_alert:
events.add(EventName.belowSteerSpeed)
+7 -3
View File
@@ -11,7 +11,7 @@ from opendbc.car.interfaces import CarInterfaceBase
from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog
from openpilot.sunnypilot.selfdrive.controls.lib.nnlc.helpers import get_nn_model_path
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Mode as SpeedLimitMode
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.helpers import set_speed_limit_assist_availability
import openpilot.system.sentry as sentry
@@ -87,8 +87,7 @@ def _cleanup_unsupported_params(CP: structs.CarParams, CP_SP: structs.CarParamsS
params.remove("SmartCruiseControlVision")
params.remove("SmartCruiseControlMap")
if params.get("SpeedLimitMode", return_default=True) == SpeedLimitMode.assist:
params.put("SpeedLimitMode", int(SpeedLimitMode.warning))
set_speed_limit_assist_availability(CP, CP_SP, params)
def setup_interfaces(CI: CarInterfaceBase, params: Params = None) -> None:
@@ -116,4 +115,9 @@ def initialize_params(params) -> list[dict[str, Any]]:
"SubaruStopAndGoManualParkingBrake",
])
# tesla
keys.extend([
"TeslaCoopSteering",
])
return [{k: params.get(k, return_default=True)} for k in keys]
@@ -22,13 +22,13 @@ LongitudinalPlanSource = custom.LongitudinalPlanSP.LongitudinalPlanSource
class LongitudinalPlannerSP:
def __init__(self, CP: structs.CarParams, mpc):
def __init__(self, CP: structs.CarParams, CP_SP: structs.CarParamsSP, mpc):
self.events_sp = EventsSP()
self.resolver = SpeedLimitResolver()
self.dec = DynamicExperimentalController(CP, mpc)
self.scc = SmartCruiseControl()
self.resolver = SpeedLimitResolver()
self.sla = SpeedLimitAssist(CP)
self.sla = SpeedLimitAssist(CP, CP_SP)
self.generation = int(model_bundle.generation) if (model_bundle := get_active_bundle()) else None
self.source = LongitudinalPlanSource.cruise
self.e2e_alerts_helper = E2EAlertsHelper()
@@ -5,7 +5,10 @@ This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
from cereal import custom, car
from openpilot.common.constants import CV
from openpilot.common.params import Params
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Mode as SpeedLimitMode
def compare_cluster_target(v_cruise_cluster: float, target_set_speed: float, is_metric: bool) -> tuple[bool, bool]:
@@ -17,3 +20,25 @@ def compare_cluster_target(v_cruise_cluster: float, target_set_speed: float, is_
req_minus = v_cruise_cluster_conv > target_set_speed_conv
return req_plus, req_minus
def set_speed_limit_assist_availability(CP: car.CarParams, CP_SP: custom.CarParamsSP, params: Params = None) -> bool:
if params is None:
params = Params()
is_release = params.get_bool("IsReleaseSpBranch")
disallow_in_release = CP.brand == "tesla" and is_release
always_disallow = CP.brand == "rivian"
allowed = True
if disallow_in_release or always_disallow:
allowed = False
if not CP.openpilotLongitudinalControl and CP_SP.pcmCruiseSpeed:
allowed = False
if not allowed:
if params.get("SpeedLimitMode", return_default=True) == SpeedLimitMode.assist:
params.put("SpeedLimitMode", int(SpeedLimitMode.warning))
return allowed

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