Compare commits

..

587 Commits

Author SHA1 Message Date
Jason Wen
057c526e4e Merge branch 'feature/slc' into ui-sla-control-only 2025-09-18 13:32:09 -04:00
Jason Wen
9798e111fc make sure to return the correct type 2025-09-18 13:31:55 -04:00
Jason Wen
1a2d9a6ca3 rename and move around 2025-09-18 12:20:01 -04:00
Jason Wen
ce53fe715a start rename 2025-09-18 11:30:11 -04:00
Jason Wen
02eefa9b7a Merge branch 'feature/slc' into ui-sla-control-only 2025-09-18 10:58:38 -04:00
Jason Wen
48b4febb08 fix 2025-09-18 10:57:47 -04:00
Jason Wen
17429857a5 auto by default for now (reimplement in another PR) 2025-09-18 10:06:05 -04:00
Jason Wen
e317cb4ab2 Merge branch 'feature/slc' into ui-sla-control-only 2025-09-18 06:57:53 -04:00
Jason Wen
f64797f87c overriding state 2025-09-18 06:44:34 -04:00
Jason Wen
15c51ddcb2 more rename 2025-09-18 06:27:12 -04:00
Jason Wen
bdebc861ac rename policy 2025-09-18 00:38:01 -04:00
Jason Wen
2542e86587 params rename 2025-09-18 00:36:36 -04:00
Jason Wen
1c65c7e084 long only 2025-09-18 00:35:50 -04:00
Jason Wen
d6fb5e079e Speed Limit Warning (SLW) in another PR 2025-09-18 00:33:29 -04:00
Jason Wen
e58d810fa4 Merge branch 'feature/slc' into ui-sla-control-only
# Conflicts:
#	selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h
#	sunnypilot/selfdrive/controls/lib/speed_limit_controller/speed_limit_controller.py
#	sunnypilot/selfdrive/controls/lib/speed_limit_controller/speed_limit_resolver.py
#	sunnypilot/selfdrive/controls/lib/speed_limit_controller/state.py
2025-09-18 00:20:55 -04:00
Jason Wen
c895969de1 in another PR 2025-09-18 00:20:00 -04:00
Jason Wen
a2e6dfdb1a Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into feature/slc
# Conflicts:
#	selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.cc
#	selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h
2025-09-18 00:09:10 -04:00
Jason Wen
c95cff27e8 Speed Limit Control -> Speed Limit Assist 2025-09-18 00:08:23 -04:00
Jason Wen
1f8941367d Intelligent Cruise Button Management (ICBM) (#1242)
* init

* slightly more

* check across all

* publish on CC_SP

* more infra setup

* try it out for HKG for now

* slight cleanup

* oops

* legacy

* send

* actually take over

* expose toggle

* icbm

* need to allow

* fix

* name

* small fixes

* actually send it now

* set default

* use cs is_metric

* offroad only lol

* allow them all

* fix

* send desire as-is

* use stock method

* clean up hysteresis

* speed cluster may be more accurate

* rename

* allow init and resume from pcmCruise

* just send it

* fix

* only allow custom v cruise after no button press at initial enabled

* no hysteresis for now

* fix tests

* fix min check

* only apply to non pcm changes

* add ICBM

* some more ui

* bump

* slight cleanup

* fixup

* cleanup

* type hints

* type hints

* bump

* bump

* bring back hysteresis

* fix ui

* do not spam if overriding or below allowed speed
2025-09-18 00:06:16 -04:00
Jason Wen
4a656e9b80 Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into feature/slc
# Conflicts:
#	cereal/custom.capnp
#	selfdrive/controls/lib/longitudinal_planner.py
#	sunnypilot/selfdrive/controls/lib/longitudinal_planner.py
2025-09-17 23:51:27 -04:00
Jason Wen
784e1d6658 Smart Cruise Control: Vision (SCC-V) (#997)
* Controls: Vision Turn Speed Control

* fix

* Data type temp fix

* format

* more

* even more

* self contain targets

* state cleanup

* fix

* param updates

* no need

* use similar state machine

* raise exception if not found

* new state

* entirely internal

* use long active

* more

* rename and expose aTarget

* rename to SCC-V

* init tests

* slight tests

* expose toggle

* lint

* todo

* remove lat planner sub and mock sm data

* introduce aTarget

* rename

* rename

* update fill_model_msg.py to calculate PLAN_T_IDXS for lanelines and road edges

* sync upstream

* no SCC-V yet

* Revert "no SCC-V yet"

This reverts commit b67281bcac.

* wrap it with SCC main

* leave enabled out of here

* wat

* enabled and active on cereal

* OP long for now, enable for ICBM once merged

* need this

* unused

* let's go hybrid

* fix

* add override state

* update tests

* huh

* don't math here if not enabled

* ui: Smart Cruise Control - Vision (SCC-V) (#1253)

* vtsc-ui

* slight cleanup

* more cleanup

* unused

* a bit more

* pulse like it's hot

* draw only enabled and active

* let's try this for now

* settle

* finalize UI

* brighter color so we blind devtekve

* add long override

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>

* slight cleanup

* more

* type hints

---------

Co-authored-by: discountchubbs <alexgrant990@gmail.com>
Co-authored-by: Kumar <36933347+rav4kumar@users.noreply.github.com>
2025-09-17 22:55:36 -04:00
Jason Wen
cb94d3b055 Longitudinal: Smart Cruise Control prerequisites (#1249)
* Controls: Vision Turn Speed Control

* fix

* Data type temp fix

* format

* more

* even more

* self contain targets

* state cleanup

* fix

* param updates

* no need

* use similar state machine

* raise exception if not found

* new state

* entirely internal

* use long active

* more

* rename and expose aTarget

* rename to SCC-V

* init tests

* slight tests

* expose toggle

* lint

* todo

* remove lat planner sub and mock sm data

* introduce aTarget

* rename

* rename

* update fill_model_msg.py to calculate PLAN_T_IDXS for lanelines and road edges

* sync upstream

* no SCC-V yet

* Revert "no SCC-V yet"

This reverts commit b67281bcac.

* wrap it with SCC main

* no SCC-V yet

* noqa now

* fix

* OP long for now, enable for ICBM once merged

* type hints

* let's get it straight from carcontrol instead

* not needed

* unused

* add source to track

* we can do this

---------

Co-authored-by: discountchubbs <alexgrant990@gmail.com>
2025-09-16 22:51:32 -04:00
DevTekVE
94f93a9f26 ui: Add standstill timer to HUD (#1251)
* Add standstill timer to HUD

- Introduced a timer displaying elapsed time when the car is at a standstill.
- Added settings toggle to enable/disable this feature.
- Updated UI elements and related logic to support the standstill timer.

* ruff be happy

* stop screaming

* c stands for not cereal

* slight cleanup

* a bit more cleanup

* unused

---------

Co-authored-by: nayan <nayan8teen@gmail.com>
Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-09-16 10:05:34 +02:00
Jason Wen
747460363f panda: consolidate supported panda checks (#1248)
* panda: fix upstream merge conflicts

* move it higher

* consolidate checks

* update

* bump

* actual bump
2025-09-14 23:51:29 -04:00
James Vecellio-Grant
b32c6dafee modeld: add laneline helper for plan indices calculation (#1240)
* modeld: add laneline_helper for plan X indices calculation

* spacing

* keep type hints

* openpilot

* sunnypilot/models/helpers

add modeld helpers to helpers

* Send it from each fill message

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-09-14 21:45:22 -04:00
Jason Wen
d877444264 Merge branch 'master' into feature/slc 2025-09-14 21:34:37 -04:00
DevTekVE
bffb2fb6fa bugfix: param store to support the latest param changes (#1244)
* bugfix: update parameter handling to use custom CarControlSP.Param and improve param retrieval

* bump opendbc
2025-09-14 20:22:51 +02:00
Jason Wen
688b694266 Sync: commaai/openpilot:master into sunnypilot/sunnypilot:master (#1229) 2025-09-13 17:42:17 -04:00
Jason Wen
ec8f036850 Merge branch 'upstream/openpilot/master' into sync-20250908
# Conflicts:
#	.github/workflows/selfdrive_tests.yaml
#	README.md
#	docs/CARS.md
#	opendbc_repo
#	panda
#	selfdrive/car/tests/test_car_interfaces.py
#	selfdrive/modeld/modeld.py
#	selfdrive/selfdrived/selfdrived.py
#	selfdrive/ui/translations/main_ar.ts
#	selfdrive/ui/translations/main_de.ts
#	selfdrive/ui/translations/main_es.ts
#	selfdrive/ui/translations/main_fr.ts
#	selfdrive/ui/translations/main_ja.ts
#	selfdrive/ui/translations/main_ko.ts
#	selfdrive/ui/translations/main_pt-BR.ts
#	selfdrive/ui/translations/main_th.ts
#	selfdrive/ui/translations/main_tr.ts
#	selfdrive/ui/translations/main_zh-CHS.ts
#	selfdrive/ui/translations/main_zh-CHT.ts
#	system/hardware/hardwared.py
#	system/updated/updated.py
#	tinygrad_repo
#	uv.lock
2025-09-13 15:23:36 -04:00
Nayan
4f44d6e643 Reapply "UI: Developer UI" (#1238) (#1239)
This reverts commit 1be13fdc55.

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-09-12 10:58:59 -04:00
Jason Wen
1be13fdc55 Revert "UI: Developer UI" (#1238)
* Revert "Revert & Reapply "UI: Developer UI" temporarily due to QT version mismatch (#1237)"

This reverts commit 810a2d9448.

* Revert "UI: Developer UI (#1233)"

This reverts commit 1bb4ca2547.
2025-09-12 08:37:24 -04:00
DevTekVE
810a2d9448 Revert & Reapply "UI: Developer UI" temporarily due to QT version mismatch (#1237)
* Revert "UI: Developer UI (#1233)"

This reverts commit 1bb4ca2547.

* Reapply "UI: Developer UI (#1233)"

This reverts commit b0a77049da.

* QColorConstants is not on device's QT version. Thanks @kumar for the fix
2025-09-12 09:03:17 +02:00
Jimmy
c9dbf97649 jotpluggler: add icons, use monospace font, and fix ui quirks (#36141)
* use play/pause icons

* use monospace font

* x button for delete

* add icons for splitting

* many scaling + scrollbar fixes and niceties

* simplify texture loading code
2025-09-11 23:31:32 -07:00
Nayan
1bb4ca2547 UI: Developer UI (#1233) 2025-09-12 01:00:05 -04:00
Adeeb Shihadeh
2c04a27a2a ubloxd: cleanup unused files 2025-09-11 14:03:37 -07:00
DevTekVE
b7f8dd11a5 SL: bugfix parameter handling in sunnylink restore and remote setting (#1234)
* refactor: improve parameter handling in sunnylink for robustness

- Updated `get_param_as_byte` to return `None` for nonexistent parameters.
- Enhanced param compression and encoding in `sunnylinkd`.

* refactor: centralize parameter restoration with new helper function

- Added `save_param_from_base64_encoded_string` to handle param decoding and saving.
- Updated backup manager and sunnylinkd to use the new method.
- Improved code readability and reduced duplication in parameter handling logic.

* don't bother

* clean
2025-09-11 21:44:43 +02:00
Adeeb Shihadeh
70c0592e84 CI: re-enable macOS build (#36120)
* CI: re-enable macOS build

* Update selfdrive_tests.yaml with new env variable
2025-09-11 11:03:59 -07:00
Jimmy
572c03dbac jotpluggler: fix flashing while searching (#36128)
* modify in place instead of recreating nodes

* don't delete DataTreeNodes and simplify code

* faster: more efficient state tracking, better handler deletion
2025-09-11 10:48:45 -07:00
Adeeb Shihadeh
fa498221da still thinking about this one 2025-09-11 10:48:32 -07:00
vanillagorillaa
67238d5045 Update release notes (#36137)
Update RELEASES.md
2025-09-11 10:47:23 -07:00
Jimmy
994170ddb5 fix qcom decoder compilation on mac with platform check (#36131) 2025-09-11 10:45:36 -07:00
Jason Young
3c28188d7a Honda: Add Honda N-Box 2018 to release (#36134)
* bump opendbc

* regen CARS.md

* add to RELEASES.md
2025-09-11 07:04:15 -04:00
Jason Young
4ccd17903b correction to Honda release notes (#36133)
correction to release notes
2025-09-11 05:59:15 -04:00
Jason Young
0e1b573f89 Honda: Add Honda Odyssey 2021-25 to release (#36132)
* bump opendbc

* regen CARS.md

* add to RELEASES.md

* forgot this was originally VG's PR

* correctly typo the typo

* follow recent DBC cleanup
2025-09-11 05:32:44 -04:00
Maxime Desroches
10580aca92 ci: adjust power draw bounds (#36130)
* consider min

* bounds
2025-09-10 15:06:25 -07:00
Jimmy
6b13175338 jotpluggler: better handle sparse message data and bools (#36124)
* better handle sparse message data

* fix plotting of of bools

* add type for msg._valid

* fix typing

* add assert in case something changes in future
2025-09-10 00:09:08 -07:00
Jason Wen
3c0d16ae69 less 2025-09-09 23:41:32 -04:00
Jason Wen
c5d95f0e8f add carstateSP 2025-09-09 23:34:26 -04:00
Jason Wen
8f8561b88d already happens while in enabled 2025-09-09 23:00:43 -04:00
YassineYousfi
d0171084b5 Update RELEASES.md 0.10.1 2025-09-09 15:40:39 -07:00
Jason Young
2bfdd0d61d PlotJuggler: Updated layout for torque controller (#36123)
* PlotJuggler: Updated layout for torque controller

* yeah, no
2025-09-09 18:02:31 -04:00
Jason Wen
6b217a0d10 update event 2025-09-09 16:55:14 -04:00
Jason Wen
2ac51c182b fix events 2025-09-09 16:37:23 -04:00
Jimmy
ea53111afc basic jotpluggler (#36045)
* jotpluggler!

* demo, executable, fontfile

* calc max and min, numpy, cloudlog

* mypy things

* simplified data.py

* multiprocessed data ingest

* allow verrryyy long search results

* stream in multiprocessed segments

* bug fixes

* simplify and speed up timeseries

* small fixes

* rewrite layout

* resizable layouts

* cleanup

* downsampling

* deque for consistency

* use item_visible_handler

* only build visible UI

* don't delete item handlers, add locks, don't expand large lists

* delete item handlers after a frame

* small data tree improvements

* seperate datatree into its own file

* reset when loading new segments

* fix plot window resizing and recursive split resizing logic
2025-09-09 10:56:07 -07:00
Jason Wen
183896f01a move around 2025-09-09 11:05:55 -04:00
Jason Wen
c928e32c04 fix 2025-09-09 02:53:37 -04:00
Jason Wen
8ae9974988 more lint 2025-09-09 02:38:15 -04:00
Jason Wen
e217604b20 lint 2025-09-09 02:14:07 -04:00
Jason Wen
1fd2a8ca1d no longer needed 2025-09-09 02:08:14 -04:00
Jason Wen
29ff34821c more resolver refactor 2025-09-09 02:04:24 -04:00
Jason Wen
51d2d7d5f5 turn off debug 2025-09-09 01:43:44 -04:00
Jason Wen
bf64fa29f7 refactor speed limit resolver 2025-09-09 01:43:38 -04:00
Jason Wen
20eca71fc5 v_target 2025-09-09 01:04:07 -04:00
Jason Wen
27e112e70c comments 2025-09-08 22:53:03 -04:00
Jason Wen
1365d7925c directly return statuses 2025-09-08 22:52:13 -04:00
Jason Wen
f6b855655a refactor new session check 2025-09-08 22:46:07 -04:00
Jason Wen
44b2e3dff3 refactor preactive timeout check 2025-09-08 22:36:32 -04:00
Jason Wen
6278b9000c one method state machine 2025-09-08 22:27:24 -04:00
Jason Wen
014213d867 typo 2025-09-08 21:09:25 -04:00
github-actions[bot]
0739d4ac2d [bot] Update translations (#36089)
Update translations

Co-authored-by: Vehicle Researcher <user@comma.ai>
2025-09-08 09:01:53 -07:00
DevTekVE
95f75ecf29 Merge branch 'master' into feature/slc 2025-09-08 12:17:37 +02:00
Jason Wen
698e0ca00f migration: new branch names (#1225)
* migration: new branch names

* more migration

* update channel type

* no more var

* update

* more

* more
2025-09-07 23:23:03 -04:00
Adeeb Shihadeh
8dca43881a Rewrite ubloxd in Python (#36112)
* Rewrite ubloxd in Python

* lil more

* rm from third_party/

* cleanup

* ubx replay

* try this

* back to kaitai

* Revert "ubx replay"

This reverts commit 570bd3d25fbabc590379ce0a9f98d30de55cf1b3.
2025-09-07 15:40:48 -07:00
Adeeb Shihadeh
a885111c0c agnos 13.1 (#36113) 2025-09-07 14:21:14 -07:00
Adeeb Shihadeh
bd73664f4c add kaitai python package 2025-09-07 12:21:13 -07:00
Adeeb Shihadeh
608c16007e Rewrite logcatd in Python (#36111)
* Add Python logcatd implementation

* lil more
2025-09-07 11:32:44 -07:00
Adeeb Shihadeh
275abc1eb5 Rewrite proclogd in Python (#36110)
* Rewrite proclogd in Python

* lil more

* lil more

* Update system/proclogd.py

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

* Update system/proclogd.py

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

* Update system/proclogd.py

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

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-07 11:13:39 -07:00
Jason Young
ff34b8af76 selfdrived: disable HUD VisualAlert for belowSteerSpeed events (#36109) 2025-09-07 11:59:48 -04:00
Jason Wen
ff4d1923f0 tici: fix staging root updates (#1223) 2025-09-06 18:46:10 -04:00
Jason Wen
3a91ae08a9 update: actually detect device type as TICI (#1221) 2025-09-06 18:03:16 -04:00
Jason Wen
b161764b1e update: sunnypilot branch migrations for tici (#1212)
* update: sunnypilot branch migrations for tici

* block onroad and notify

* type

* check channel type

* update

* ui init

* no search and locked list for tici

* whenever available
2025-09-06 15:26:32 -04:00
DevTekVE
03e9777c3f Improve debugging for safety (#36055)
* feat: add debugging configurations for replay drive and LLDB attachment

* Add readme with video demo

* clean

* docs: update debugging safety documentation with demo link

* no need for mp4 then added on PR

* Update SConstruct

* bump opendbc

* updating readme

* updating readme

* updating readme

* is this better / worth it?

* final cleanups

* hacky. but does it work?

* Yep that worked!

---------

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-09-06 12:05:15 -07:00
Shane Smiskol
1033d3d80e Desire helper: set lane change direction on entering preLaneChange state (#36074)
* set immediately to avoid flash on right lane changes

* one function

* name

* comment
2025-09-05 22:34:04 -07:00
Jason Wen
7057c57419 ui: cleanup cereal event params parsing (#1219)
* Revert "bugfix: streamline LiveDelay parameter loading with safe handling (#1204)"

This reverts commit 288a5e14da.

* ui: use AlignedBuffer for cereal data processing for Models panel

* align

* separate

* split

* event it

* no more backup

* Revert "no more backup"

This reverts commit fa66ce5e77.
2025-09-05 20:51:58 -04:00
pencilpusher
1f1efec4c9 replay: C3/C3X hardware decoder (#35821)
* bump msgq

* add third_party/linux/include/media/msm_vidc.h

* add sde_rotator hw interface

* add msm_vidc hw decoder interface

* update SConscript to build qcom decoder and rotator

* use qcom decoder in replay framereader

* decode directly to NV12 with the correct stride without using the hw rotator

* bump msgq back to master

* don't compile rotator

* cleanup

* works now but much to simplify

* rm signals

* rm header

---------

Co-authored-by: Test User <test@example.com>
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-09-05 16:05:06 -07:00
DevTekVE
7d4df73ea5 hotfix: model fetcher warning instead of exception when fetching fail 2025-09-05 14:42:08 +02:00
James Vecellio-Grant
29fe152bd3 modeld_v2: desire rename and add many parts from thneed modeld (#1197)
* Add model metadata lookup and update desire handling

* Bump selector version to 10

* meh

* Refactor shape mode parameters for desire handling in test buffer logic

* loop more models

* Refactor buffer handling for temporal inputs and streamline desire updates

* Refactor lateral control input handling and remove unused code
2025-09-04 22:26:59 -04:00
Jason Wen
31918c067a events: add sunnypilot/openpilot to remote origin check (#1216)
events: add sunnypilot/openpilot to remote origin check
2025-09-04 22:22:48 -04:00
Jason Wen
daf5ea2783 update: remove git cleanup in finalized stage (#1210)
* updater: remove git cleanup in finalized stage for quicker updates

* nah
2025-09-04 22:10:08 -04:00
Harald Schäfer
f0f04d4b5b Firehose model (#36087)
816ce390-c41a-42fa-a5df-f393cbe2dcc4/400
2025-09-04 18:51:29 -07:00
Shane Smiskol
2b7707ecf6 Deduplicate car interface test (#36101)
deduplicate test car interfaces
2025-09-04 18:20:43 -07:00
Shane Smiskol
ef870d5533 bump opendbc (#36103)
* bump

* update refs
2025-09-04 18:11:44 -07:00
github-actions[bot]
fd7295c980 [bot] Update Python packages (#1214)
Update Python packages

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-04 14:31:01 -04:00
Jason Wen
220cfff04d ci: skip uv lock upgrade on forks (#1213) 2025-09-04 14:29:11 -04:00
Jason Wen
ee0fb6bf8e Revert "[bot] Update Python packages" (#1211)
Revert "[bot] Update Python packages (#1201)"

This reverts commit 0cd2bbf6c0.
2025-09-04 14:19:31 -04:00
github-actions[bot]
0cd2bbf6c0 [bot] Update Python packages (#1201)
Update Python packages

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-04 10:08:51 -04:00
DevTekVE
0871abcf55 bugfix: fix fetching params for sunnylink and backup (#1177)
* Hotfix for the params stuff until I rework this properly and leverage the new data types

* Revert "Hotfix for the params stuff until I rework this properly and leverage the new data types"

This reverts commit c6031b29d92d3ff5b679ffce3ba53611bb2dba0e.

* refactor: enhance getParams function to support JSON and bytes types with optional compression

* refactor: add TODO for enhancing server support of metadata in sunnylinkd.py

* lint and clean

* refactor: update value handling in getParams to return decoded values for JSON serialization

* refactor: simplify params_dict initialization by removing type hint

* refactor: update response handling in getParams to include JSON serialization of params

* refactor: update response handling in getParams to include JSON serialization of params

* Add to dic types

* refactor: extract get_param_as_byte function for improved parameter handling and fix backup inconsistencies

* cleanup

* ensure error propagates on backup fail
2025-09-04 14:45:37 +02:00
DevTekVE
8ccb777192 bugfix: improve exception handling for sunnylinkd (SUN-89) (#1207)
* bugfix: improve exception handling for WebSocket connections in sunnylinkd

* bugfix: enhance exception handling for WebSocket connections in sunnylinkd

* bugfix: improve OSError handling in sunnylinkd for better error reporting
2025-09-04 14:45:03 +02:00
DevTekVE
0593667601 bugfix: improve error handling in model fetching process (SUN-87) (#1205)
* bugfix: improve error handling in model fetching process

* cleanup

* bugfix: refine error handling in model fetching process
2025-09-04 14:44:42 +02:00
Shane Smiskol
a5044302a2 auto source: auto source 2025-09-03 16:06:41 -07:00
Trey Moen
6a4f685d04 feat(esim): bootstrap (#36094)
* bootstrap

* more

* fix

* simple

* moar

* clarify

---------

Co-authored-by: Comma Device <device@comma.ai>
2025-09-03 11:34:03 -07:00
Trey Moen
355499a8de feat(esim): hotswap (#36096)
feat(esim): device hw reboot modem
2025-09-03 11:31:48 -07:00
DevTekVE
288a5e14da bugfix: streamline LiveDelay parameter loading with safe handling (#1204) 2025-09-03 17:18:18 +02:00
James Vecellio-Grant
9447aa0e3d modeld: turn desires (#1182)
* Add modelDataV2SP and lane turn logic implementation

Note: still need to hook up to other modeld's create unit test, fix stuff, and do the UI for it

* add unit tests for lane turn logic

* Add lane turn desire controls to models panel

* use `events_sp` instead of `events`

* integrate modelDataV2SP messaging to the other modeld controllers

* move this to that

* use min for general population here, on custom branches, change this to max :)

* Update events.py

Co-authored-by: royjr <royjr96@gmail.com>

* Update events.py

Co-authored-by: royjr <royjr96@gmail.com>

* refactor lane turn value control into one method

* Update selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc

* add integration tests for lane turn desire

* 10 updates is possibly more representative of real life

* real objects ofc

* desc: add toggle description for clarity

---------

Co-authored-by: royjr <royjr96@gmail.com>
2025-09-03 05:49:12 -07:00
Jason Wen
8b5290b462 no 2025-09-02 22:15:13 -04:00
Jason Wen
0e40024548 finish it up 2025-09-02 22:13:06 -04:00
Jason Wen
711a43082a init better 2025-09-02 22:09:26 -04:00
Jason Wen
87beff9cad use vCruiseCluster for set speed 2025-09-02 21:53:05 -04:00
Jason Wen
e1ac6fef51 more 2025-09-02 11:23:44 -04:00
Jason Wen
fa26dda544 more 2025-09-02 11:14:01 -04:00
Jason Wen
c3e513053c Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into feature/slc 2025-09-02 01:16:59 -04:00
Jason Wen
28544dc803 wrap 2025-09-02 01:16:50 -04:00
Jason Wen
19bb39f09a some more tests 2025-09-02 01:14:37 -04:00
Jason Wen
6acb23ba30 fix 2025-09-02 01:07:27 -04:00
Jason Wen
db9e410bee lint 2025-09-02 01:05:04 -04:00
Jason Wen
0adb5570b9 not really needed yet 2025-09-02 01:05:00 -04:00
Jason Wen
157181bc86 more tests 2025-09-02 01:02:30 -04:00
Jason Wen
b325fb2a9e new tests, fixes controller 2025-09-02 00:54:59 -04:00
Jason Wen
8174b2da51 offset default > off 2025-09-01 23:49:47 -04:00
Jason Wen
7824e73272 rename 2025-09-01 22:29:26 -04:00
Jason Wen
ebc117af1d clean 2025-09-01 22:29:00 -04:00
commaci-public
67fd6c80dd [bot] Update Python packages (#36090)
* Update Python packages

* no more stall

---------

Co-authored-by: Vehicle Researcher <user@comma.ai>
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-09-01 09:37:18 -07:00
Jason Wen
800920f9bc no more tempinactive 2025-08-31 23:19:53 -04:00
Jason Wen
dcf0dd5d80 fix tests 2025-08-31 12:12:22 -04:00
Jason Wen
e4ae2a7774 introduce disabled, no longer transitions at inactive 2025-08-31 12:06:01 -04:00
Jason Wen
3fe2ec883f no 2025-08-31 10:11:41 -04:00
Jason Wen
3d065a066c wide open 2025-08-31 10:11:01 -04:00
Jason Wen
25668fcf33 no speed factor engage type yet 2025-08-31 10:02:12 -04:00
Jason Wen
db2edc944d no warning in this PR 2025-08-31 10:01:02 -04:00
Jason Wen
1fc7071584 off 2025-08-31 09:58:22 -04:00
Kumar
43c12ae7b3 Visual: 🌈 road (#1067)
* 🌈

* Update selfdrive/ui/qt/onroad/model.cc

Co-authored-by: royjr <royjr96@gmail.com>

* ui: enhance rainbow mode description and add colorized text rendering

---------

Co-authored-by: royjr <royjr96@gmail.com>
Co-authored-by: DevTekVE <devtekve@gmail.com>
2025-08-31 10:30:20 +02:00
Nayan
1894a312d3 Bug: Fix OSM Download Time & ETA (#1194)
fix osm download time
2025-08-31 08:46:20 +02:00
DevTekVE
3e9545670b feature: Adding support for copyparty (#1116)
* feat: add support for copyparty-sfx

* feat: add toggle for Copyparty service in developer panel

* feat: enhance Copyparty configuration with additional volume mounts and options

* Update system/manager/process_config.py

* remove f string

* lint
2025-08-31 08:29:45 +02:00
Nayan
45ee58b1f6 ui: Favorite Models (#1168)
* init model favorites

* fix fav buttons

* fix blank favs

* switch to ref

* new favs at top

* remove debug prints & add some comments

* button style

* fix current selection

* !@%#$%(@^%$#(@!%#^

* add last update date to folders
2025-08-31 08:27:08 +02:00
Michael
3f3c293559 reeadme: Reorder tables to show -new branches first (#1191)
* Update to Readme.MD install instructions

This commit changes a few things in the installation guide. I moved the the tables that have the branches and install URLs. I also added a TIP that let's users know that they can install with sunnypilot/staging-c3-new.

* Update README.md with proposed changes from DevTek

Added header text over the legacy branches to bring in separation and let users know they are not recommended.

* bit of change

* Reorganizing a bit more

---------

Co-authored-by: DevTekVE <devtekve@gmail.com>
2025-08-31 07:35:14 +02:00
Jason Wen
4eab2b01e4 end session if long_active but slc inactive at any given time 2025-08-31 01:27:19 -04:00
Jason Wen
5d2fc14a24 always reset state 2025-08-31 01:24:13 -04:00
Jason Wen
20ff0b8d7b bump 2025-08-31 01:19:22 -04:00
Jason Wen
d9b11dec9a too limiting 2025-08-31 01:07:43 -04:00
Jason Wen
0f2db833d5 some tests 2025-08-31 01:05:26 -04:00
Jason Wen
0ff8e3be3c track session 2025-08-31 00:33:08 -04:00
Jason Wen
e454ca42c9 use frame instead of time 2025-08-31 00:14:57 -04:00
Jason Wen
27fe7aa83f test init 2025-08-31 00:06:07 -04:00
Jason Wen
791f597bf6 fix params 2025-08-31 00:05:12 -04:00
Jason Wen
2bd87ff6a0 no need to pass sm 2025-08-30 23:48:43 -04:00
Jason Wen
a6ea4e31b4 split speed limit resolver out of slc 2025-08-30 23:44:20 -04:00
Jason Wen
84abd66bba use frames instead 2025-08-30 23:35:04 -04:00
Jason Wen
e6a6476740 some 2025-08-30 22:43:02 -04:00
Jason Wen
22fd56e32e Revert "not used for now"
This reverts commit f0083d6241.
2025-08-30 22:40:49 -04:00
Jason Wen
f0083d6241 not used for now 2025-08-30 22:38:31 -04:00
Jason Wen
68d7a955f7 Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into feature/slc 2025-08-30 22:17:41 -04:00
Jason Wen
e1d5b9019b fix 2025-08-30 22:00:13 -04:00
Jason Wen
3408873018 wrong cruise speed 2025-08-30 21:54:42 -04:00
DevTekVE
5d110bcee5 ci: prebuilt process improvement & tag of staging prebuilt source (#1190)
* ci: add validate-test-on-staging-c3 branch to deployment triggers and enhance stable branch handling

* fix long overdue mistake lol

* ci: add condition to wait for start on push events in build workflow

* Fix extra version identifier

* no need for this, i validated what I needed

* only care for release tags, not any

* fix: update versioning logic to use build date and run number for tagging

* fix: update tagging logic and enhance commit message format in build scripts

* fix: refine tagging condition to exclude tag pushes for stable branches

* fix: add extra version identifier to output for better version tracking

* trying to keep things clean and simple

* bugfix
2025-08-30 14:35:05 +02:00
DevTekVE
62bf9fcc27 ci: tweaking the deploy with delay process + fixing bugs (#1189)
* ci: disable cancel-in-progress for publish concurrency

* check using var

* typo

* ci: update publish concurrency settings to use dynamic cancel-in-progress flag

* typoooo

* ci: update cancel-in-progress condition for publish concurrency

* ci: enhance publish concurrency handling to queue jobs based on commit SHA

* typos and new commit hash to test cancel in progress

* see if this helps?

* tired of waiting

* ci: add publish concurrency group to deployment configuration

* ci: update publish concurrency handling to improve job queuing and cancellation logic

* ci: output GITHUB_OUTPUT contents for better debugging of publish concurrency

* ci: remove prebuilt output from strategy and streamline GITHUB_OUTPUT handling

* ci: refine publish concurrency handling for flexible job cancellation

- Default `cancel_publish_in_progress` to `true` if undefined in config.
- Adjust concurrency group logic to handle null and true conditions properly.

* another ocmmit shouldnt cancel publish

* ci: enhance job cancellation logic for publish concurrency handling

* ci: add prepare_strategy job for dynamic deploy strategy extraction

* ci: ensure job execution always proceeds on success and skips failure

* ci: improve job execution conditions to handle cancellation and failure states

* ci: enhance versioning logic to support stable and unstable branch differentiation

* ci: add checkout step to ensure code is available for deploy strategy extraction

* ci: add extra version identifier for stable branch environments

* ci: update extra version identifier format for stable branches

* Grammar, oh, grammar.

* test this
2025-08-30 11:52:57 +02:00
DevTekVE
205863b71f ci: add deploy strategy extraction and refactor publish dependencies (#1118)
* ci: add deploy strategy extraction and refactor publish dependencies

- Introduced `prepare_strategy` step to dynamically extract deployment configurations.
- Adjusted `publish` job to depend on `prepare_strategy` and use its outputs.

* what happens if I do this...

* cleaning

* other test

* ci: update auto_deploy logic in build configuration

* cleaning
2025-08-30 07:26:31 +02:00
YassineYousfi
c990515eaf update RELEASES.md for 0.10.1 2025-08-29 14:16:52 -07:00
Jason Wen
ba1da60c25 NNLC: compute error in torque space (#1185)
* NNLC: compute error in torque space

* bump

* sp happy too

* bump

* lint

* update path

* oops

* test entire loop

* bump

* test gm

* bump

* bump
2025-08-29 22:39:25 +02:00
DevTekVE
54174d1ef0 agnos: split launch for c3 and c3x to support custom agnos (#1186)
* refactor: skip AGNOS update for tici models in launch script

* back to stock on chffrplus

* feat: enhance launch script for Tici model with error handling and fallback

* empty new line pls
2025-08-29 22:23:58 +02:00
Jason Wen
f2fe63fa5f use existing 2025-08-29 01:03:21 -04:00
Jason Wen
6bea163998 no need 2025-08-29 00:59:03 -04:00
Jason Wen
6956c6ef05 no 2025-08-29 00:57:24 -04:00
Kacper Rączy
76e91da3ad process_replay: use LiveParametersV2 in custom params (#36080)
Fill LiveParametersV2 in get_custom_params_from_lr
2025-08-28 20:11:20 +00:00
Adeeb Shihadeh
9fcac06297 op.sh: fix switch on fresh install 2025-08-28 11:49:31 -07:00
Adeeb Shihadeh
3e2549f2b8 remove tici-specific code (#36078)
* remove tici-specific code

* lil more

* update those
2025-08-28 08:19:39 -07:00
Jason Wen
20feab0eae this 2025-08-28 00:20:46 -04:00
Jason Wen
2aee69d267 rename 2025-08-28 00:15:08 -04:00
Maxime Desroches
63961dec45 jenkins: run pandad test once 2025-08-27 19:04:16 -07:00
Maxime Desroches
7a19a11001 jenkins: tizi loopback device 2025-08-27 18:46:50 -07:00
Maxime Desroches
93f7925c4d jenkins: tizi ox 2025-08-27 18:36:10 -07:00
ZwX1616
a2c5fca787 modeld input queues class (#36072)
* move from xx

* no get_single

* stupid name

* thats fine

* desire_pulse

* 1less

* desire->desire_pulse

* simplify

* reduce copies

* more less
2025-08-27 17:54:53 -07:00
Adeeb Shihadeh
bb06468ead safety standards for forks (#36077)
standards for forks
2025-08-27 16:41:57 -07:00
Adeeb Shihadeh
1d8dc8a69a camerad: remove AR0231 (#36070) 2025-08-27 15:11:58 -07:00
Maxime Desroches
a254a05df0 jenkins: replace tici-common (#36073)
* common

* remove

* test

* Revert "test"

This reverts commit 2c76a8f818e42e0af1d4540dede3595fe0d59ed9.

* Reapply "test"

This reverts commit d9974dd8564d0699dcfa3aac0ffb2dca33f3b47d.

* Revert "Reapply "test""

This reverts commit 2377c6ab20df5dd06886f3dd9a0be07abfce9df6.

* tizi bounds
2025-08-27 14:39:02 -07:00
Maxime Desroches
2aa7648bb8 jenkins: remove ar device 2025-08-27 14:29:39 -07:00
Maxime Desroches
b309bf4173 jenkins: sensord device 2025-08-27 14:26:56 -07:00
Maxime Desroches
a3fcde2ae8 jenkins: tizi-replay 2025-08-27 14:19:23 -07:00
ZwX1616
f8ff156869 modeld: desire->desire_pulse (#36076)
consistent naming
2025-08-27 13:48:23 -07:00
Maxime Desroches
375dfe16a8 jenkins: remove bmx device 2025-08-27 13:39:21 -07:00
felsager
b976135d2f torqued: apply offset (with more robust unit test) (#36075)
* torqued: apply latAccelOffset to torque control feed forward

* test learned latAccelOffset captures roll compensation bias on straight road driving, when the device is not flush in roll relative to the car

* test correct torqued latAccelOffset parameter convergence
2025-08-27 13:06:01 -07:00
Maxime Desroches
f40f7f9ece Revert "torqued: apply offset (#36005)"
This reverts commit 1d74a97ba6.
2025-08-26 21:45:49 -07:00
Jason Wen
13122c6c1d auto draft 2025-08-26 23:26:15 -04:00
Jason Wen
1081dc4d6c rearrange 2025-08-26 20:46:05 -04:00
Jason Wen
727a4ae8cb unused 2025-08-26 20:44:14 -04:00
Jason Wen
561210d2d2 internalize output 2025-08-26 20:34:17 -04:00
Maxime Desroches
ea6677c464 AGNOS 13 (#36069)
* staging

* prod
2025-08-26 17:16:57 -07:00
Jason Wen
863a8a43a9 Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into feature/slc 2025-08-26 19:10:26 -04:00
Jason Wen
30d5f4ed52 more fixes 2025-08-26 19:08:12 -04:00
Maxime Desroches
8258257658 ci: modernize test onroad (#36059)
* start

* fix

* better

* more

* test

* Revert "test"

This reverts commit 17066ac123668cb7280cf85e3f21a3043b4785b0.

* remove
2025-08-26 15:34:34 -07:00
Jaume Balust
f5d67b5eee cereal: fix frequency precision by changing from int to float (#36060) 2025-08-26 15:23:24 -07:00
Maxime Desroches
8ee3c7b485 add back dbus-next 2025-08-26 11:52:58 -07:00
Adeeb Shihadeh
8450f9f333 update: more migration 2025-08-26 09:57:23 -07:00
royjr
342ff24510 feature: external storage (#979)
* external storage

* fix mountStorage

* fix perms

* works for now

* better

* lagless

* move to sp qt

* orderish

* fix ui crash

* cleanup

* fix format

* offroad only

* debug external storage

* dont care about delete

* just use cloudlog

* show logs if using external storage

* better text

* wipe entire drive

* allow partitionless drive to be formatted

* label while formatting

* this works

* better

* cleaner

* cleaner logs

* keep upstream happy

---------

Co-authored-by: DevTekVE <devtekve@gmail.com>
2025-08-26 11:49:55 -04:00
Shane Smiskol
4cd76f4966 raylib networking: prevent concurrently updating networks (#36066)
* dont run by multiple threads at the same time!

* this doesn't work since we rely on is_connected

* Revert "this doesn't work since we rely on is_connected"

This reverts commit 7455b2fe831bf5c9524e8ee71a9966de32a9755a.
2025-08-26 03:55:05 -07:00
Shane Smiskol
ec254074d1 raylib: prevent Firehose from blocking UI (#36067)
* stop blocking ui thread for 1s!!

* rm

* whoopsiedaisy

whoopsiedaisy

* meh
2025-08-26 03:51:45 -07:00
Shane Smiskol
8059106cae raylib networking: reduce DBus calls (#36065)
* this reduces getsettings calls from n*n to n

* these are combined now

* same check
2025-08-26 03:33:08 -07:00
Shane Smiskol
23b4aaf2a5 raylib networking: remove locking on UI thread (#36063)
* use callback queue to make this thread safe and remove locks (which lag ui thread?)

* woah this works

* no more lock!

* always run signal handler and store callbacks, like qt

* debug

* more

* okay not for now

* combine _get_connections and _connection_by_ssid, closer to qt and not an explosion of GetSettings dbus calls

* debug

* try this

* skip

* len

* skip hidden networks

* actually slower

* stash

* back to 8929f37d495a524d4a996d66b82d4a947fbf4f1c

* clean up
2025-08-26 03:25:01 -07:00
Shane Smiskol
5359f6d354 raylib: clean up networking (#36039)
* stasj

* remove one of many classes

* clean up and fix

* clean up

* stash/draft: oh this is sick

* so epic

* some clean up

* what the fuck, it doesn't even use these

* more epic initializers + make it kind of work

* so simple, wonder if we should further 2x reduce line count

* i've never ever seen this pattern b4, rm

* remove bs add niceness

* minor organization

* set security type and support listing and rming conns

* forget and connect

* jeepney is actually pretty good, it's 2x faster to get wifi device (0.005s to 0.002s)

* temp

* do blocking add in worker thread

* add jeepney

* lets finish with python-dbus first then evaluate - revert jeepney

This reverts commit 7de04b11c2285c298bb1ec907782026c795ab207.

and

* safe wrap

* missing

* saved connections

* set rest of callbacks

* skip hidden APs, simplify _running

* add state management

* either wrong password or disconnected for now

* i can't believe we didn't check this...

* disable button if unsupported!!!

* hide/show event no lag hopefully yayay

* fix hide event

* remove old wifi manager

* cache wifi device path + some clean up

* more clean up

* more clean up

* temp disable blocking prime thread

* hackily get device path once

* ok

* debug

* fix open networks

* debug

* clean up

* all threads wait for device path, and user functions dont ever attempt to get, just skip

* same place

* helper

* Revert "helper"

This reverts commit e237d9a720915fb6bd67c539123d3e2d9d582ce1.

* organize?

* Revert "organize?"

This reverts commit 3aca3e5d629c947711ade88799febeb3f61eda87.

* c word is a bad word

* rk monitor debug for now

* nothing crazy

* improve checkmark responsiveness

* when forgetting: this is correct, but feels unresponsive

* this feels good

* need these two to keep forgetting and activating responsive

* sort by connected, strength, then name

* handle non-critical race condition

* log more

* unused

* oh jubilee is sick you can block on signals!!

* proof of concept to see if works on device

whoiops

* so sucking fick

* ah this is not generic, it's a filter on the return vals

* flip around to not drop

* oh thank god

* fix

* stash

* atomic replace

* clean up

* add old to keep track of what's moved over

* these are already moved

* so much junk

* so much junk

* more

* tethering wasn't used so we can ignore that for now

* no params now

* rm duplicate imports

* not used anymore

* move get wifi device over to jeepney! ~no additional lines

* request scan w/ keepney

* get_conns

* _connection_by_ssid_jeepney is 2x faster (0.01 vs 0.02s)

* do forget and activate

* _update_networks matches!

* rm old update_networks

* replace connect_to_network, about same time (yes i removed thread call)

* no more python-dbus!k

* doesn't hurt

* AP.from_dbus: actually handle incorrect paths w/ jeep + more efficient single call

* properly handle errors

* it's jeepney now

* less state

* using the thread safe router passes a race condition test that conn failed!

* bad to copy from old wifimanager

* fix conn usage

* clean up

* curious if locks are lagging

* not for now

* Revert "curious if locks are lagging"

This reverts commit 085dd185b083f5905a4e71ba3e8c0565175e04aa.

* clean up _monitor_state

* remove tests

* clean up dataclasses

* sort

* lint: okay fine it can be non by virtue of exiting right at the perfect time

* some network clean up

* some wifi manager clean up

* this is handled

* stop can be called manually, from deleting wifimanager, or exiting python. some protection

* its not mutable anymore

* scan on enter

* clean up

* back

* lint

* catch dbus fail to connect

catch dbus fail to connect
2025-08-26 01:23:59 -07:00
Shane Smiskol
a70e4c3074 raylib: rm debug print 2025-08-25 22:30:27 -07:00
Shane Smiskol
7a2f2ddf32 raylib: speed up network panel first load (#36062)
* debug

* debug

* clean up
2025-08-25 22:30:09 -07:00
Shane Smiskol
2dc0f97c93 raylib: fix slow Toggles panel first load (#36061)
fix slow load on toggles page
2025-08-25 22:29:14 -07:00
github-actions[bot]
6bbf42c16a [bot] Update translations (#1183)
Update translations

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-25 23:50:58 -04:00
github-actions[bot]
73e66c4a0b [bot] Update Python packages (#1178)
Update Python packages

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-08-25 21:22:20 -04:00
Shane Smiskol
15fcbf24f1 raylib home ui: show/hide events (#36058)
* it's a widget

* proper events

* bottom
2025-08-25 15:52:13 -07:00
Shane Smiskol
e89c6b3b88 raylib: remove redundant networking class (#36057)
remove a class
2025-08-25 15:23:14 -07:00
Shane Smiskol
c4a7f25b62 raylib: refactor NetworkManager constants (#36056)
* new file

* import

* and this
2025-08-25 15:17:37 -07:00
nayan
28eb825013 Revert "mapd: improved system transforms GPS navigation from a basic "am I near a road?" check into an intelligent map matching system that understands movement patterns, GPS reliability, and road network"
This reverts commit ea1e521306.
2025-08-25 17:26:13 -04:00
rav4kumar
ea1e521306 mapd: improved system transforms GPS navigation from a basic "am I near a road?" check into an intelligent map matching system that understands movement patterns, GPS reliability, and road network 2025-08-25 17:21:55 -04:00
nayan
2d937295ed Merge branch 'feature/slc' into ui/slc-ui 2025-08-25 17:14:41 -04:00
Harald Schäfer
1d74a97ba6 torqued: apply offset (#36005)
* torqued: apply latAccelOffset to torque control feed forward 

* test learned latAccelOffset captures roll compensation bias on straight road driving, when the device is not flush in roll relative to the car

* test correct torqued latAccelOffset parameter convergence

---------

Co-authored-by: felsager <d.felsager@gmail.com>
2025-08-25 13:50:10 -07:00
nayan
4a0b30ae35 omg sunny.. pls 2025-08-25 16:29:36 -04:00
nayan
b8620fb843 Merge branch 'feature/slc' into ui/slc-ui 2025-08-25 16:25:44 -04:00
nayan
200d6145dc sunny pls 2025-08-25 16:00:49 -04:00
commaci-public
aea467ff02 [bot] Update Python packages (#36053)
* Update Python packages

* bump

---------

Co-authored-by: Vehicle Researcher <user@comma.ai>
Co-authored-by: Shane Smiskol <shane@smiskol.com>
2025-08-25 11:43:49 -07:00
Nayan
9579d331fc ui: sunnylink panel title & message (#1181)
add title & message to clarify sponsorship isn't required for basic functions
2025-08-25 19:49:49 +02:00
Jason Wen
1f017c411c drop new state machine for now 2025-08-25 13:31:28 -04:00
Jason Wen
ca1a626d7a fix 2025-08-25 08:16:08 -04:00
Jason Wen
9822179d47 no more 2025-08-25 08:01:50 -04:00
Jason Wen
ff0c891b5f params fix 2025-08-24 23:27:57 -04:00
Jason Wen
2e0ace119c fix import 2025-08-24 23:27:57 -04:00
Jason Wen
132a109798 rename 2025-08-24 23:27:57 -04:00
Jason Wen
7b9568d0ab user confirm in another PR 2025-08-24 23:27:57 -04:00
Jason Wen
676f48c9b5 Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into feature/slc
# Conflicts:
#	common/params_keys.h
#	selfdrive/selfdrived/selfdrived.py
2025-08-24 22:25:57 -04:00
James Vecellio-Grant
7c6d887187 modeld_v2: infer model shapes from inputs (#1162)
* modeld_v2: dynamify temporal buffer management.

* skip redundant reshaping and flattening.

* simplify MHP checks for lead and plan

* modeld_v2: add unit tests for buffer logic and refactor index mapping

* Let’s possibly fail a test :)

* Update test_buffer_logic_inspect.py

* Update test_buffer_logic_inspect.py

* modeld_v2: better temporal mapping for non-split

* Bump to 10 I guess

* Downgrade CURRENT_SELECTOR_VERSION to 9

* red diff ya know?

* add dynamic buffer update tests and compare against legacy logic.

 Cover modelState.init and modelState.run

* send

* Revert "send"

This reverts commit 9e6c95fbfd.

* format

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-24 22:08:55 -04:00
github-actions[bot]
f89796033c [bot] Update translations (#1179)
Update translations

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-08-24 15:52:38 -07:00
Jason Wen
c8249f3657 Sync: commaai/openpilot:master into sunnypilot/sunnypilot:master (#1176) 2025-08-24 14:56:35 -04:00
Jason Wen
798e9071d8 Merge branch 'upstream/openpilot/master' into sync-20250823
# Conflicts:
#	.github/workflows/release.yaml
#	README.md
#	RELEASES.md
#	common/params_keys.h
#	docs/CARS.md
#	opendbc_repo
#	panda
#	release/build_stripped.sh
#	selfdrive/controls/lib/longitudinal_planner.py
#	selfdrive/modeld/modeld.py
#	selfdrive/ui/feedback/feedbackd.py
#	selfdrive/ui/translations/main_ar.ts
#	selfdrive/ui/translations/main_de.ts
#	selfdrive/ui/translations/main_es.ts
#	selfdrive/ui/translations/main_fr.ts
#	selfdrive/ui/translations/main_ja.ts
#	selfdrive/ui/translations/main_ko.ts
#	selfdrive/ui/translations/main_pt-BR.ts
#	selfdrive/ui/translations/main_th.ts
#	selfdrive/ui/translations/main_tr.ts
#	selfdrive/ui/translations/main_zh-CHS.ts
#	selfdrive/ui/translations/main_zh-CHT.ts
#	system/version.py
#	uv.lock
2025-08-24 14:52:21 -04:00
Comma Device
b501ad4d51 nice encoder debugging script 2025-08-24 00:48:54 +00:00
github-actions[bot]
d6af554db4 [bot] Update translations (#1172)
Update translations

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-23 20:38:19 -04:00
github-actions[bot]
9e50a1b660 [bot] Update Python packages (#1175)
Update Python packages

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-08-23 20:34:53 -04:00
Jason Wen
2b86cc1373 param_store: update list every 3 seconds (#1174) 2025-08-23 09:42:05 -04:00
Shane Smiskol
dd7de180ea raylib: cache API token (#36050)
* cache with time

* safety

* rm

* clean up
2025-08-23 04:56:00 -07:00
Shane Smiskol
2b46e1450a raylib: simplify network state (#36049)
* wtf

* we never disabled unsupported networks

* dont be a hero

* i hate mypy

* fix
2025-08-23 00:49:19 -07:00
Adeeb Shihadeh
7ed8abb66c camerad: garbage collect CL files (#36046) 2025-08-22 20:11:50 -07:00
Adeeb Shihadeh
ef2bb7f2fc release: build orphaned branch (#36047) 2025-08-22 20:06:12 -07:00
github-actions[bot]
de56b21103 [bot] Update Python packages (#1165)
Update Python packages

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-22 19:50:09 -04:00
Jason Wen
5491a61384 ci: skip tinygrad bump in repo-maintenance (#1173) 2025-08-22 19:46:24 -04:00
Adeeb Shihadeh
ae3b74245f sgo is just o now! 2025-08-22 09:08:40 -07:00
Shane Smiskol
c0a74f7a20 raylib: change default tethering password 2025-08-22 01:55:01 -07:00
James Vecellio-Grant
7f035bae39 ui: bugfix visibility for developer panel (#1131)
* yes

idk

move up

* patch

* updates

* Update developer_panel.cc

* Update developer_panel.cc

* Update developer_panel.cc

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-21 21:04:57 -04:00
Shane Smiskol
cea3572b74 raylib: fix mouse scale for Widgets (#36040)
fix mouse scale for mousestate
2025-08-21 16:54:15 -07:00
kostas.pats
cd9ec6b240 Compressed vipc name pick (#36036)
* add custom vipc server name argument

* Update compressed_vipc.py

* add custom vipc server name argument + fixes

* Update compressed_vipc.py
2025-08-20 15:45:05 -07:00
Adeeb Shihadeh
b4cc4ea8e2 Update README.md 2025-08-20 15:44:23 -07:00
Adeeb Shihadeh
154f655335 update release checklist 2025-08-20 15:44:13 -07:00
Warren Togami
638dfb68ba ui: display thousandths place on lagd toggle (#1166)
lagd: display thousandth place so typical variation is visible

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-20 10:18:07 -07:00
Shane Smiskol
2ff707d82f Fix gradient point ignore 2025-08-19 22:37:55 -07:00
Shane Smiskol
8320934d91 raylib: cleanup experimental mode gradient color calculations (#36035)
* dfebug

* simplify

* come on man
2025-08-19 22:33:07 -07:00
Maxime Desroches
63441c048c test_onroad: relax first fid assertion (#36032)
* fid

* test

* Revert "test"

This reverts commit 38e6635dd0b0b9fb9c08bcc3a74b9283207b0c2f.

* r

* Revert "r"

This reverts commit 4037a321f89af137a645345a0fffb73da6071c72.
2025-08-19 22:30:48 -07:00
Shane Smiskol
d0069c136b raylib: fix experimental mode path gradient (#36033)
* fix!

* this is enough to fix the broken colors

* clean up

* fix

* use last colors -- need this so we don't have to always pass perfect gradient

* clean up

* clean up

* clean up
2025-08-19 22:19:56 -07:00
Jason Wen
fa0017fafc car: initialize brand-related settings in opendbc (#1146) 2025-08-19 23:54:07 -04:00
Shane Smiskol
870d19f33d Reapply "File sourcing: Not all files are logs (#36025)"
This reverts commit 3570022b9a.

Fix test
2025-08-19 19:59:50 -07:00
Shane Smiskol
60c34a0837 LogReader: run source test (#36031)
run "slow" test
2025-08-19 19:58:47 -07:00
Shane Smiskol
22e79479d2 unit tests: add comment (#36030)
* remove collection

* test

* back

* wtf it actually saves 10s?!

* ah that makes sense

* rm

* ?

* ugh

* qq

* bc
2025-08-19 19:39:27 -07:00
Maxime Desroches
3570022b9a Revert "File sourcing: Not all files are logs (#36025)"
This reverts commit 18b7ddef8f.
2025-08-19 17:11:53 -07:00
Maxime Desroches
dd5f5fdb98 ci: show all unit test failures (#36029)
* testci

* fix

* Revert "testci"

This reverts commit b62a0aacb604fc0fd39c6e50a726b686979b9880.
2025-08-19 17:11:29 -07:00
Harald Schäfer
18b7ddef8f File sourcing: Not all files are logs (#36025)
* Not all files are logs

* more refactor

* linting ok

* fix tests

* import exception

* whoops forgot to git add

* fix

---------

Co-authored-by: Shane Smiskol <shane@smiskol.com>
2025-08-19 16:25:13 -07:00
Shane Smiskol
5ec9aee216 File sourcing: simplify return type (#36028)
* rm str | none pattern

* clean up

* more clean up

* stash

* Revert "stash"

This reverts commit 3e2472160cc97e9d11922137757d9ef942a0312d.

* fix da prints

* fix cmt
2025-08-19 15:39:44 -07:00
Maxime Desroches
927548621b update to latest userdata partition (#36027)
bump
2025-08-19 15:37:39 -07:00
Shane Smiskol
6005b12f94 format logreader 2025-08-19 15:04:17 -07:00
Jason Young
09aa21390d Honda: Adding support for Honda City (#36026)
* bump opendbc

* release notes

* regen CARS.md

* bump opendbc correctly this time
2025-08-19 15:38:55 -04:00
YassineYousfi
d097a0c201 model parser: fix lead mhp out shape (#36024)
* model parser: fix lead mhp out shape

* fix for real
2025-08-19 11:35:22 -07:00
Adeeb Shihadeh
560c503871 new release flow (#36021)
* new release flow

* Update README.md
2025-08-19 11:19:58 -07:00
YassineYousfi
3d24225cc1 model parser: use check missing for mhp checks (#36023)
* model parser: use check missing for mhp checks

* lint + support re

* lint...

* no walrus

* just remove

* forgot this
2025-08-19 10:19:00 -07:00
YassineYousfi
51314fa9fe Revert "model parser: use check missing for mhp checks" (#36022)
Revert "model parser: use check missing for mhp checks (#36020)"

This reverts commit 803b54ebdb.
2025-08-19 10:09:59 -07:00
YassineYousfi
803b54ebdb model parser: use check missing for mhp checks (#36020)
* model parser: use check missing for mhp checks

* lint + support re

* lint...

* no walrus

* just remove
2025-08-19 10:09:09 -07:00
Jimmy
c085b8af19 feedbackd: remove lkas toggle for this release (#36018)
remove lkas toggle for this release
2025-08-19 09:18:32 -07:00
Adeeb Shihadeh
2cec2587be bump panda 2025-08-19 09:18:14 -07:00
Kirito3481
9e3a35035a Update ko-kr translation (#1167) 2025-08-19 07:24:53 +02:00
Adeeb Shihadeh
2148e2dff2 build_devel: clean submodules 2025-08-18 19:48:08 -07:00
Shane Smiskol
f55f3bb7cd setup is a noun! 2025-08-18 19:33:34 -07:00
Adeeb Shihadeh
4d55671b17 feedbackd: temp disable LKAS button as feedback (#36017)
* feedbackd: temp disable LKAS button as feedback

* disable that

* mark
2025-08-18 18:57:16 -07:00
commaci-public
dfc66d7807 [bot] Update Python packages (#36014)
Update Python packages

Co-authored-by: Vehicle Researcher <user@comma.ai>
2025-08-18 18:52:05 -07:00
Maxime Desroches
31101ecaab AGNOS 12.8 (#36008)
* staging

* prod
2025-08-18 15:37:44 -07:00
James Vecellio-Grant
80d702c866 models panel ui: live description for lagd toggle (#1139)
* Handle decoding directly in ui bc why not

* dynamic max

---------

Co-authored-by: DevTekVE <devtekve@gmail.com>
2025-08-18 13:02:17 -07:00
commaci-public
3d879dd1ae [bot] Update Python packages (#36012)
* Update Python packages

* add psa

---------

Co-authored-by: Vehicle Researcher <user@comma.ai>
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-08-17 17:53:50 -07:00
Muhammed Jaseem Pallikkal
ef9e430992 Fixed development environment link in CONTRIBUTING.md (#36011)
* Fixed development environment link in CONTRIBUTING.md

This is my first PR to openpilot 🎉 excited to contribute!

* Using absolute path for tools
2025-08-17 13:51:12 -07:00
Adeeb Shihadeh
63fa250f29 Add note around excessive actuation check (#36010)
* Add note around excessive actuation check

* Update selfdrived.py
2025-08-17 11:53:20 -07:00
Harald Schäfer
ceb557058c Steam Powered model (#36000)
* f3e67f3e-6079-48cf-92a4-dee5eebd1d73/360

* f3e67f3e-6079-48cf-92a4-dee5eebd1d73/400

* No more action head: a8f96b93-bde2-4e28-a732-4df21ebba968/400
2025-08-17 10:18:30 -07:00
Maxime Desroches
6a67f9e56f setup: custom software warning (#36003)
* warn

* msg

* label

* space

* Revert "space"

This reverts commit ae9b8ad1149612c5741ae3b091740170238473ed.
2025-08-15 23:10:47 -07:00
Maxime Desroches
372682d4a9 updated: branch migration (#35993)
* release

* Update system/updated/updated.py

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>

---------

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-08-15 14:46:20 -07:00
github-actions[bot]
102ac66fab [bot] Update Python packages (#1145)
* Update Python packages

* revert tinygrad

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-15 16:42:35 -04:00
Shane Smiskol
ab44c9a4ff Torque controller: refactor calculations to be in accel space (#35790)
* clean up

* little confusing but works

* clean up

* fix

* pid outputs torque again, fix windup above max torque

* clean up

* fix

* fix

* typo

* fix conflicts

* fix PID

* cleanups

* seems correct

* updte

* inverse

* whitespace

* move

* small cleanup

* more cleanup

* update ref

---------

Co-authored-by: Bruce Wayne <harald.the.engineer@gmail.com>
2025-08-15 11:39:56 -07:00
Adeeb Shihadeh
1805a47139 USB takes forever to come up... 2025-08-15 11:13:45 -07:00
Adeeb Shihadeh
5417efaa1d bump opendbc (#36001) 2025-08-15 11:12:18 -07:00
eFini
4536719353 longitudinal_planner: Convert self.mode to a local variable in update() (#35999)
Make 'mode' variable local
2025-08-15 09:02:38 -07:00
James Vecellio-Grant
34f4aadca5 ci: enforce runner cutoff above 9.0V threshold (#1156)
* ci: github runner auto off when voltage is above 9.0v .

This ensures that a runner in vehicle doesn't accidentally break everything lol.

* suggestion for clarity.

* refactor: rename and update handling of `GithubRunnerVoltage` parameter

- Improve clarity by renaming to `GithubRunnerSufficientVoltage`.
- Changed attribute to `CLEAR_ON_MANAGER_START` for improved runtime state management.
- No need for this value to be backed up!

* refactor: streamline voltage check for GithubRunnerSufficientVoltage

---------

Co-authored-by: DevTekVE <devtekve@gmail.com>
2025-08-15 07:42:56 -07:00
Adeeb Shihadeh
b54d5997de Update RELEASES.md 2025-08-14 21:59:25 -07:00
Maxime Desroches
385ad9e839 updated: connectivity check with new setup (#35998)
* default

* fix
2025-08-14 21:38:27 -07:00
Maxime Desroches
7c6bc70312 params: fix default boolean params (#35997)
* fix

* update test
2025-08-14 20:14:12 -07:00
Shane Smiskol
8ec61991ee LogReader sourcing: remove redundant file existence checks (#35991)
* speed up sourcing but avoiding checking for existence of collected files already from previous sources

* clean up

* been meaning to make them return dicts

* no longer true

* no longer true

* clean up

* more

* more

* revert
2025-08-14 19:28:37 -07:00
Shane Smiskol
1eef956cad LogReader sourcing: return dict (#35994)
* new return type

* fix test

* why not
2025-08-14 19:19:37 -07:00
Maxime Desroches
daef43f620 ci: show all tests durations (#35995)
show
2025-08-14 18:54:56 -07:00
Shane Smiskol
aa91a02db8 LogReader sourcing: check comma API source before CI source (#35992)
sort
2025-08-14 18:26:19 -07:00
eFini
a6d0a88b1e Multilang: update chs/cht translations (#35981) 2025-08-14 10:27:44 -07:00
Jason Young
f2c806f8a0 bump opendbc for fingerprint updates (#35990)
bump opendbc
2025-08-14 11:39:02 -04:00
Jason Young
349c0ec662 Honda: Add several new cars to release (#35989)
* bump opendbc

* regen CARS.md

* update RELEASES.md
2025-08-14 10:30:42 -04:00
Maxime Desroches
741ea44aba AGNOS 12.7 (#35988)
* agnos12.7

* prod
2025-08-13 23:25:09 -07:00
github-actions[bot]
56a89eb4fb [bot] Update translations (#35975)
Update translations

Co-authored-by: Vehicle Researcher <user@comma.ai>
2025-08-13 18:32:10 -07:00
Maxime Desroches
3f830827b2 setup: new flow (#35960)
* start

* remove

* path

* fix

* prepare

* url

* format

* better

* better

* consist

* check

* not real

* ref

* simpler

* fix

* fix

* more

* more

* path

* clean

* line

* progress

* fast

* no

* ori

* flag

* remove

* install

* line

* wait time

* wait install

* Revert "wait time"

This reverts commit 14f750971c3d19b93e4609e9344cb3a8ce9175f4.

* move

* fix

* install

* universal service resources

* fix

* safer

* this is stupid

* time

* cleaner

* comment
2025-08-13 16:07:12 -07:00
Alexandre Nobuharu Sato
a2a385336e Multilang: update pt-BR translation (#35971)
Multilang: update pt-BR translations
2025-08-13 15:20:58 -07:00
Harald Schäfer
be934b3881 fancontroller: remove weird minus (#35983)
* fancontroller: remove weird minus

* another minus
2025-08-13 11:43:50 -07:00
Jimmy
3d6dfc864d clip: terminate processes in clip() instead of in main() (#35984)
* terminate processes in clip() instead of in main()

* context manager for proc
2025-08-13 11:43:35 -07:00
Warren Togami
3cf81c081c bug: Fix "Default" interactivity timeout display (#1154)
If param `InteractivityTimeout` does not exist, timeoutValue == "",
resulting in the Interactivity Timeout UI displaying "s" by default.

Fix displayed "Default" by checking for "0" or "".

Co-authored-by: Nayan <nayan8teen@gmail.com>
2025-08-13 12:12:22 -04:00
DevTekVE
8910668e4e sunnylink: enable uploader option for admins (#1152)
* feat: add sunnylink uploader option for admins in sunnylink panel

* feat: enhance uploader to support zstd compression and improve route handling

* feat: update sunnylink uploader description and enablement criteria for admin tiers

* ui cleanup

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-13 12:12:01 -04:00
Jason Wen
bed8da06dc sunnylink: cleanup unused code in uploader (#1155) 2025-08-13 12:06:03 -04:00
Jason Wen
c490b3ca12 Sync: commaai/openpilot:master into sunnypilot/sunnypilot:master (#1153) 2025-08-13 00:31:44 -04:00
Jason Wen
6c4c0c00b4 Merge branch 'upstream/openpilot/master' into sync-20250812
# Conflicts:
#	opendbc_repo
#	selfdrive/controls/controlsd.py
#	selfdrive/controls/lib/latcontrol_angle.py
#	selfdrive/controls/lib/latcontrol_pid.py
#	selfdrive/controls/lib/latcontrol_torque.py
2025-08-12 23:11:18 -04:00
James Vecellio-Grant
68625222b6 chore: sync tinygrad (#1151)
* commence the sync!

* !cancelled

* Thats it folks
2025-08-12 22:33:06 -04:00
YassineYousfi
8deb1bf285 Down To Ride model 🏎️ (#35982)
* e9237324-4b92-48f5-acaa-ebdf7fe46339/400

* ff4c292c-8e5a-44c0-9b75-e79c60152da2/400

* 1496451e-897b-4a1b-a284-37d244bfddb3/400

* Revert "Revert TR again (#35179)"

This reverts commit e9cea3ae5c.

* try stopping closer

* 5e4cb3d3-b9cc-45c7-a476-38083e75029c/400

* 2164d501-7d2c-467d-b132-be4f85db4164/60

* Revert "2164d501-7d2c-467d-b132-be4f85db4164/60"

This reverts commit 1f4b98ed7d63971507dff94e5ac20223ee15e067.

* 9a836aee-dec6-4f26-8d7e-6db4bb9c8176

* no replace ln

* Revert "no replace ln"

This reverts commit fb5173ced84bb8a07a4e06a5bec43d115404973b.

* opset_version 17

* rebase

* 5f255b73-2e54-46bc-8f80-82c5838165a3/400

* a423dec7-7dcc-4523-aaae-a4012d56b9b5/400

---------

Co-authored-by: Bruce Wayne <harald.the.engineer@gmail.com>
2025-08-12 19:01:56 -07:00
James Vecellio-Grant
28b17858be sunnypilot modeld: refactor gen12 parsing (#1150)
* gen12

* lint

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-12 19:07:07 -04:00
commaci-public
91aec49cee [bot] Update Python packages (#35976)
Update Python packages

Co-authored-by: Vehicle Researcher <user@comma.ai>
2025-08-11 18:43:52 -07:00
Harald Schäfer
cd087a561e Simple plan (#35980)
* squash

* double

* proper merge

* better organization
2025-08-11 17:42:03 -07:00
Shane Smiskol
10cc87b80b raylib: rm some common colors (#35979)
common colors
2025-08-11 17:06:11 -07:00
Jimmy
13d4c6a167 ui: replace "Hotspot" with link icon (#35978)
replace "Hotspot" with link icon
2025-08-11 16:26:07 -07:00
Harald Schäfer
455a6a586a Misc PID refactors (#35844)
* Misc PID refactors

* dead

* finish rename

* unused import

* whitespace

* typo

* fix fan controller

* pid_log

* whitespace

* integral clipping in pid

* update ref

* cleaner

* rm print

* update ref

* revert fan changes

* forgot this
2025-08-11 14:25:29 -07:00
YassineYousfi
c78b302b93 Space Lab 3 🛰️🛰️🛰️ (#35905)
* c147a591-1f86-4ea4-b2b7-391eff1178b5/400

* 6d6639ee-643e-4f72-bd1c-dda546383854/400
2025-08-11 14:07:01 -07:00
Maxime Desroches
a11a8591e4 bump version to 0.10.1 2025-08-11 13:14:48 -07:00
Nayan
ec3f044c83 ui: refresh model list (#1074)
that's all folks

Co-authored-by: Kumar <36933347+rav4kumar@users.noreply.github.com>
Co-authored-by: James Vecellio-Grant <159560811+Discountchubbs@users.noreply.github.com>
2025-08-11 10:24:05 -04:00
Jason Wen
6eaae848c9 Revert "registration required to go onroad" (#1143)
This reverts commit f4b017a7
2025-08-11 08:47:52 -04:00
Jason Wen
fc9a79406f NNLC: cleanup unused attributes (#1142)
* NNLC: cleanup unused attributes

* more cleanup
2025-08-11 08:28:29 -04:00
Maxime Desroches
0bbceb8539 wifi_manager: wait for wifi device (#35974)
wait
2025-08-10 19:41:13 -07:00
royjr
e97ae07589 macOS: fix font-noto-color-emoji (#35972)
Update mac_setup.sh
2025-08-10 09:49:52 -07:00
Kumar
c768cd1973 Merge branch 'feature/slc' into ui/slc-ui 2025-08-10 09:15:11 -07:00
Jason Wen
f45ad6bab9 panda: skip flash and firmware check if deprecated panda is detected (#1117)
* flash: skip if deprecated panda is detected

* skip firmware checks

* wrong

* typing

* fix

* revert
2025-08-10 02:52:02 -04:00
github-actions[bot]
b5cbb980fb [bot] Update translations (#1140)
Update translations

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-10 02:47:39 -04:00
github-actions[bot]
876738e96a [bot] Update Python packages (#1141)
* Update Python packages

* revert

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-10 02:42:02 -04:00
Jason Wen
4116b412a3 Sync: commaai/openpilot:master into sunnypilot/sunnypilot:master (#1134) 2025-08-10 02:20:07 -04:00
Jason Wen
75509aec16 Disable record feedback with LKAS button when MADS is enabled 2025-08-10 02:05:09 -04:00
Jason Wen
97c2d7e655 Merge branch 'upstream/openpilot/master' into sync-20250809
# Conflicts:
#	common/params_keys.h
#	opendbc_repo
#	panda
#	selfdrive/car/cruise.py
#	selfdrive/controls/controlsd.py
#	selfdrive/selfdrived/selfdrived.py
#	selfdrive/test/process_replay/process_replay.py
#	selfdrive/ui/qt/setup/setup.cc
#	tinygrad_repo
2025-08-10 02:05:05 -04:00
Jason Wen
1bc12f1e21 Reapply "LagdToggle: refactor and only instantiate once" (#1137) (#1138)
* Reapply "`LagdToggle`: refactor and only instantiate once" (#1137)

This reverts commit b4f19d4860.

* infinite woo gone

* use them hz
2025-08-09 22:50:29 -04:00
Jason Young
430079113c Revert "Honda: Temporary test exception for driver regen paddle" (#35969)
Revert "Honda: Temporary test exception for driver regen paddle (#35929)"

This reverts commit d15d3c73b8.
2025-08-09 20:57:04 -04:00
Jason Wen
b4f19d4860 Revert "LagdToggle: refactor and only instantiate once" (#1137)
Revert "`LagdToggle`: refactor and only instantiate once (#1130)"

This reverts commit 6ae668e987.
2025-08-09 20:06:10 -04:00
Adeeb Shihadeh
1c46640ea6 Remove more Qt, part 2 (#35968) 2025-08-09 15:04:26 -07:00
Adeeb Shihadeh
2d8030de0b ui: move watch3 to raylib (#35967)
* move to py

* cleaner

* clean that up
2025-08-09 15:00:36 -07:00
Jason Wen
80a4ace1ab ci: use upstream docker build script for cereal validation (#1136) 2025-08-09 17:57:49 -04:00
Jason Wen
b391708b3d Revert "ci: update cereal validation repo reference to sunnypilot" (#1135)
Revert "ci: update cereal validation repo reference to sunnypilot (#1108)"

This reverts commit 08216c1ea4.
2025-08-09 17:40:29 -04:00
Jason Wen
6ef386da3d NNLC: fix friction not being applied to error (#1113)
* params: fix type

* NNLC: fix friction not being applied to error

* another PR

* apply suggestions

* lint
2025-08-09 16:56:37 -04:00
Jason Wen
6ae668e987 LagdToggle: refactor and only instantiate once (#1130)
* wrap the params

* just 1 class and use a single param for now

* refactor

* fix

* cache itself

* no longer

* rename

* type hint

* in helpers instead

* lint

* all

* init as 0 to pass ci

* init as 0 to pass ci

* return_default

* fix init

* add LAT_SMOOTH_SECONDS directly in modeld, temp remove dynamic desc, red difffffffff
2025-08-09 16:51:31 -04:00
github-actions[bot]
72b71d57bc [bot] Update translations (#35965)
Update translations

Co-authored-by: Vehicle Researcher <user@comma.ai>
2025-08-09 12:21:05 -07:00
commaci-public
5339a89e81 [bot] Update Python packages (#35964)
Update Python packages

Co-authored-by: Vehicle Researcher <user@comma.ai>
2025-08-09 12:19:52 -07:00
James Vecellio-Grant
2f60026c22 ci: crosscheck tinygrad ref during tests (#1106)
* Add tinygrad ref testing

* BaseDir and give a fake ref id to test

* one more before the real thing

* Add the correct ref

* test

* Update test_tinygrad_ref.py

* Update tinygrad_ref

* Update test_tinygrad_ref.py

* Update tinygrad_ref

* This SHOULD FAIL

* Revert "This SHOULD FAIL"

This reverts commit 58862f8a73.

* bit of red

* Move ref to models so compiled branches can read it

* step one

* step 2

* Update build-all-tinygrad-models.yaml

* Update build-all-tinygrad-models.yaml

* Update build-all-tinygrad-models.yaml

* Update build-all-tinygrad-models.yaml

* Update build-all-tinygrad-models.yaml

* Update build-all-tinygrad-models.yaml

* Update tinygrad_ref.py

* Update build-all-tinygrad-models.yaml

* bump to fail test

* Revert "bump to fail test"

This reverts commit 4f58991f32.

* pytest should take care of it

* lint

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-09 14:55:52 -04:00
Shane Smiskol
e0f51bdbb6 Reapply "LogReader: wrap events to cache which() (#35882)" (#35909)
* Reapply "LogReader: wrap events to cache which() (#35882)"

This reverts commit ba2dced54c.

* fix lr

* speed up

* clean up

* more

* should be fast

* clean up

* only supports Event

* rmrmr

* bye

* simple

* gix
2025-08-08 23:42:54 -07:00
Maxime Desroches
63d8c6c7f7 ui: adapt InputBox to new touch api (#35962)
new
2025-08-08 22:50:35 -07:00
Maxime Desroches
83f6843a48 ci: run all unit tests (#35959)
* more please

* back
2025-08-08 20:07:33 -07:00
Maxime Desroches
4bb5986c14 setup: fix url for urllib (#35958)
fix
2025-08-08 19:57:20 -07:00
Maxime Desroches
e596704644 ui: remove gui_label usages from setup (#35955)
clean
2025-08-08 16:00:00 -07:00
James Vecellio-Grant
bcc416c7eb ci: adjusting build-single to comply with githubs new input type (#1132) 2025-08-08 15:12:47 -07:00
DevTekVE
38de06232e bugfix: fix backup manager after params change (#1123)
* why? because why not!? damn.

* test

* more disable

* i am hating this

* fuck mypy.

* hopefully this is fixing json

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-08-08 18:02:31 +02:00
Jason Wen
567c5459db params: fix auto type cast (#1127)
* params: fix auto type cast on put

* literally

* lint

* pls comma why dis a string but actually json
2025-08-08 10:26:58 -04:00
Shane Smiskol
fd32fcd20d raylib ui: only process mouse events when enabled (#35948) 2025-08-08 01:09:03 -07:00
Shane Smiskol
a79a5e5a16 revert
i thought i pushed!
2025-08-08 00:36:13 -07:00
Shane Smiskol
5117a8c3a6 ui: test raylib ui (#35949)
* add raylib ui

* test

* this is better for now

* rm

rm

* finalize it

* need this?

* ?

* shite

shite

* try

* ?

* huh

* simp

* ?

* wtf is going on

* ???????????????

* lock

* stash

* no 2 packages

* Revert "stash"

This reverts commit 9efb0d9bda6a6309e7a567634d1921bf1cd0fb59.

* debug

* noo

* debug

* ?

* and

* yeah yeah

* init one

* 2

* i wonder

* oooh

* make sure

* fix dat

* try this

* see if wifiman

* forgot

* ?

* ???

* fuck this we can rewrite it later
2025-08-08 00:34:53 -07:00
Maxime Desroches
1555c0b5fe ui: custom software warning (#35953)
cu
2025-08-07 23:19:48 -07:00
Maxime Desroches
0e9de8f1b1 ui: support text wrapping in Label (#35952)
* lb

* t

* Revert "t"

This reverts commit a9b8e2b9faa5e9d1b189c1dc2ed1aa876e4df476.

* tr

* Revert "tr"

This reverts commit 8de8719ded0fed2b0e5469230e83c13714f88319.

* better

* much better
2025-08-07 23:08:42 -07:00
Shane Smiskol
7bfac9d050 raylib ui: improve is_pressed (#35950)
* stash

* clean up exp

* come on

* fix

* ?

* maybe better

* fix

* same order

* clean up
2025-08-07 16:28:16 -07:00
Maxime Desroches
a800c129b0 run setup and reset at 20FPS for now 2025-08-07 14:33:40 -07:00
Maxime Desroches
f13ec6cb27 wifi manager: correctly handle emoji ssid 2025-08-07 14:22:34 -07:00
Maxime Desroches
f04bb6b9fa ui: reduce network selection lag (#35945)
lag
2025-08-07 13:43:27 -07:00
Brett Sanderson
ed0346980c Update plotjuggler README.md (#35946)
Update README.md

Real example using segment range.  Remove segment count as its not a parameter.
2025-08-07 11:47:50 -07:00
Shane Smiskol
6cf710d4cb Widget: add enabled property (#35944)
* add enabled

* sort

* rename

* rest

* rm that
2025-08-06 22:00:12 -07:00
ZwX1616
8b90c210f8 encoderd: more efficient compression for low res frames (#35924)
* shein says inline

* Update system/loggerd/loggerd.h

Co-authored-by: Shane Smiskol <shane@smiskol.com>

* Revert "Update system/loggerd/loggerd.h"

This reverts commit 3602523cefdeb2a46d77946f7f2cc7fc21bd5a4f.

* Revert "shein says inline"

This reverts commit d3c079e137c5d98068501df636975c5fbf8810ee.

* EncoderSettings

* getter

* update test_encoder

* def

---------

Co-authored-by: Comma Device <device@comma.ai>
Co-authored-by: Shane Smiskol <shane@smiskol.com>
2025-08-06 21:17:10 -07:00
Maxime Desroches
62bbf6db8d ui: use label in confirm dialog (#35943)
forget
2025-08-06 20:11:30 -07:00
Maxime Desroches
a51477d40d ui: use Label in keyboard (#35941)
better
2025-08-06 18:07:06 -07:00
ZwX1616
a84089c6e5 EncoderInfo: encoder setting factorys (#35940) 2025-08-06 16:53:16 -07:00
Jimmy
bb8a2ff65b Remove rerun (#35939)
remove rerun
2025-08-06 16:50:26 -07:00
Maxime Desroches
3a78eee2f9 ui: emoji (#35913)
* emoji

* label

* back

* default

* type

* more

* ico

* device

* clean

* brew
2025-08-06 16:04:19 -07:00
Shane Smiskol
52a4b52628 FileName clean up (#35938)
two spaces!
2025-08-06 14:07:02 -07:00
Jason Young
839a773345 enable lateral accel factor learning for Honda (#35936)
enable torqued for Honda
2025-08-06 16:11:07 -04:00
DevTekVE
c236f472a9 update ISO_LATERAL_ACCEL import + VM changes (#35865)
* refactor: move lateral methods from init to lateral.py (#2594)

* Extracting lateral methods to lateral.py

* cleaning

* more cleaning

* more cleaning

* Making sure it remains where it should

* Leave rate_limit where it belongs

* Moving things to `car/controls/`

* Moving rate limit to get a taste of the changes

* clean

* copy verbatim

* clean up

* more

* now we can format

---------

Co-authored-by: Shane Smiskol <shane@smiskol.com>

* Merge branch 'master' into move-common-vm-methods. dunno what happend with ci

* now we need to move this import

* bump opendbc

---------

Co-authored-by: Shane Smiskol <shane@smiskol.com>
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-08-06 11:53:57 -07:00
Bruce Wayne
ac3d96d2fd Revert "selfdrive.ui.feedback: add init (#35935)"
This reverts commit eca2f40341.
2025-08-05 23:11:19 -07:00
Harald Schäfer
eca2f40341 selfdrive.ui.feedback: add init (#35935)
add init
2025-08-05 23:08:09 -07:00
Maxime Desroches
5e6f942234 gitignore .cache/ from clangd 2025-08-05 22:02:10 -07:00
Maxime Desroches
69ca699773 clip: fix params (#35934)
fix
2025-08-05 21:50:30 -07:00
Harald Schäfer
d1e0a60408 Filename refactor: no enum (#35930)
* conflict

* typing

* typing

* no value

* fix typing

* whitespace

* whitespace

* unused

* Reapply "Filename: minor refactor (#35927)"

This reverts commit 8c7d53004f.

* unused import

* done
2025-08-05 20:37:09 -07:00
Harald Schäfer
999db5b426 Update RELEASES.md 2025-08-05 20:14:01 -07:00
Harald Schäfer
e8135c5431 Update RELEASES.md 2025-08-05 20:11:56 -07:00
Adeeb Shihadeh
978d1c38f1 clip: add speed up support (#35933) 2025-08-05 19:17:58 -07:00
Adeeb Shihadeh
8c7d53004f Revert "Filename: minor refactor (#35927)"
This reverts commit 96313fa4c0.
2025-08-05 19:07:17 -07:00
Mitchell Goff
7413982f0d Lower ALLOW_THROTTLE_THRESHOLD (#35928)
* Lower ALLOW_THROTTLE_THRESHOLD

* Bumped process_replay refs
2025-08-05 17:35:54 -07:00
Maxime Desroches
c95cac3b06 update to latest userdata partition (#35931)
update
2025-08-05 17:11:19 -07:00
Maxime Desroches
fbbb2ef5d0 update release checklist 2025-08-05 16:57:39 -07:00
Jason Young
d15d3c73b8 Honda: Temporary test exception for driver regen paddle (#35929)
Honda: Test exception for driver regen
2025-08-05 19:35:06 -04:00
Harald Schäfer
96313fa4c0 Filename: minor refactor (#35927)
* Filename

* rest of refactor
2025-08-05 16:29:25 -07:00
Shane Smiskol
c35494c19f Check for excessive lateral acceleration (#35921)
* here?

* nah card shouldn't become bloated

* better

* import

* actually selfdrived is probably best since it already manages alerts

card is car interfacing, controlsd is for calculating control input, selfdrived is rest

* consistent name

* add to params

* ai

* maybe better?

* shorter

* build out lockout

* do

* check active

* descriptive

* this is a terrible experience just to get lat accel

* just pass sm

* not iso

* type

* rm

* math

* use calibrated roll

* fix

* fix borkenness

* cmt

* compare some methods

* rolling window

* 1 and 2 are the same

* rm it

* stuff

* plot

* plot kf

* generic implementation

* adjust limits

* fix from merge

* clean up

* revert filter to master

* and here

* and

* run_process_on_route imps

* clean up

* why not

* extrapolate

* this doesn't generically work for angle/curvature cars

Revert "extrapolate"

This reverts commit 556f0c3a92b82f07ceb6422f0e39322e79a10dcd.

* cmt

* move

* rm debug

rm debug

and

* others use helpers

* two counters might be too much to return

* turn into class

* clean up

* cmt

* kinda obvious

* impossible for this not to be true, but make it explicit

* clean up
2025-08-05 16:15:07 -07:00
Adeeb Shihadeh
c321fa72e2 one more 2025-08-05 16:08:14 -07:00
Adeeb Shihadeh
2c654500d2 update release README 2025-08-05 16:07:29 -07:00
YassineYousfi
bb4f9651ba Update RELEASES.md 2025-08-05 14:57:57 -07:00
Adeeb Shihadeh
c23537b4d5 lil copy updates 2025-08-05 14:55:30 -07:00
Adeeb Shihadeh
865e6fa9d8 update release notes 2025-08-05 13:42:51 -07:00
Jimmy
d7b0a5fa7e Record feedback with LKAS button (#35888)
* record feedback with LKAS button

* fix alert test

* slightly simplify feedbackd

* "Audio Feedback Saved" upon time expiration or early stop

* earlySend --> earlyStop

* userFlag --> userBookmark

* RecordAudioFeedback param/toggle

* add audioFeedback test

* simplify feedbackd

* send bookmark regardless of toggle, show feedback event with higher priority

* add userBookmark to selfdrived sm

* fix mispelled param name

* default off and move to main

* segmentNum --> blockNum, earlyStop --> lastBlock

* preserve audioFeedback

* get rid of lastBlock and just send bookmark saved at the end

* update raylib side

* update toggle description and add raylib toggle

---------

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-08-05 13:41:41 -07:00
Maxime Desroches
112d615ac9 ci: fix setup device variable 2025-08-04 21:28:43 -07:00
Maxime Desroches
fb34e7ccd3 ci: kick power watchdog on ci devices 2025-08-04 21:06:28 -07:00
Maxime Desroches
f08d95b95a AGNOS 12.6 (#35922)
* bump

* production
2025-08-04 20:40:20 -07:00
Shane Smiskol
1c9bbb290a run_process_on_route.py: qol improvements (#35923)
* take from upstrema/exc-lat-accel

* see ya

* sort

* rm

* duh

duh
2025-08-04 17:11:53 -07:00
Shane Smiskol
2c8415f81c ui.py: gas is deprecated 2025-08-04 16:21:20 -07:00
mvl-boston
bae7a610fa Honda: allow sport gear (#35911)
add honda sport gear
2025-08-04 16:19:26 -07:00
Adeeb Shihadeh
aecb6d13e7 cabana: add independent panda lib (#35920)
* cabana: add separate panda lib

* cleanup
2025-08-04 16:09:22 -07:00
Maxime Desroches
1ca8a4ca75 raylib: bump commit 2025-08-04 15:43:50 -07:00
Maxime Desroches
c316c400f8 reset: proper button scale (#35919)
* reset scale

* r
2025-08-04 15:41:29 -07:00
Adeeb Shihadeh
408cef2d46 Delete Jenkins trigger comments (#35916) 2025-08-04 13:29:22 -07:00
pencilpusher
be0626f7e3 improved safe_ioctl (#35908)
* improved safe_ioctl

* readability

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>

* use correct ioctl command

* ameliorated api

* use try/catch to prevent spi_fd leak

* Update common/util.h

* use correct ioctl command

* error log message is more readable

---------

Co-authored-by: Test User <test@example.com>
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-08-04 13:25:24 -07:00
commaci-public
f06c98018f [bot] Update Python packages (#35915)
Update Python packages

Co-authored-by: Vehicle Researcher <user@comma.ai>
2025-08-04 09:44:14 -07:00
Maxime Desroches
976dfa3982 ui: multi touch keyboard support (#35912)
* start

* better

* 2

* dumb
2025-08-03 18:14:48 -07:00
Willem Melching
623de0e22a cabana: PandaStream use noOutput safety mode instead silent (#35910) 2025-08-03 09:22:52 -07:00
Maxime Desroches
86146981c4 ui: fix connection check 2025-08-03 01:32:51 -07:00
Maxime Desroches
56dcf71774 ui: fix non-ascii access points 2025-08-03 01:21:40 -07:00
Maxime Desroches
a1f073921c test_messaging: less flaky wait time check 2025-08-03 00:31:01 -07:00
Maxime Desroches
cccd60a28b ui: make wifi selection usable (#35895)
* start

* wrong

* more

* more

* better

* better

* more better
2025-08-03 00:14:36 -07:00
Jason Wen
24059b22f3 Merge remote-tracking branch 'sunnypilot/sunnypilot/master' into feature/slc
# Conflicts:
#	common/params_keys.h
#	opendbc_repo
#	sunnypilot/selfdrive/controls/lib/longitudinal_planner.py
#	system/manager/manager.py
2025-08-02 23:47:22 -04:00
Maxime Desroches
181ea39a83 ui: re-compute text size (#35907)
* one

* app

* fix
2025-08-02 20:38:37 -07:00
Maxime Desroches
8cce8cf3f3 ui: keyboard improvements (#35906)
* better

* miss this one
2025-08-02 19:01:59 -07:00
Simon Kuang
0b855a93d7 scons: support build on single processor (#35904)
Update SConstruct
2025-08-02 16:50:45 -07:00
Jason Young
8c78749846 sim: fix "msg not found" errors (#35903)
* garbage-collect CRUISE_PARAMS

* follow GEARBOX message refactor
2025-08-02 19:10:49 -04:00
Adeeb Shihadeh
aa2a3b3c8f hw: remove unused volume properties 2025-08-02 16:08:58 -07:00
Adeeb Shihadeh
ba2dced54c Revert "LogReader: wrap events to cache which() (#35882)"
This reverts commit 0ebee55050.
2025-08-02 15:53:20 -07:00
Shane Smiskol
2e15ac5f4f test manager in CI (#35900)
* test manager

* not now

* try

* fix
2025-08-02 13:18:30 -07:00
Shane Smiskol
c92add1280 process replay: don't wait for process to start (#35897)
* hmm

* test proc replay determinism

* clean up

* rm

* clean up
2025-08-02 12:34:13 -07:00
Adeeb Shihadeh
bab251b287 fix conversions import path (#35899) 2025-08-02 12:02:17 -07:00
DevTekVE
9dc98b36be refactor: cleanup gravity constant handling (#35866)
* refactor: move lateral methods from init to lateral.py (#2594)

* Extracting lateral methods to lateral.py

* cleaning

* more cleaning

* more cleaning

* Making sure it remains where it should

* Leave rate_limit where it belongs

* Moving things to `car/controls/`

* Moving rate limit to get a taste of the changes

* clean

* copy verbatim

* clean up

* more

* now we can format

---------

Co-authored-by: Shane Smiskol <shane@smiskol.com>

* No need to change order of import

* refactor: consolidate ACCELERATION_DUE_TO_GRAVITY import path

* bump opendbc

* update refs

* don't import from opendbc

---------

Co-authored-by: Shane Smiskol <shane@smiskol.com>
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-08-02 11:20:18 -07:00
Shane Smiskol
313f36712c process replay: lock polled socket only (#35887)
* stash

* Revert "stash"

This reverts commit 333818b80f498e8e3dac3c1cd36e669e97521d52.

* works for paramsd

* INSANE

* format

* fater

* clean up

* more

* huh i thought order matterred?

* clean that up

* can remove this

* cmt

* check isisntance

* rename

* clean up

* clean up

* more

* more!

* sounds better
2025-08-02 00:45:29 -07:00
Maxime Desroches
3ff874d6c2 ui: fix keyboard lint 2025-08-02 00:24:52 -07:00
Maxime Desroches
eb751a3804 setup: convert to raylib touch api (#35862)
* first

* lint

* c

* simple first

* btn

* n

* more

* more

* bring back
2025-08-02 00:22:28 -07:00
Shane Smiskol
5a8e3470ff selfdrived: feed PoseCalibrator with updates (#35893)
this is also slow
2025-08-02 00:09:54 -07:00
Shane Smiskol
07909906d4 controlsd: speed up number checking (#35890)
Update controlsd.py
2025-08-02 00:08:18 -07:00
Shane Smiskol
7c87ada8d8 Simplify radarFault handling (#35891)
* Revert "Fix up `radarFault` handling (#35880)"

This reverts commit 4d01b7bec8.

* Reapply "Fix up `radarFault` handling (#35880)"

This reverts commit 597d7ec1ed78206035b924a6e8464cd9239b5db4.

* can do this

* yeah this is fine
2025-08-01 23:55:16 -07:00
Shane Smiskol
bdd6ff4f3e process replay: remove frequency based recv callback (#35886)
* wtf is going on?

* rm it

* default
2025-08-01 21:46:32 -07:00
Shane Smiskol
f2e100b0e1 process replay: clean up recv callbacks (#35889)
clean up callbacks
2025-08-01 21:36:15 -07:00
Shane Smiskol
8b0bfd7910 match on /test/ 2025-08-01 20:52:36 -07:00
Shane Smiskol
db55f1275d process replay: set selfdrived main_pub (#35885)
* save 1-2s for full route

* now more than halve the time on top of previous speedup!

* stash

* default should be most common!

* revert

* revert

* clean up

* clean up

* clean up

* clean up
2025-08-01 20:49:45 -07:00
Shane Smiskol
8f9ee43d34 process replay: flip main_pub_drained default 2025-08-01 20:44:33 -07:00
Shane Smiskol
37c4ee1532 process replay: only enter prefix when interacting with process (#35884)
* save 1-2s for full route

* cu

* stock

* Revert "stock"

This reverts commit 7cfb550817b124c3085cf005fda8c102ae53ae9d.

* clean up
2025-08-01 20:13:02 -07:00
Shane Smiskol
0ebee55050 LogReader: wrap events to cache which() (#35882)
* speed up lr

* lazy caching

* clean up

* it fast

* stash

* stash

* chatgpt code is bad as usual

* clean up

* clean up

* clean up

* clean up

* clean up

* clean up

* match behavior

* cmt
2025-08-01 19:07:16 -07:00
Maxime Desroches
cb5299be5a ui: adapt network to raylib touch api (#35881)
* start

* for now

* con

* more
2025-08-01 18:40:43 -07:00
Shane Smiskol
5c73681be8 process replay: rm dummy sockets (#35883)
* rm dummy sockets

* debug

* clean up

* cu
2025-08-01 18:38:42 -07:00
Shane Smiskol
dd09c4f341 process replay: speed up startup (#35879)
* format

* containers might not be set

* opts

* halves startup time for 12 procs (1.6 to 0.8s)

* stash

* clean up

* who knew going through entire list of msgs each time is so slow

* rewrite this to be more readable

* speed up lr

* clean up

* more

* more
2025-08-01 17:51:39 -07:00
Adeeb Shihadeh
4d01b7bec8 Fix up radarFault handling (#35880)
* fixup radarFault handling

* catch all

---------

Co-authored-by: Comma Device <device@comma.ai>
2025-08-01 16:27:26 -07:00
Maxime Desroches
42ebab1334 ui: add missing keyboard function 2025-08-01 16:02:25 -07:00
Shane Smiskol
9117a414bb process replay clean up (#35878)
* format

* containers might not be set

* opts

* halves startup time for 12 procs (1.6 to 0.8s)

* stash

* Revert "stash"

This reverts commit 3e119a9602e495bd5a57b94e73fa53d4f45051b1.

* Revert "halves startup time for 12 procs (1.6 to 0.8s)"

This reverts commit a39edf0a579f0c861ccb904a2718254fe32e03d0.

* Revert "opts"

This reverts commit 4dc1f75f0909a93650f8f7e8525af3e4eae08205.

* already set!
2025-08-01 15:20:50 -07:00
DevTekVE
1966845fc9 refactor: move lateral methods from init to lateral.py (#35856)
* refactor: move lateral methods from init to lateral.py (#2594)

* Extracting lateral methods to lateral.py

* cleaning

* more cleaning

* more cleaning

* Making sure it remains where it should

* Leave rate_limit where it belongs

* Moving things to `car/controls/`

* Moving rate limit to get a taste of the changes

* clean

* copy verbatim

* clean up

* more

* now we can format

---------

Co-authored-by: Shane Smiskol <shane@smiskol.com>

* No need to change order of import

---------

Co-authored-by: Shane Smiskol <shane@smiskol.com>
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
2025-08-01 15:17:37 -07:00
Maxime Desroches
889e386dbc ui: adapt keyboard to raylib touch api (#35875)
* key

* cancel

* more

* wow mypy very usefull as always

* _

* b

* std
2025-08-01 14:07:12 -07:00
Maxime Desroches
4e97a29e83 ui: add icon to Button (#35874)
ico
2025-08-01 12:03:22 -07:00
Adeeb Shihadeh
b695715753 sensord: reset LSM (#35872)
* sensord: reset LSM

* they'll be ready in time

* switch to SW_RESET, BOOT not working for some reason
2025-08-01 10:13:39 -07:00
Jason Wen
f5991caf6f params: update AthenadPid to use integer type (#35871)
* params: update `AthenadPid` to use integer type

* fix type
2025-08-01 09:29:25 -07:00
Shane Smiskol
2e4de9b7d8 process replay: speed up multi-process replay (#35867)
* holy shit

* benchmark without this main pub drain stuff

* revert

* ??

* actually this is what we want

* what is going on this is python 3.11 sir

* stash

* this is how you dew it

* minor clean up

* fix

* clean up

* clean up

* this is madness!

* typing

* clean up
2025-08-01 03:32:03 -07:00
Shane Smiskol
f2c17dd688 process replay: ordered dict is in Python 2025-08-01 03:26:45 -07:00
Shane Smiskol
c4298ce287 process replay: create openpilot prefix directories once (#35864)
this is so slow
2025-07-31 23:42:02 -07:00
Maxime Desroches
1de1640689 ui: improve Button widget (#35861)
* bnt

* more

* dup
2025-07-31 22:28:58 -07:00
Adeeb Shihadeh
fc58c866c6 AGNOS power monitoring watchdog (#35860)
* AGNOS power monitoring watchdog

* manager should do this
2025-07-31 19:43:21 -07:00
nayan
7b8b0ab949 Merge remote-tracking branch 'origin/feature/slc' into ui/slc-ui
# Conflicts:
#	opendbc_repo
2025-07-04 14:16:02 -04:00
nayan
b5b86fe75e Merge remote-tracking branch 'origin/master-new' into feature/slc
# Conflicts:
#	opendbc_repo
2025-07-04 14:06:35 -04:00
nayan
8d65bf1232 Merge remote-tracking branch 'origin/master-new' into ui/slc-ui
# Conflicts:
#	opendbc_repo
#	selfdrive/ui/sunnypilot/SConscript
#	selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.cc
#	selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal_panel.h
2025-07-03 18:09:03 -04:00
rav4kumar
a39c7cf11d Merge remote-tracking branch 'origin/feature/slc' into ui/slc-ui 2025-06-08 19:11:46 -07:00
Jason Wen
3f7e1e2d16 use CC.longActive 2025-06-07 20:19:20 -04:00
Jason Wen
3864dc5c88 Merge branch 'feature/slc' into ui/slc-ui
# Conflicts:
#	opendbc_repo
2025-06-07 17:39:47 -04:00
Jason Wen
01f32f2c3d Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc
# Conflicts:
#	opendbc_repo
2025-06-07 17:39:28 -04:00
Jason Wen
95905de1ff Merge branch 'feature/slc' into ui/slc-ui 2025-06-07 17:13:53 -04:00
Jason Wen
374150618c Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc 2025-06-07 17:10:49 -04:00
Jason Wen
ccd8d5a592 fix tests 2025-06-07 17:10:01 -04:00
Jason Wen
7294709139 lint 2025-06-07 12:08:59 -04:00
Jason Wen
f683f897bb Merge branch 'feature/slc' into ui/slc-ui 2025-06-07 12:07:54 -04:00
Jason Wen
75cffc4100 quote...? 2025-06-07 12:05:13 -04:00
Jason Wen
01f4d23a50 use gps data directly 2025-06-07 11:45:11 -04:00
Jason Wen
a998bf781e refactor 2025-06-07 11:39:26 -04:00
Jason Wen
71f85ec9d3 Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc 2025-06-07 05:47:48 -04:00
Jason Wen
02ba1af1b5 fix test 2025-06-07 05:46:56 -04:00
Jason Wen
3bfbc5e629 Merge branch 'feature/slc' into ui/slc-ui 2025-06-07 05:17:29 -04:00
Jason Wen
2615735b87 use it directly 2025-06-07 05:17:14 -04:00
Jason Wen
d0b37d645f Merge branch 'feature/slc' into ui/slc-ui 2025-06-07 04:40:13 -04:00
Jason Wen
678216de2c no need to check alive 2025-06-07 04:39:55 -04:00
Jason Wen
dfb8b0963b extra 2025-06-07 04:18:31 -04:00
Jason Wen
d58a875090 upstream opendbc again 2025-06-07 03:52:34 -04:00
Jason Wen
5d39bd211f Merge branch 'feature/slc' into ui/slc-ui 2025-06-07 03:50:55 -04:00
Jason Wen
55931e080a Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc
# Conflicts:
#	cereal/custom.capnp
#	common/params_keys.h
#	sunnypilot/mapd/live_map_data/__init__.py
#	sunnypilot/mapd/live_map_data/base_map_data.py
#	sunnypilot/mapd/live_map_data/debug.py
#	sunnypilot/mapd/live_map_data/osm_map_data.py
#	sunnypilot/mapd/live_map_data/standalone.py
#	sunnypilot/mapd/mapd_installer.py
#	sunnypilot/mapd/mapd_manager.py
2025-06-07 03:50:28 -04:00
Jason Wen
de2770ee91 rebump 2025-06-07 03:34:08 -04:00
Jason Wen
168337ab73 Revert "in another pr"
This reverts commit a29bccff12.
2025-06-07 03:33:58 -04:00
Jason Wen
0242fd8ce6 Revert "slc in another pr"
This reverts commit 3a6987e6
2025-06-07 03:33:55 -04:00
Jason Wen
8b594eef91 Merge branch 'feature/slc' into ui/slc-ui 2025-06-06 22:54:16 -04:00
Jason Wen
13e987f2ad Merge branch 'mapd' into feature/slc 2025-06-06 22:53:38 -04:00
Jason Wen
0c3773f5d2 even more type hint 2025-06-06 22:53:00 -04:00
Jason Wen
f2faa1262c type hints 2025-06-06 22:50:58 -04:00
Jason Wen
70ef1c0fd5 slight more cleanup 2025-06-06 22:43:42 -04:00
Jason Wen
6a8f31636a combine pm 2025-06-06 22:29:36 -04:00
Jason Wen
6546100afc use directly 2025-06-06 22:27:58 -04:00
Jason Wen
a05f7255c1 from old implementation 2025-06-06 22:24:01 -04:00
Jason Wen
f3eff3fdbd type hint and slight cleanup 2025-06-06 22:22:32 -04:00
Jason Wen
8dc32ac90f unused 2025-06-06 22:04:11 -04:00
Jason Wen
02da318901 sort 2025-06-06 21:56:54 -04:00
Jason Wen
235ffe374b unused 2025-06-06 21:51:38 -04:00
Jason Wen
601e0e082e set core affinity for all realtime processes 2025-06-06 21:51:19 -04:00
Jason Wen
748a0b6481 use horizontal accuracy 2025-06-06 21:35:52 -04:00
Jason Wen
0539cc7348 use horizontal accuracy 2025-06-06 21:31:44 -04:00
Jason Wen
3a6987e6ba slc in another pr 2025-06-06 18:54:05 -04:00
Jason Wen
89d332105f qlog 2025-06-06 18:49:57 -04:00
Jason Wen
4bbde8071d no longer need data type 2025-06-06 18:49:28 -04:00
Jason Wen
a29bccff12 in another pr 2025-06-06 18:49:18 -04:00
Jason Wen
ce0cdcaa17 back to upstream 2025-06-06 18:47:00 -04:00
Jason Wen
dc2402cf30 Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc
# Conflicts:
#	common/params_keys.h
#	opendbc_repo
2025-06-06 18:46:00 -04:00
Jason Wen
3ca50ef990 Merge branch 'feature/slc' into ui/slc-ui 2025-06-05 23:39:26 -04:00
Jason Wen
064f7a84df Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc
# Conflicts:
#	opendbc_repo
2025-06-05 23:39:10 -04:00
nayan8teen
a0a8280ac8 Merge remote-tracking branch 'origin/ui/slc-ui' into ui/slc-ui 2025-06-05 19:01:22 -04:00
nayan8teen
8df7f2c743 update margins 2025-06-05 19:01:03 -04:00
Jason Wen
bf277d68f0 Merge branch 'feature/slc' into ui/slc-ui 2025-06-05 02:45:17 -04:00
Jason Wen
7ca82593f0 type hint all 2025-06-05 02:44:55 -04:00
Jason Wen
dc2e5ef460 type hint all 2025-06-05 02:43:56 -04:00
Jason Wen
0306ba701b don't reset if gas pressed 2025-06-05 02:25:55 -04:00
Jason Wen
5d705d3f6d no need for brake pressed 2025-06-05 02:25:05 -04:00
Jason Wen
845a57a21a rename 2025-06-05 02:24:43 -04:00
Jason Wen
cb3f57110b more mypy stuff 2025-06-05 02:22:45 -04:00
Jason Wen
40c456b56b simpler op enabled check 2025-06-05 02:19:26 -04:00
Jason Wen
810ffc266c cleaner 2025-06-05 02:13:53 -04:00
Jason Wen
5b68983497 Merge branch 'feature/slc' into ui/slc-ui 2025-06-05 02:03:03 -04:00
Jason Wen
36e910d500 rename 2025-06-05 02:00:34 -04:00
Jason Wen
4b5cd3eef2 define types in init 2025-06-05 01:59:53 -04:00
Jason Wen
74a2a01a0f single method 2025-06-05 01:57:25 -04:00
Jason Wen
bbe6c684d8 more 2025-06-05 01:50:15 -04:00
Jason Wen
1929a37b1f handle all params with exceptions 2025-06-05 01:49:28 -04:00
Jason Wen
06eaa56a9d policy param catch exceptions 2025-06-05 01:25:18 -04:00
Jason Wen
b0e0b46c8e Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc 2025-06-05 01:22:20 -04:00
Jason Wen
75b2eca5df mypy my bt 2025-06-04 23:25:15 -04:00
nayan8teen
4d9b0c77b4 hide slc_offset on none 2025-06-04 23:20:57 -04:00
nayan8teen
9b3eb4127c Merge remote-tracking branch 'origin/ui/slc-ui' into ui/slc-ui
# Conflicts:
#	selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/slc/speed_limit_control_subpanel.cc
2025-06-04 23:13:58 -04:00
nayan8teen
cf95828e1c adjust margins & slc_offset size 2025-06-04 23:12:12 -04:00
Jason Wen
ea9df3fe10 bigger btns 2025-06-04 23:11:33 -04:00
Jason Wen
01d84dc1ab bigger btns 2025-06-04 23:03:00 -04:00
Jason Wen
c9d0accf16 unused 2025-06-04 22:56:39 -04:00
Jason Wen
094d5a6fcf more formatting 2025-06-04 22:56:15 -04:00
Jason Wen
b0e979f09e use std::atoi 2025-06-04 22:49:17 -04:00
Jason Wen
736815f736 Merge branch 'feature/slc' into ui/slc-ui 2025-06-04 22:40:41 -04:00
Jason Wen
2bed6bfe06 create directory if does not exist 2025-06-04 22:38:20 -04:00
Jason Wen
858d437f57 more 2025-06-04 22:34:26 -04:00
Jason Wen
73b8892125 formatting 2025-06-04 22:31:17 -04:00
Jason Wen
7d9e70d396 Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc
# Conflicts:
#	opendbc_repo
#	selfdrive/ui/sunnypilot/qt/offroad/settings/settings.cc
2025-06-04 22:21:19 -04:00
nayan8teen
2cd0e918d3 move src from settings/slc to settings/longitudinal/slc 2025-06-04 20:49:02 -04:00
nayan8teen
ee84438c41 minor layout updates
remove unnecessary imports
call showDescription on showEvent instead of refresh
2025-06-04 20:41:01 -04:00
nayan8teen
c88fe5294d update margins 2025-06-02 21:38:07 -04:00
nayan8teen
c06d7effea Merge remote-tracking branch 'origin/feature/slc' into ui/slc-ui 2025-06-02 21:17:20 -04:00
Jason Wen
5b98cdf750 none for now 2025-06-02 00:19:58 -04:00
Jason Wen
42423e35de Merge branch 'feature/slc' into ui/slc-ui 2025-06-02 00:18:38 -04:00
Jason Wen
be11d07a01 type hints 2025-06-02 00:01:19 -04:00
Jason Wen
fe521a39be fix source 2025-06-01 23:58:17 -04:00
Jason Wen
0aa6953066 fix 2025-06-01 23:52:24 -04:00
Jason Wen
4531cd7ac6 use old controller for now 2025-06-01 23:36:55 -04:00
Jason Wen
ab3a7e82e8 fix 2025-06-01 22:49:17 -04:00
Jason Wen
eaa96655ca Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc
# Conflicts:
#	cereal/custom.capnp
#	cereal/log.capnp
#	cereal/services.py
#	opendbc_repo
2025-06-01 22:48:51 -04:00
nayan8teen
48947609be remove extra include 2025-06-01 22:35:18 -04:00
nayan8teen
a0463f2c1a subpanel within subpanel 2025-06-01 22:28:41 -04:00
nayan8teen
b5084ab97d slc ui 2025-06-01 15:58:50 -04:00
Jason Wen
e350b1bebc bring back car state speed limit 2025-06-01 14:31:52 -04:00
Jason Wen
5ecbed3125 Merge branch 'cs-sp' into feature/slc
# Conflicts:
#	cereal/custom.capnp
#	cereal/log.capnp
#	cereal/services.py
2025-06-01 14:31:34 -04:00
Jason Wen
17e6781a71 fix tests 2025-06-01 10:52:28 -04:00
Jason Wen
72cbcd0601 Car: CarStateSP 2025-06-01 10:32:46 -04:00
Jason Wen
b6f3e5229f Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc 2025-05-31 23:38:20 -04:00
Jason Wen
6f7a3e7834 missed event 2025-05-31 23:37:49 -04:00
Jason Wen
3885ee068d no car state speed yet 2025-05-31 23:36:20 -04:00
Jason Wen
3d254f8ed6 need to sub 2025-05-31 23:32:39 -04:00
Jason Wen
471b24f7be no nav for now 2025-05-31 23:28:22 -04:00
Jason Wen
d9a1f6a553 publish events 2025-05-31 02:02:52 -04:00
Jason Wen
8cc9eb1562 service missing 2025-05-31 01:44:07 -04:00
Jason Wen
4a94abe2ea let's use gps chips directly for now 2025-05-31 01:34:09 -04:00
Jason Wen
ca100995b2 fix path 2025-05-30 23:38:21 -04:00
Jason Wen
f5e9a439db fix spinner import 2025-05-30 23:36:43 -04:00
Jason Wen
4c133c601d print them out 2025-05-30 23:21:43 -04:00
Jason Wen
69c68f7dc0 Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc
# Conflicts:
#	selfdrive/ui/sunnypilot/SConscript
2025-05-30 23:14:40 -04:00
Jason Wen
ac67871a47 ui? ui! 2025-05-30 23:09:28 -04:00
Jason Wen
f7eb39abf4 enable debug print 2025-05-30 23:00:34 -04:00
Jason Wen
ca340510bf init these 2025-05-30 22:59:52 -04:00
Jason Wen
c7d1e9f9cc some type hints 2025-05-30 22:56:27 -04:00
Jason Wen
52da6e398c start refactor controller 2025-05-30 22:51:12 -04:00
Jason Wen
26fc671251 wrong state 2025-05-30 20:18:50 -04:00
Jason Wen
b082daeb79 refactor state machine 2025-05-29 22:32:09 -04:00
Jason Wen
a389fa81c2 fixme-sp 2025-05-29 21:20:47 -04:00
Jason Wen
2d47bdf297 implement in long plan 2025-05-29 21:17:41 -04:00
Jason Wen
5e19d7d1a3 Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc 2025-05-29 19:29:44 -04:00
Jason Wen
440678f64f Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc
# Conflicts:
#	cereal/custom.capnp
#	sunnypilot/selfdrive/selfdrived/events.py
2025-05-21 00:40:54 -04:00
Jason Wen
b661fee9b1 Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc 2025-04-30 23:10:52 -04:00
Jason Wen
09be18cd9b Merge remote-tracking branch 'sunnypilot/sunnypilot/master-new' into feature/slc 2025-04-28 22:25:57 -04:00
Jason Wen
b136d05ea2 lint 2025-04-27 22:30:40 -04:00
Jason Wen
2ff6060fe3 sp events 2025-04-27 22:10:55 -04:00
Jason Wen
4001bb1e46 add to cereal first 2025-04-27 21:37:54 -04:00
Jason Wen
49ed7795b9 more 2025-04-27 21:31:26 -04:00
Jason Wen
27fcc2f42a fix linting 2025-04-27 21:02:45 -04:00
Jason Wen
398ded76d6 bring back cereal 2025-04-27 20:25:37 -04:00
Jason Wen
e0b73d32ad old navd helpers 2025-04-27 20:12:49 -04:00
Jason Wen
b9d0b71bc1 more 2025-04-27 20:09:44 -04:00
Jason Wen
938796d467 move 2025-04-27 20:07:18 -04:00
Jason Wen
c50b187da9 some fixes 2025-04-27 19:59:35 -04:00
Jason Wen
2dd1258670 init 2025-04-27 11:52:15 -04:00
390 changed files with 28113 additions and 12122 deletions

View File

@@ -1,6 +1,6 @@
ci:
- changed-files:
- any-glob-to-all-files: "{.github/**,**/test_*,Jenkinsfile}"
- any-glob-to-all-files: "{.github/**,**/test_*,**/test/**,Jenkinsfile}"
chore:
- changed-files:

View File

@@ -40,10 +40,10 @@ jobs:
runs-on: ubuntu-latest
if: (github.event.pull_request.head.repo.fork && (contains(github.event_name, 'pull_request') && github.event.action == 'synchronize'))
env:
PR_LABEL: 'dev-c3'
PR_LABEL: 'dev'
TRUST_FORK_PR_LABEL: 'trust-fork-pr'
steps:
- name: Check if PR has dev-c3 label
- name: Check if PR has dev label
id: check-labels
uses: actions/github-script@v7
with:
@@ -62,11 +62,11 @@ jobs:
console.log(`PR #${prNumber} has ${process.env.PR_LABEL} label: ${hasDevC3Label}`);
console.log(`PR #${prNumber} has ${process.env.TRUST_FORK_PR_LABEL} label: ${hasTrustLabel}`);
core.setOutput('has-dev-c3', hasDevC3Label ? 'true' : 'false');
core.setOutput('has-dev', hasDevC3Label ? 'true' : 'false');
core.setOutput('has-trust', hasTrustLabel ? 'true' : 'false');
- name: Remove trust-fork-pr label if present
if: steps.check-labels.outputs.has-dev-c3 == 'true' && steps.check-labels.outputs.has-trust == 'true'
if: steps.check-labels.outputs.has-dev == 'true' && steps.check-labels.outputs.has-trust == 'true'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -16,7 +16,24 @@ jobs:
recompiled_dir: ${{ steps.create-recompiled-dir.outputs.recompiled_dir }}
json_file: ${{ steps.get-json.outputs.json_file }}
model_matrix: ${{ steps.set-matrix.outputs.model_matrix }}
tinygrad_ref: ${{ steps.get-tinygrad-ref.outputs.tinygrad_ref }}
steps:
- name: Checkout sunnypilot repo
uses: actions/checkout@v4
with:
repository: sunnypilot/sunnypilot
path: sunnypilot
submodules: recursive
- name: Get tinygrad_repo ref
id: get-tinygrad-ref
run: |
cd sunnypilot
export PYTHONPATH=$(pwd)
ref=$(python3 sunnypilot/models/tinygrad_ref.py)
echo "tinygrad_ref=$ref" >> $GITHUB_OUTPUT
echo "tinygrad_ref is $ref"
- name: Checkout docs repo (sunnypilot-docs, gh-pages)
uses: actions/checkout@v4
with:
@@ -110,7 +127,7 @@ jobs:
retry_failed_models:
needs: [setup, get_and_build]
runs-on: ubuntu-latest
if: ${{ needs.setup.result != 'failure' && (failure() && !cancelled()) }}
if: ${{ needs.setup.result != 'failure' && !cancelled() }}
outputs:
retry_matrix: ${{ steps.set-retry-matrix.outputs.retry_matrix }}
steps:
@@ -269,6 +286,7 @@ jobs:
ARGS=""
[ -n "${{ inputs.set_min_version }}" ] && ARGS="$ARGS --set-min-version \"${{ inputs.set_min_version }}\""
ARGS="$ARGS --sort-by-date"
ARGS="$ARGS --tinygrad-ref \"${{ needs.setup.outputs.tinygrad_ref }}\""
eval python3 docs/json_parser.py \
--json-path "$JSON_FILE" \
--recompiled-dir "gitlab_docs/models/$RECOMPILED_DIR" \

View File

@@ -42,11 +42,11 @@ on:
recompiled_dir:
description: 'Existing recompiled directory number (e.g. 3 for recompiled3)'
required: true
type: number
type: string
json_version:
description: 'driving_models version number to update (e.g. 5 for driving_models_v5.json)'
required: true
type: number
type: string
model_folder:
description: 'Model folder'
type: choice
@@ -67,11 +67,11 @@ on:
generation:
description: 'Model generation'
required: false
type: number
type: string
version:
description: 'Minimum selector version'
required: false
type: number
type: string
env:
RECOMPILED_DIR: recompiled${{ inputs.recompiled_dir }}
JSON_FILE: docs/docs/driving_models_v${{ inputs.json_version }}.json

View File

@@ -21,8 +21,8 @@ concurrency:
env:
PYTHONWARNINGS: error
BASE_IMAGE: sunnypilot-base
BUILD: release/ci/docker_build_sp.sh base
BASE_IMAGE: openpilot-base
BUILD: selfdrive/test/docker_build.sh base
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
jobs:
@@ -59,7 +59,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
repository: 'sunnypilot/sunnypilot'
repository: 'commaai/openpilot'
submodules: true
ref: "refs/heads/master"
- uses: ./.github/workflows/setup-with-retry

View File

@@ -9,6 +9,9 @@ jobs:
scan-comments:
runs-on: ubuntu-latest
if: ${{ github.event.issue.pull_request }}
permissions:
contents: write
issues: write
steps:
- name: Check for trigger phrase
id: check_comment
@@ -43,3 +46,14 @@ jobs:
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b tmp-jenkins-${{ github.event.issue.number }}
GIT_LFS_SKIP_PUSH=1 git push -f origin tmp-jenkins-${{ github.event.issue.number }}
- name: Delete trigger comment
if: steps.check_comment.outputs.result == 'true' && always()
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
});

View File

@@ -39,4 +39,4 @@ jobs:
git config --global --add safe.directory '*'
git lfs pull
- name: Push __nightly
run: BRANCH=__nightly release/build_devel.sh
run: BRANCH=__nightly release/build_stripped.sh

View File

@@ -43,6 +43,7 @@ jobs:
with:
submodules: true
- name: uv lock
if: github.repository == 'commaai/openpilot'
run: |
python3 -m ensurepip --upgrade
pip3 install uv
@@ -50,6 +51,7 @@ jobs:
- name: bump submodules
run: |
git config --global --add safe.directory '*'
git config submodule.tinygrad.update none
git submodule update --remote
git add .
- name: update car docs

View File

@@ -27,7 +27,7 @@ env:
RUN: docker run --shm-size 2G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/bash -c
PYTEST: pytest --continue-on-collection-errors --durations=0 --durations-min=5 -n logical
PYTEST: pytest --continue-on-collection-errors --durations=0 -n logical
jobs:
build_release:
@@ -52,7 +52,7 @@ jobs:
command: git lfs pull
- name: Build devel
timeout-minutes: 1
run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh
run: TARGET_DIR=$STRIPPED_DIR release/build_stripped.sh
- uses: ./.github/workflows/setup-with-retry
- name: Build openpilot and run checks
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
@@ -107,7 +107,6 @@ jobs:
build_mac:
name: build macOS
if: false # temp disable since homebrew install is getting stuck
runs-on: ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-macos-8x14' || 'macos-latest' }}
steps:
- uses: actions/checkout@v4
@@ -125,8 +124,8 @@ jobs:
- name: Install dependencies
run: ./tools/mac_setup.sh
env:
# package install has DeprecationWarnings
PYTHONWARNINGS: default
PYTHONWARNINGS: default # package install has DeprecationWarnings
HOMEBREW_DISPLAY_INSTALL_TIMES: 1
- name: Save Homebrew cache
uses: actions/cache/save@v4
if: github.ref == 'refs/heads/master'
@@ -189,7 +188,9 @@ jobs:
- name: Run unit tests
timeout-minutes: ${{ contains(runner.name, 'nsc') && ((steps.setup-step.outputs.duration < 18) && 1 || 2) || 999 }}
run: |
${{ env.RUN }} "$PYTEST --collect-only -m 'not slow' &> /dev/null && \
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
# Pre-compile Python bytecode so each pytest worker doesn't need to
$PYTEST --collect-only -m 'not slow' -qq && \
MAX_EXAMPLES=1 $PYTEST -m 'not slow' && \
./selfdrive/ui/tests/create_test_translations.sh && \
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \

View File

@@ -8,21 +8,15 @@ env:
PUBLIC_REPO_URL: "https://github.com/sunnypilot/sunnypilot"
# Branch configurations
STAGING_C3_SOURCE_BRANCH: ${{ vars.STAGING_C3_SOURCE_BRANCH || 'master' }} # vars are set on repo settings.
DEV_C3_SOURCE_BRANCH: ${{ vars.DEV_C3_SOURCE_BRANCH || 'master-dev-c3-new' }} # vars are set on repo settings.
# Target branch configurations
STAGING_TARGET_BRANCH: ${{ vars.STAGING_TARGET_BRANCH || 'staging-c3-new' }} # vars are set on repo settings.
DEV_TARGET_BRANCH: ${{ vars.DEV_TARGET_BRANCH || 'dev-c3-new' }} # vars are set on repo settings.
RELEASE_TARGET_BRANCH: ${{ vars.RELEASE_TARGET_BRANCH || 'release-c3-new' }} # vars are set on repo settings.
STAGING_SOURCE_BRANCH: 'master'
# Runtime configuration
SOURCE_BRANCH: "${{ github.head_ref || github.ref_name }}"
on:
push:
branches: [ master, master-dev-c3-new ]
tags: [ '*' ]
branches: [ master, master-dev ]
tags: [ 'release/*' ]
pull_request_target:
types: [ labeled ]
workflow_dispatch:
@@ -34,9 +28,72 @@ on:
default: false
jobs:
prepare_strategy:
runs-on: ubuntu-24.04
if: (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
outputs:
environment: ${{ steps.strategy.outputs.environment }}
new_branch: ${{ steps.strategy.outputs.new_branch }}
extra_version_identifier: ${{ steps.strategy.outputs.extra_version_identifier }}
version: ${{ steps.strategy.outputs.version }}
cancel_publish_in_progress: ${{ steps.strategy.outputs.cancel_publish_in_progress }}
publish_concurrency_group: ${{ steps.strategy.outputs.publish_concurrency_group }}
is_stable_branch: ${{ steps.strategy.outputs.is_stable_branch }}
build: ${{ steps.strategy.outputs.build }}
steps:
- uses: actions/checkout@v4
- name: Extract deploy strategy
id: strategy
run: |
echo '::group::Strategy Extraction'
BRANCH="${{ github.head_ref || github.ref_name }}"
echo "Current branch: $BRANCH"
STRATEGY_JSON='${{ vars.DEPLOY_STRATEGY }}'
CONFIG=$(echo "$STRATEGY_JSON" | jq -r --arg branch "$BRANCH" '
.configs[] | select(.branch == $branch)
')
BUILD="$(date '+%Y.%m.%d')-${{ github.run_number }}"
if [[ -z "$CONFIG" || "$CONFIG" == "null" ]]; then
echo "No exact strategy match found. Falling back to feature/fork logic."
IS_FORK="${{ github.event.pull_request.head.repo.fork && 'true' || 'false' }}"
FORK_SUFFIX=$( [[ "$IS_FORK" == "true" ]] && echo "-fork" || echo "" )
NEW_BRANCH="${BRANCH}${FORK_SUFFIX}-prebuilt"
echo "new_branch=$NEW_BRANCH" >> $GITHUB_OUTPUT
echo "version=$BUILD" >> $GITHUB_OUTPUT
echo "cancel_publish_in_progress=true" >> $GITHUB_OUTPUT
echo "publish_concurrency_group=publish-${BRANCH}" >> $GITHUB_OUTPUT
echo "environment=feature-branch" >> $GITHUB_OUTPUT
echo "extra_version_identifier=feature-branch" >> $GITHUB_OUTPUT
else
echo "Matched config: $CONFIG"
environment=$(echo "$CONFIG" | jq -r '.environment')
echo "environment=$environment" >> $GITHUB_OUTPUT
echo "new_branch=$(echo "$CONFIG" | jq -r '.target_branch')" >> $GITHUB_OUTPUT
cancel="$(echo "$CONFIG" | jq -r '.cancel_publish_in_progress')";
echo "cancel_publish_in_progress=$( [ "$cancel" = "null" ] && echo "true" || echo $cancel)" >> $GITHUB_OUTPUT
echo "publish_concurrency_group=publish-${BRANCH}$( [ "$cancel" = "null" ] || [ "$cancel" = "true" ] || echo "${{ github.sha }}" )" >> $GITHUB_OUTPUT
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');
echo "version=$([ "$is_stable_branch" = "true" ] && echo "$stable_version" || echo "$BUILD")" >> $GITHUB_OUTPUT
echo "extra_version_identifier=${environment}" >> $GITHUB_OUTPUT
fi
echo "build=$BUILD" >> $GITHUB_OUTPUT
cat $GITHUB_OUTPUT
validate_tests:
runs-on: ubuntu-24.04
if: ((github.event_name == 'workflow_dispatch' && inputs.wait_for_tests) || contains(github.event_name, 'pull_request') && (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
needs: [ prepare_strategy ]
if: ${{
((github.event_name == 'workflow_dispatch' && inputs.wait_for_tests) ||
(github.event_name == 'push' && needs.prepare_strategy.outputs.is_stable_branch == 'true') ||
contains(github.event_name, 'pull_request') && (github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
}}
steps:
- uses: actions/checkout@v4
- name: Wait for Tests
@@ -44,19 +101,26 @@ jobs:
with:
workflow: selfdrive_tests.yaml # The workflow file to monitor
github-token: ${{ secrets.GITHUB_TOKEN }}
should-wait-for-start: ${{ github.event_name == 'push' && 'true' || 'false' }}
build:
needs: [ validate_tests ]
needs: [ validate_tests, prepare_strategy ]
concurrency:
group: build-${{ github.head_ref || github.ref_name }}
cancel-in-progress: false
runs-on: [self-hosted, tici]
outputs:
new_branch: ${{ steps.set-env.outputs.new_branch }}
version: ${{ steps.set-env.outputs.version }}
extra_version_identifier: ${{ steps.set-env.outputs.extra_version_identifier }}
commit_sha: ${{ steps.set-env.outputs.commit_sha }}
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
new_branch: ${{ needs.prepare_strategy.outputs.new_branch }}
version: ${{ needs.prepare_strategy.outputs.version }}
extra_version_identifier: ${{ needs.prepare_strategy.outputs.extra_version_identifier }}
commit_sha: ${{ github.sha }}
if: ${{
(always() && !cancelled() && !failure()) &&
needs.prepare_strategy.result == 'success' &&
(needs.validate_tests.result == 'success' || needs.validate_tests.result == 'skipped') &&
(!contains(github.event_name, 'pull_request') ||
(github.event.action == 'labeled' && github.event.label.name == 'prebuilt'))
}}
steps:
- uses: actions/checkout@v4
with:
@@ -74,64 +138,15 @@ jobs:
# for security. Only caches from the default branch are shared across all builds. This is by design and cannot be overridden.
restore-keys: |
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.SOURCE_BRANCH }}
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_C3_SOURCE_BRANCH }}
scons-${{ runner.os }}-${{ runner.arch }}-${{ env.STAGING_SOURCE_BRANCH }}
scons-${{ runner.os }}-${{ runner.arch }}
- name: Set Feature Branch Prebuilt Configuration
id: set_feature_configuration
if: (
!(env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH) &&
!(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH) &&
!(startsWith(github.ref, 'refs/tags/'))
)
run: |
echo "NEW_BRANCH=${{ env.SOURCE_BRANCH }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-prebuilt" >> $GITHUB_ENV
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
- name: Set dev-c3-new prebuilt Configuration
id: set_dev_configuration
if: (
steps.set_feature_configuration.outcome == 'skipped' &&
env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH
)
run: |
echo "NEW_BRANCH=${{ env.DEV_TARGET_BRANCH }}" >> $GITHUB_ENV
echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV
echo "EXTRA_VERSION_IDENTIFIER=${{ github.run_number }}" >> $GITHUB_ENV
- name: Set staging-c3-new prebuilt Configuration
id: set_staging_configuration
if: (
steps.set_feature_configuration.outcome == 'skipped' &&
!contains(github.event_name, 'pull_request') &&
steps.set_dev_configuration.outcome == 'skipped' &&
(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH)
)
run: |
echo "NEW_BRANCH=${{ env.STAGING_TARGET_BRANCH }}" >> $GITHUB_ENV
echo "EXTRA_VERSION_IDENTIFIER=staging" >> $GITHUB_ENV
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-staging" >> $GITHUB_ENV
- name: Set release-c3-new prebuilt Configuration
id: set_tag_configuration
if: (
steps.set_feature_configuration.outcome == 'skipped' &&
!contains(github.event_name, 'pull_request') &&
steps.set_staging_configuration.outcome == 'skipped' &&
startsWith(github.ref, 'refs/tags/')
)
run: |
echo "NEW_BRANCH=${{ env.RELEASE_TARGET_BRANCH }}" >> $GITHUB_ENV
echo "EXTRA_VERSION_IDENTIFIER=release" >> $GITHUB_ENV
echo "VERSION=$(cat common/version.h | grep COMMA_VERSION | sed -e 's/[^0-9|.]//g')-release" >> $GITHUB_ENV
- name: Set environment variables
id: set-env
run: |
# Write to GITHUB_OUTPUT from environment variables
echo "new_branch=$NEW_BRANCH" >> $GITHUB_OUTPUT
[[ ! -z "$EXTRA_VERSION_IDENTIFIER" ]] && echo "extra_version_identifier=$EXTRA_VERSION_IDENTIFIER" >> $GITHUB_OUTPUT
[[ ! -z "$VERSION" ]] && echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "new_branch=${{ needs.prepare_strategy.outputs.new_branch }}" >> $GITHUB_OUTPUT
echo "version=${{ needs.prepare_strategy.outputs.version }}" >> $GITHUB_OUTPUT
echo "extra_version_identifier=${{ needs.prepare_strategy.outputs.extra_version_identifier }}" >> $GITHUB_OUTPUT
echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT
# Set up common environment
@@ -226,15 +241,19 @@ jobs:
if: always()
run: |
PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable
publish:
concurrency:
group: publish-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
needs: [ build ]
# We do a bit of a hack here to avoid canceling the publishing job if a new commit comes in while we're publishing by adding the sha to the group name.
# This means that if multiple commits come in while we're publishing, they will be queued up and publish one after the other.
# Otherwise, if a job is waiting to be published due to environment wait time, it would be canceled by a new commit and restart the wait time.
group: ${{ needs.prepare_strategy.outputs.publish_concurrency_group }}
cancel-in-progress: ${{ needs.prepare_strategy.outputs.cancel_publish_in_progress == 'true' }}
if: ${{ (always() && !cancelled() && !failure()) && needs.build.result == 'success' && needs.prepare_strategy.result == 'success' && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
needs: [ build, prepare_strategy ]
runs-on: ubuntu-24.04
environment: ${{ (contains(fromJSON(vars.AUTO_DEPLOY_PREBUILT_BRANCHES), github.head_ref || github.ref_name) || contains(github.event.pull_request.labels.*.name, 'prebuilt')) && 'auto-deploy' || 'feature-branch' }}
environment: ${{ needs.prepare_strategy.outputs.environment }}
steps:
- uses: actions/checkout@v4
@@ -266,7 +285,7 @@ jobs:
"${{ needs.build.outputs.new_branch }}" \
"${{ needs.build.outputs.version }}" \
"https://x-access-token:${{github.token}}@github.com/sunnypilot/sunnypilot.git" \
"-${{ needs.build.outputs.extra_version_identifier }}"
"${{ needs.build.outputs.extra_version_identifier }}"
echo ""
echo "---- To update the list of branches that auto deploy prebuilts -----"
@@ -274,11 +293,18 @@ jobs:
echo "1. Go to: ${{ github.server_url }}/${{ github.repository }}/settings/variables/actions/AUTO_DEPLOY_PREBUILT_BRANCHES"
echo "2. Current value: ${{ vars.AUTO_DEPLOY_PREBUILT_BRANCHES }}"
echo "3. Update as needed (JSON array with no spaces)"
- name: Tag ${{ needs.prepare_strategy.outputs.environment }}
if: ${{ needs.prepare_strategy.outputs.is_stable_branch == 'true' && (github.event_name != 'push' || !startsWith(github.ref, 'refs/tags/')) }}
run: |
TAG="${{ needs.prepare_strategy.outputs.environment }}/${{ needs.prepare_strategy.outputs.version }}/${{ needs.prepare_strategy.outputs.build }}"
git tag -f -a ${TAG} -m "${{ needs.prepare_strategy.outputs.environment }} @ ${{ needs.prepare_strategy.outputs.version }} of build ${{ needs.build.outputs.build }}."
git push -f origin ${TAG}
notify:
needs: [ build, publish ]
runs-on: ubuntu-24.04
if: ${{ (always() && !failure() && !cancelled()) && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
if: ${{ (always() && !cancelled() && !failure()) && needs.publish.result == 'success' && !failure() && (!contains(github.event_name, 'pull_request') || (github.event.action == 'labeled' && github.event.label.name == 'prebuilt')) }}
steps:
- uses: actions/checkout@v4
- name: Setup Alpine Linux environment

View File

@@ -1,9 +1,9 @@
name: Build dev-c3-new
name: Build dev
env:
DEFAULT_SOURCE_BRANCH: "master"
DEFAULT_TARGET_BRANCH: "master-dev-c3-new"
PR_LABEL: "dev-c3"
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'
@@ -25,7 +25,7 @@ on:
target_branch:
description: 'Target branch to reset and squash into'
required: true
default: 'master-dev-c3-new'
default: 'master-dev'
type: string
cancel_in_progress:
description: 'Cancel any in-progress runs of this workflow'
@@ -43,7 +43,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-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|| (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'))))
)
steps:
- uses: actions/checkout@v4
@@ -55,7 +55,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-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3'))))
|| (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'))))
)
with:
workflow: selfdrive_tests.yaml # The workflow file to monitor

3
.gitignore vendored
View File

@@ -13,9 +13,11 @@ venv/
model2.png
a.out
.hypothesis
.cache/
/docs_site/
*.mp4
*.dylib
*.DSYM
*.d
@@ -48,7 +50,6 @@ cereal/services.h
cereal/gen
cereal/messaging/bridge
selfdrive/mapd/default_speeds_by_region.json
system/proclogd/proclogd
selfdrive/ui/translations/tmp
selfdrive/test/longitudinal_maneuvers/out
selfdrive/car/tests/cars_dump

41
.vscode/launch.json vendored
View File

@@ -23,6 +23,11 @@
"id": "args",
"description": "Arguments to pass to the process",
"type": "promptString"
},
{
"id": "replayArg",
"type": "promptString",
"description": "Enter route or segment to replay."
}
],
"configurations": [
@@ -40,7 +45,41 @@
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/${input:cpp_process}",
"cwd": "${workspaceFolder}",
"cwd": "${workspaceFolder}"
},
{
"name": "Attach LLDB to Replay drive",
"type": "lldb",
"request": "attach",
"pid": "${command:pickMyProcess}",
"initCommands": [
"script import time; time.sleep(3)"
]
},
{
"name": "Replay drive",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/opendbc/safety/tests/safety_replay/replay_drive.py",
"args": [
"${input:replayArg}"
],
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"subProcess": true,
"stopOnEntry": false
}
],
"compounds": [
{
"name": "Replay drive + Safety LLDB",
"configurations": [
"Replay drive",
"Attach LLDB to Replay drive"
]
}
]
}

34
Jenkinsfile vendored
View File

@@ -167,7 +167,7 @@ node {
env.GIT_COMMIT = checkout(scm).GIT_COMMIT
def excludeBranches = ['__nightly', 'devel', 'devel-staging', 'release3', 'release3-staging',
'testing-closet*', 'hotfix-*']
'release-tici', 'testing-closet*', 'hotfix-*']
def excludeRegex = excludeBranches.join('|').replaceAll('\\*', '.*')
if (env.BRANCH_NAME != 'master' && !env.BRANCH_NAME.contains('__jenkins_loop_')) {
@@ -178,7 +178,7 @@ node {
try {
if (env.BRANCH_NAME == 'devel-staging') {
deviceStage("build release3-staging", "tici-needs-can", [], [
deviceStage("build release3-staging", "tizi-needs-can", [], [
step("build release3-staging", "RELEASE_BRANCH=release3-staging $SOURCE_DIR/release/build_release.sh"),
])
}
@@ -186,12 +186,12 @@ node {
if (env.BRANCH_NAME == '__nightly') {
parallel (
'nightly': {
deviceStage("build nightly", "tici-needs-can", [], [
deviceStage("build nightly", "tizi-needs-can", [], [
step("build nightly", "RELEASE_BRANCH=nightly $SOURCE_DIR/release/build_release.sh"),
])
},
'nightly-dev': {
deviceStage("build nightly-dev", "tici-needs-can", [], [
deviceStage("build nightly-dev", "tizi-needs-can", [], [
step("build nightly-dev", "PANDA_DEBUG_BUILD=1 RELEASE_BRANCH=nightly-dev $SOURCE_DIR/release/build_release.sh"),
])
},
@@ -200,39 +200,30 @@ node {
if (!env.BRANCH_NAME.matches(excludeRegex)) {
parallel (
// tici tests
'onroad tests': {
deviceStage("onroad", "tici-needs-can", ["UNSAFE=1"], [
deviceStage("onroad", "tizi-needs-can", ["UNSAFE=1"], [
step("build openpilot", "cd system/manager && ./build.py"),
step("check dirty", "release/check-dirty.sh"),
step("onroad tests", "pytest selfdrive/test/test_onroad.py -s", [timeout: 60]),
])
},
'HW + Unit Tests': {
deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [
deviceStage("tizi-hardware", "tizi-common", ["UNSAFE=1"], [
step("build", "cd system/manager && ./build.py"),
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
step("test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"),
step("test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py", [diffPaths: ["system/loggerd/"]]),
step("test pigeond", "pytest system/ubloxd/tests/test_pigeond.py", [diffPaths: ["system/ubloxd/"]]),
step("test manager", "pytest system/manager/test/test_manager.py"),
])
},
'loopback': {
deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [
deviceStage("loopback", "tizi-loopback", ["UNSAFE=1"], [
step("build openpilot", "cd system/manager && ./build.py"),
step("test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
])
},
'camerad AR0231': {
deviceStage("AR0231", "tici-ar0231", ["UNSAFE=1"], [
step("build", "cd system/manager && ./build.py"),
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
])
},
'camerad OX03C10': {
deviceStage("OX03C10", "tici-ox03c10", ["UNSAFE=1"], [
deviceStage("OX03C10", "tizi-ox03c10", ["UNSAFE=1"], [
step("build", "cd system/manager && ./build.py"),
step("test camerad", "pytest system/camerad/test/test_camerad.py", [timeout: 60]),
step("test exposure", "pytest system/camerad/test/test_exposure.py"),
@@ -246,17 +237,13 @@ node {
])
},
'sensord': {
deviceStage("LSM + MMC", "tici-lsmc", ["UNSAFE=1"], [
step("build", "cd system/manager && ./build.py"),
step("test sensord", "pytest system/sensord/tests/test_sensord.py"),
])
deviceStage("BMX + LSM", "tici-bmx-lsm", ["UNSAFE=1"], [
deviceStage("LSM + MMC", "tizi-lsmc", ["UNSAFE=1"], [
step("build", "cd system/manager && ./build.py"),
step("test sensord", "pytest system/sensord/tests/test_sensord.py"),
])
},
'replay': {
deviceStage("model-replay", "tici-replay", ["UNSAFE=1"], [
deviceStage("model-replay", "tizi-replay", ["UNSAFE=1"], [
step("build", "cd system/manager && ./build.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
step("model replay", "selfdrive/test/process_replay/model_replay.py", [diffPaths: ["selfdrive/modeld/", "tinygrad_repo", "selfdrive/test/process_replay/model_replay.py"]]),
])
@@ -266,7 +253,6 @@ node {
step("build openpilot", "cd system/manager && ./build.py"),
step("test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"),
step("test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"),
step("test pandad", "pytest selfdrive/pandad/tests/test_pandad.py", [diffPaths: ["panda", "selfdrive/pandad/"]]),
step("test amp", "pytest system/hardware/tici/tests/test_amplifier.py"),
// TODO: enable once new AGNOS is available
// step("test esim", "pytest system/hardware/tici/tests/test_esim.py"),

View File

@@ -22,34 +22,24 @@ https://docs.sunnypilot.ai/ is your one stop shop for everything from features t
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 `release-c3` 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-c3-new` branch.
### If you want to use our newest branches (our rewrite)
> [!TIP]
>You can see the rewrite state on our [rewrite project board](https://github.com/orgs/sunnypilot/projects/2), and to install the new branches, you can use the following links
* 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: ```release-c3.sunnypilot.ai```.
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://staging-c3-new.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`.
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: `release-c3`
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging-c3-new`
| Branch | Installation URL |
|:------------:|:--------------------------------:|
| `release-c3` | https://release-c3.sunnypilot.ai |
| `staging-c3` | https://staging-c3.sunnypilot.ai |
| `dev-c3` | https://dev-c3.sunnypilot.ai |
### If you want to use our newest branches (our rewrite)
> [!TIP]
>You can see the rewrite state on our [rewrite project board](https://github.com/orgs/sunnypilot/projects/2), and to install the new branches, you can use the following links
> [!IMPORTANT]
> It is recommended to [re-flash AGNOS](https://flash.comma.ai/) if you intend to downgrade from the new branches.
> You can still restore the latest sunnylink backup made on the old branches.
| Branch | Installation URL |
|:----------------:|:---------------------------------------------:|
@@ -59,8 +49,31 @@ Please refer to [Recommended Branches](#-recommended-branches) to find your pref
| `release-c3-new` | **Not yet available**. |
> [!TIP]
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-c3-new'.
> [!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.
<details>
<summary>Older legacy branches</summary>
### If you want to use our older legacy branches (*not recommended*)
> [**IMPORTANT**]
> It is recommended to [re-flash AGNOS](https://flash.comma.ai/) if you intend to downgrade from the new branches.
> You can still restore the latest sunnylink backup made on the old branches.
| Branch | Installation URL |
|:------------:|:--------------------------------:|
| `release-c3` | https://release-c3.sunnypilot.ai |
| `staging-c3` | https://staging-c3.sunnypilot.ai |
| `dev-c3` | https://dev-c3.sunnypilot.ai |
</details>
## 🎆 Pull Requests
We welcome both pull requests and issues on GitHub. Bug fixes are encouraged.

View File

@@ -1,11 +1,28 @@
Version 0.10.0 (2025-07-07)
Version 0.10.1 (2025-09-08)
========================
* New driving model
* Lead car ground-truth fixes
* Ported over VAE from the MLSIM stack
* New training architecture described in CVPR paper
* World Model: removed global localization inputs
* World Model: 2x the number of parameters
* World Model: trained on 4x the number of segments
* Driving Vision Model: trained on 4x the number of segments
* Honda City 2023 support thanks to vanillagorillaa and drFritz!
* Honda N-Box 2018 support thanks to miettal!
* Honda Odyssey 2021-25 support thanks to csouers and MVL!
Version 0.10.0 (2025-08-05)
========================
* New driving model
* New training architecture
* Described in our CVPR paper: "Learning to Drive from a World Model"
* Longitudinal MPC replaced by E2E planning from World Model in Experimental Mode
* Action from lateral MPC as training objective replaced by E2E planning from World Model
* Low-speed lead car ground-truth fixes
* Enable live-learned steering actuation delay
* Opt-in audio recording for dashcam video
* Acura MDX 2025 support thanks to vanillagorillaa and MVL!
* Honda Accord 2023-25 support thanks to vanillagorillaa and MVL!
* Honda CR-V 2023-25 support thanks to vanillagorillaa and MVL!
* Honda Pilot 2023-25 support thanks to vanillagorillaa and MVL!
Version 0.9.9 (2025-05-23)
========================

View File

@@ -17,7 +17,7 @@ AGNOS = TICI
Decider('MD5-timestamp')
SetOption('num_jobs', int(os.cpu_count()/2))
SetOption('num_jobs', max(1, int(os.cpu_count()/2)))
AddOption('--kaitai',
action='store_true',
@@ -359,11 +359,6 @@ SConscript([
'system/ubloxd/SConscript',
'system/loggerd/SConscript',
])
if arch != "Darwin":
SConscript([
'system/logcatd/SConscript',
'system/proclogd/SConscript',
])
if arch == "larch64":
SConscript(['system/camerad/SConscript'])

View File

@@ -25,6 +25,26 @@ struct ModularAssistiveDrivingSystem {
}
}
struct IntelligentCruiseButtonManagement {
state @0 :IntelligentCruiseButtonManagementState;
sendButton @1 :SendButtonState;
vTarget @2 :Float32;
enum IntelligentCruiseButtonManagementState {
inactive @0; # No button press or default state
preActive @1; # Pre-active state before transitioning to increasing or decreasing
increasing @2; # Increasing speed
decreasing @3; # Decreasing speed
holding @4; # Holding steady speed
}
enum SendButtonState {
none @0;
increase @1;
decrease @2;
}
}
# Same struct as Log.RadarState.LeadData
struct LeadData {
dRel @0 :Float32;
@@ -48,6 +68,7 @@ struct LeadData {
struct SelfdriveStateSP @0x81c2f05a394cf4af {
mads @0 :ModularAssistiveDrivingSystem;
intelligentCruiseButtonManagement @1 :IntelligentCruiseButtonManagement;
}
struct ModelManagerSP @0xaedffd8f31e7b55d {
@@ -122,6 +143,10 @@ struct ModelManagerSP @0xaedffd8f31e7b55d {
struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
dec @0 :DynamicExperimentalControl;
longitudinalPlanSource @1 :LongitudinalPlanSource;
smartCruiseControl @2 :SmartCruiseControl;
speedLimitAssist @3 :SpeedLimitAssist;
events @4 :List(OnroadEventSP.Event);
struct DynamicExperimentalControl {
state @0 :DynamicExperimentalControlState;
@@ -133,6 +158,61 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
blended @1;
}
}
struct SmartCruiseControl {
vision @0 :Vision;
struct Vision {
state @0 :VisionState;
vTarget @1 :Float32;
aTarget @2 :Float32;
currentLateralAccel @3 :Float32;
maxPredictedLateralAccel @4 :Float32;
enabled @5 :Bool;
active @6 :Bool;
}
enum VisionState {
disabled @0; # System disabled or inactive.
enabled @1; # No predicted substantial turn on vision range.
entering @2; # A substantial turn is predicted ahead, adapting speed to turn comfort levels.
turning @3; # Actively turning. Managing acceleration to provide a roll on turn feeling.
leaving @4; # Road ahead straightens. Start to allow positive acceleration.
overriding @5; # System overriding with manual control.
}
}
struct SpeedLimitAssist {
state @0 :SpeedLimitAssistState;
enabled @1 :Bool;
active @2 :Bool;
speedLimit @3 :Float32;
speedLimitOffset @4 :Float32;
distToSpeedLimit @5 :Float32;
source @6 :SpeedLimitSource;
}
enum LongitudinalPlanSource {
cruise @0;
sccVision @1;
speedLimitAssist @2;
}
enum SpeedLimitAssistState {
disabled @0;
inactive @1; # No speed limit set or not enabled by parameter.
preActive @2;
pending @3; # Awaiting new speed limit.
adapting @4; # Reducing speed to match new speed limit.
active @5; # Cruising at speed limit.
overriding @6; # System overriding with manual control.
}
enum SpeedLimitSource {
none @0;
car @1;
map @2;
}
}
struct OnroadEventSP @0xda96579883444c35 {
@@ -172,12 +252,20 @@ struct OnroadEventSP @0xda96579883444c35 {
experimentalModeSwitched @14;
wrongCarModeAlertOnly @15;
pedalPressedAlertOnly @16;
laneTurnLeft @17;
laneTurnRight @18;
speedLimitPreActive @19;
speedLimitActive @20;
speedLimitConfirmed @21;
speedLimitChanged @22;
}
}
struct CarParamsSP @0x80ae746ee2596b11 {
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
safetyParam @1 : Int16; # flags for sunnypilot's custom safety flags
pcmCruiseSpeed @3 :Bool = true;
intelligentCruiseButtonManagementAvailable @4 :Bool;
neuralNetworkLateralControl @2 :NeuralNetworkLateralControl;
@@ -197,10 +285,24 @@ struct CarControlSP @0xa5cd762cd951a455 {
params @1 :List(Param);
leadOne @2 :LeadData;
leadTwo @3 :LeadData;
intelligentCruiseButtonManagement @4 :IntelligentCruiseButtonManagement;
struct Param {
key @0 :Text;
value @1 :Text;
type @2 :ParamType;
value @3 :Data;
valueDEPRECATED @1 :Text; # The data type change may cause issues with backwards compatibility.
}
enum ParamType {
string @0;
bool @1;
int @2;
float @3;
time @4;
json @5;
bytes @6;
}
}
@@ -247,6 +349,7 @@ struct BackupManagerSP @0xf98d843bfd7004a3 {
}
struct CarStateSP @0xb86e6369214c01c8 {
speedLimit @0 :Float32; # m/s
}
struct LiveMapDataSP @0xf416ec09499d9d19 {
@@ -258,9 +361,16 @@ struct LiveMapDataSP @0xf416ec09499d9d19 {
roadName @5 :Text;
}
struct CustomReserved9 @0xa1680744031fdb2d {
struct ModelDataV2SP @0xa1680744031fdb2d {
laneTurnDirection @0 :TurnDirection;
}
enum TurnDirection {
none @0;
turnLeft @1;
turnRight @2;
}
struct CustomReserved10 @0xcb9fd56c7057593a {
}

View File

@@ -127,8 +127,9 @@ struct OnroadEvent @0xc4fa6047f024e718 {
espActive @90;
personalityChanged @91;
aeb @92;
userFlag @95;
userBookmark @95;
excessiveActuation @96;
audioFeedback @97;
soundsUnavailableDEPRECATED @47;
}
@@ -584,7 +585,6 @@ struct PandaState @0xa7649e2575e4591e {
heartbeatLost @22 :Bool;
interruptLoad @25 :Float32;
fanPower @28 :UInt8;
fanStallCount @34 :UInt8;
spiErrorCount @33 :UInt16;
@@ -713,6 +713,7 @@ struct PandaState @0xa7649e2575e4591e {
usbPowerModeDEPRECATED @12 :PeripheralState.UsbPowerModeDEPRECATED;
safetyParamDEPRECATED @20 :Int16;
safetyParam2DEPRECATED @26 :UInt32;
fanStallCountDEPRECATED @34 :UInt8;
}
struct PeripheralState {
@@ -2468,7 +2469,7 @@ struct DebugAlert {
alertText2 @1 :Text;
}
struct UserFlag {
struct UserBookmark @0xfe346a9de48d9b50 {
}
struct SoundPressure @0xdc24138990726023 {
@@ -2486,6 +2487,11 @@ struct AudioData {
sampleRate @1 :UInt32;
}
struct AudioFeedback {
audio @0 :AudioData;
blockNum @1 :UInt16;
}
struct Touch {
sec @0 :Int64;
usec @1 :Int64;
@@ -2586,9 +2592,13 @@ struct Event {
mapRenderState @105: MapRenderState;
# UI services
userFlag @93 :UserFlag;
uiDebug @102 :UIDebug;
# driving feedback
userBookmark @93 :UserBookmark;
bookmarkButton @148 :UserBookmark;
audioFeedback @149 :AudioFeedback;
# *********** debug ***********
testJoystick @52 :Joystick;
roadEncodeData @86 :EncodeData;
@@ -2621,7 +2631,7 @@ struct Event {
backupManagerSP @113 :Custom.BackupManagerSP;
carStateSP @114 :Custom.CarStateSP;
liveMapDataSP @115 :Custom.LiveMapDataSP;
customReserved9 @116 :Custom.CustomReserved9;
modelDataV2SP @116 :Custom.ModelDataV2SP;
customReserved10 @136 :Custom.CustomReserved10;
customReserved11 @137 :Custom.CustomReserved11;
customReserved12 @138 :Custom.CustomReserved12;

View File

@@ -33,7 +33,7 @@ MessageContext message_context;
struct SubMaster::SubMessage {
std::string name;
SubSocket *socket = nullptr;
int freq = 0;
float freq = 0.0f;
bool updated = false, alive = false, valid = false, ignore_alive;
uint64_t rcv_time = 0, rcv_frame = 0;
void *allocated_msg_reader = nullptr;

View File

@@ -177,8 +177,8 @@ class TestMessaging:
# wait 5 socket timeouts before sending
msg = random_carstate()
delayed_send(sock_timeout*5, pub_sock, msg.to_bytes())
start_time = time.monotonic()
delayed_send(sock_timeout*5, pub_sock, msg.to_bytes())
recvd = messaging.recv_one_retry(sub_sock)
assert (time.monotonic() - start_time) >= sock_timeout*5
assert isinstance(recvd, capnp._DynamicStructReader)

View File

@@ -86,7 +86,7 @@ class TestSubMaster:
"cameraOdometry": (20, 10),
"liveCalibration": (4, 4),
"carParams": (None, None),
"userFlag": (None, None),
"userBookmark": (None, None),
}
for service, (max_freq, min_freq) in checks.items():

View File

@@ -72,9 +72,11 @@ _services: dict[str, tuple] = {
"navRoute": (True, 0.),
"navThumbnail": (True, 0.),
"qRoadEncodeIdx": (False, 20.),
"userFlag": (True, 0., 1),
"userBookmark": (True, 0., 1),
"soundPressure": (True, 10., 10),
"rawAudioData": (False, 20.),
"bookmarkButton": (True, 0., 1),
"audioFeedback": (True, 0., 1),
# sunnypilot
"modelManagerSP": (False, 1., 1),
@@ -86,6 +88,7 @@ _services: dict[str, tuple] = {
"carControlSP": (True, 100., 10),
"carStateSP": (True, 100., 10),
"liveMapDataSP": (True, 1., 1),
"modelDataV2SP": (True, 20.),
# debug
"uiDebug": (True, 0., 1),
@@ -118,12 +121,12 @@ def build_header():
h += "#include <map>\n"
h += "#include <string>\n"
h += "struct service { std::string name; bool should_log; int frequency; int decimation; };\n"
h += "struct service { std::string name; bool should_log; float frequency; int decimation; };\n"
h += "static std::map<std::string, service> services = {\n"
for k, v in SERVICE_LIST.items():
should_log = "true" if v.should_log else "false"
decimation = -1 if v.decimation is None else v.decimation
h += ' { "%s", {"%s", %s, %d, %d}},\n' % \
h += ' { "%s", {"%s", %s, %f, %d}},\n' % \
(k, k, should_log, v.frequency, decimation)
h += "};\n"

View File

@@ -1,6 +1,7 @@
import numpy as np
class Conversions:
# conversions
class CV:
# Speed
MPH_TO_KPH = 1.609344
KPH_TO_MPH = 1. / MPH_TO_KPH
@@ -17,3 +18,6 @@ class Conversions:
# Mass
LB_TO_KG = 0.453592
ACCELERATION_DUE_TO_GRAVITY = 9.81 # m/s^2

View File

@@ -1 +1 @@
#define DEFAULT_MODEL "Space Lab 2 (Default)"
#define DEFAULT_MODEL "Firehose (Default)"

View File

@@ -12,7 +12,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ApiCache_Device", {PERSISTENT, STRING}},
{"ApiCache_FirehoseStats", {PERSISTENT, JSON}},
{"AssistNowToken", {PERSISTENT, STRING}},
{"AthenadPid", {PERSISTENT, STRING}},
{"AthenadPid", {PERSISTENT, INT}},
{"AthenadUploadQueue", {PERSISTENT, JSON}},
{"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}},
{"BootCount", {PERSISTENT, INT}},
@@ -73,9 +73,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"LastOffroadStatusPacket", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON}},
{"LastPowerDropDetected", {CLEAR_ON_MANAGER_START, STRING}},
{"LastUpdateException", {CLEAR_ON_MANAGER_START, STRING}},
{"LastUpdateRouteCount", {PERSISTENT, INT}},
{"LastUpdateRouteCount", {PERSISTENT, INT, "0"}},
{"LastUpdateTime", {PERSISTENT, TIME}},
{"LastUpdateUptimeOnroad", {PERSISTENT, FLOAT}},
{"LastUpdateUptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
{"LiveDelay", {PERSISTENT | BACKUP, BYTES}},
{"LiveParameters", {PERSISTENT, JSON}},
{"LiveParametersV2", {PERSISTENT, BYTES}},
@@ -94,7 +94,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
{"Offroad_Recalibration", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
{"Offroad_StorageMissing", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_UnregisteredHardware", {CLEAR_ON_MANAGER_START, JSON}},
{"Offroad_UpdateFailed", {CLEAR_ON_MANAGER_START, JSON}},
@@ -105,6 +104,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"PandaSignatures", {CLEAR_ON_MANAGER_START, BYTES}},
{"PrimeType", {PERSISTENT, INT}},
{"RecordAudio", {PERSISTENT | BACKUP, BOOL}},
{"RecordAudioFeedback", {PERSISTENT | BACKUP, BOOL, "0"}},
{"RecordFront", {PERSISTENT | BACKUP, BOOL}},
{"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
{"SecOCKey", {PERSISTENT | DONT_LOG | BACKUP, STRING}},
@@ -139,21 +139,29 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CarParamsSP", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}},
{"CarParamsSPCache", {CLEAR_ON_MANAGER_START, BYTES}},
{"CarParamsSPPersistent", {PERSISTENT, BYTES}},
{"CarPlatformBundle", {PERSISTENT | BACKUP, STRING}},
{"CarPlatformBundle", {PERSISTENT | BACKUP, JSON}},
{"ChevronInfo", {PERSISTENT | BACKUP, INT, "4"}},
{"CustomAccIncrementsEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
{"CustomAccLongPressIncrement", {PERSISTENT | BACKUP, INT, "5"}},
{"CustomAccShortPressIncrement", {PERSISTENT | BACKUP, INT, "1"}},
{"DeviceBootMode", {PERSISTENT | BACKUP, INT, "0"}},
{"DevUIInfo", {PERSISTENT | BACKUP, INT, "0"}},
{"EnableCopyparty", {PERSISTENT | BACKUP, BOOL}},
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
{"GithubRunnerSufficientVoltage", {CLEAR_ON_MANAGER_START , BOOL}},
{"IntelligentCruiseButtonManagement", {PERSISTENT | BACKUP , BOOL}},
{"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}},
{"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}},
{"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}},
{"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}},
{"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}},
{"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}},
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
{"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}},
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
{"SmartCruiseControlVision", {PERSISTENT | BACKUP, BOOL, "0"}},
{"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}},
// MADS params
{"Mads", {PERSISTENT | BACKUP, BOOL, "1"}},
@@ -162,11 +170,12 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"MadsUnifiedEngagementMode", {PERSISTENT | BACKUP, BOOL, "1"}},
// Model Manager params
{"ModelManager_ActiveBundle", {PERSISTENT, STRING}},
{"ModelManager_ActiveBundle", {PERSISTENT, JSON}},
{"ModelManager_ClearCache", {CLEAR_ON_MANAGER_START, BOOL}},
{"ModelManager_DownloadIndex", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, INT, "0"}},
{"ModelManager_Favs", {PERSISTENT | BACKUP, STRING}},
{"ModelManager_LastSyncTime", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, INT, "0"}},
{"ModelManager_ModelsCache", {PERSISTENT | BACKUP, STRING}},
{"ModelManager_ModelsCache", {PERSISTENT | BACKUP, JSON}},
// Neural Network Lateral Control
{"NeuralNetworkLateralControl", {PERSISTENT | BACKUP, BOOL, "0"}},
@@ -177,7 +186,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"SunnylinkCache_Roles", {PERSISTENT, STRING}},
{"SunnylinkCache_Users", {PERSISTENT, STRING}},
{"SunnylinkDongleId", {PERSISTENT, STRING}},
{"SunnylinkdPid", {PERSISTENT, STRING}},
{"SunnylinkdPid", {PERSISTENT, INT}},
{"SunnylinkEnabled", {PERSISTENT, BOOL}},
// Backup Manager params
@@ -190,21 +199,23 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}},
{"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}},
// model panel params
// sunnypilot model params
{"LagdToggle", {PERSISTENT | BACKUP, BOOL, "1"}},
{"LagdToggleDesc", {PERSISTENT, STRING}},
{"LagdToggleDelay", {PERSISTENT | BACKUP, FLOAT, "0.2"}},
{"LagdValueCache", {PERSISTENT, FLOAT, "0.2"}},
{"LaneTurnDesire", {PERSISTENT | BACKUP, BOOL, "0"}},
{"LaneTurnValue", {PERSISTENT | BACKUP, FLOAT, "19.0"}},
// mapd
{"MapAdvisorySpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, FLOAT}},
{"MapdVersion", {PERSISTENT, STRING, ""}},
{"MapdVersion", {PERSISTENT, STRING}},
{"MapSpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, FLOAT, "0.0"}},
{"NextMapSpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, STRING}},
{"NextMapSpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, JSON}},
{"Offroad_OSMUpdateRequired", {CLEAR_ON_MANAGER_START, JSON}},
{"OsmDbUpdatesCheck", {CLEAR_ON_MANAGER_START, BOOL}}, // mapd database update happens with device ON, reset on boot
{"OSMDownloadBounds", {PERSISTENT, STRING}},
{"OsmDownloadedDate", {PERSISTENT, STRING, "0.0"}},
{"OSMDownloadLocations", {PERSISTENT, STRING}},
{"OSMDownloadLocations", {PERSISTENT, JSON}},
{"OSMDownloadProgress", {CLEAR_ON_MANAGER_START, JSON}},
{"OsmLocal", {PERSISTENT, BOOL}},
{"OsmLocationName", {PERSISTENT, STRING}},
@@ -213,5 +224,15 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"OsmStateName", {PERSISTENT, STRING, "All"}},
{"OsmStateTitle", {PERSISTENT, STRING}},
{"OsmWayTest", {PERSISTENT, STRING}},
{"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING, ""}},
{"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING}},
// Speed Limit Control
{"SpeedLimitAssist", {PERSISTENT | BACKUP, BOOL, "0"}},
{"SpeedLimitPolicy", {PERSISTENT | BACKUP, INT, "3"}},
{"SpeedLimitEngageType", {PERSISTENT | BACKUP, INT, "0"}},
{"SpeedLimitOffsetType", {PERSISTENT | BACKUP, INT, "0"}},
{"SpeedLimitValueOffset", {PERSISTENT | BACKUP, INT, "0"}},
{"SpeedLimitWarningType", {PERSISTENT | BACKUP, INT, "0"}},
{"SpeedLimitWarningOffsetType", {PERSISTENT | BACKUP, INT, "0"}},
{"SpeedLimitWarningValueOffset", {PERSISTENT | BACKUP, INT, "0"}},
};

View File

@@ -103,14 +103,14 @@ cdef class Params:
return cast(value)
raise TypeError(f"Type mismatch while writing param {key}: {proposed_type=} {expected_type=} {value=}")
def cpp2python(self, t, value, default, key):
def _cpp2python(self, t, value, default, key):
if value is None:
return None
try:
return CPP_2_PYTHON[t](value)
except (KeyError, TypeError, ValueError):
cloudlog.warning(f"Failed to cast param {key} with {value=} from type {t=}")
return self.cpp2python(t, default, None, key)
return self._cpp2python(t, default, None, key)
def get(self, key, bool block=False, bool return_default=False):
cdef string k = self.check_key(key)
@@ -127,8 +127,8 @@ cdef class Params:
# it means we got an interrupt while waiting
raise KeyboardInterrupt
else:
return self.cpp2python(t, default_val, None, key)
return self.cpp2python(t, val, default_val, key)
return self._cpp2python(t, default_val, None, key)
return self._cpp2python(t, val, default_val, key)
def get_bool(self, key, bool block=False):
cdef string k = self.check_key(key)
@@ -189,4 +189,9 @@ cdef class Params:
cdef string k = self.check_key(key)
cdef ParamKeyType t = self.p.getKeyType(k)
cdef optional[string] default = self.p.getKeyDefaultValue(k)
return self.cpp2python(t, default.value(), None, key) if default.has_value() else None
return self._cpp2python(t, default.value(), None, key) if default.has_value() else None
def cpp2python(self, key, value):
cdef string k = self.check_key(key)
cdef ParamKeyType t = self.p.getKeyType(k)
return self._cpp2python(t, value, None, key)

View File

@@ -14,10 +14,8 @@ class PIDController:
if isinstance(self._k_d, Number):
self._k_d = [[0], [self._k_d]]
self.pos_limit = pos_limit
self.neg_limit = neg_limit
self.set_limits(pos_limit, neg_limit)
self.i_unwind_rate = 0.3 / rate
self.i_rate = 1.0 / rate
self.speed = 0.0
@@ -35,10 +33,6 @@ class PIDController:
def k_d(self):
return np.interp(self.speed, self._k_d[0], self._k_d[1])
@property
def error_integral(self):
return self.i/self.k_i
def reset(self):
self.p = 0.0
self.i = 0.0
@@ -46,25 +40,25 @@ class PIDController:
self.f = 0.0
self.control = 0
def update(self, error, error_rate=0.0, speed=0.0, override=False, feedforward=0., freeze_integrator=False):
self.speed = speed
def set_limits(self, pos_limit, neg_limit):
self.pos_limit = pos_limit
self.neg_limit = neg_limit
def update(self, error, error_rate=0.0, speed=0.0, feedforward=0., freeze_integrator=False):
self.speed = speed
self.p = float(error) * self.k_p
self.f = feedforward * self.k_f
self.d = error_rate * self.k_d
if override:
self.i -= self.i_unwind_rate * float(np.sign(self.i))
else:
if not freeze_integrator:
self.i = self.i + error * self.k_i * self.i_rate
if not freeze_integrator:
i = self.i + error * self.k_i * self.i_rate
# Clip i to prevent exceeding control limits
control_no_i = self.p + self.d + self.f
control_no_i = np.clip(control_no_i, self.neg_limit, self.pos_limit)
self.i = np.clip(self.i, self.neg_limit - control_no_i, self.pos_limit - control_no_i)
# Don't allow windup if already clipping
test_control = self.p + i + self.d + self.f
i_upperbound = self.i if test_control > self.pos_limit else self.pos_limit
i_lowerbound = self.i if test_control < self.neg_limit else self.neg_limit
self.i = np.clip(i, i_lowerbound, i_upperbound)
control = self.p + self.i + self.d + self.f
self.control = np.clip(control, self.neg_limit, self.pos_limit)
return self.control

View File

@@ -9,20 +9,19 @@ from openpilot.system.hardware.hw import Paths
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
class OpenpilotPrefix:
def __init__(self, prefix: str = None, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
def __init__(self, prefix: str = None, create_dirs_on_enter: bool = True, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
self.msgq_path = os.path.join(Paths.shm_path(), self.prefix)
self.create_dirs_on_enter = create_dirs_on_enter
self.clean_dirs_on_exit = clean_dirs_on_exit
self.shared_download_cache = shared_download_cache
def __enter__(self):
self.original_prefix = os.environ.get('OPENPILOT_PREFIX', None)
os.environ['OPENPILOT_PREFIX'] = self.prefix
try:
os.mkdir(self.msgq_path)
except FileExistsError:
pass
os.makedirs(Paths.log_root(), exist_ok=True)
if self.create_dirs_on_enter:
self.create_dirs()
if self.shared_download_cache:
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
@@ -40,6 +39,13 @@ class OpenpilotPrefix:
pass
return False
def create_dirs(self):
try:
os.mkdir(self.msgq_path)
except FileExistsError:
pass
os.makedirs(Paths.log_root(), exist_ok=True)
def clean_dirs(self):
symlink_path = Params().get_param_path()
if os.path.exists(symlink_path):

View File

@@ -1,4 +1,6 @@
import subprocess
from contextlib import contextmanager
from subprocess import Popen, PIPE, TimeoutExpired
def run_cmd(cmd: list[str], cwd=None, env=None) -> str:
@@ -11,3 +13,16 @@ def run_cmd_default(cmd: list[str], default: str = "", cwd=None, env=None) -> st
except subprocess.CalledProcessError:
return default
@contextmanager
def managed_proc(cmd: list[str], env: dict[str, str]):
proc = Popen(cmd, env=env, stdout=PIPE, stderr=PIPE)
try:
yield proc
finally:
if proc.poll() is None:
proc.terminate()
try:
proc.wait(timeout=5)
except TimeoutExpired:
proc.kill()

View File

@@ -37,9 +37,9 @@ class TestParams:
def test_params_two_things(self):
self.params.put("DongleId", "bob")
self.params.put("AthenadPid", "123")
self.params.put("AthenadPid", 123)
assert self.params.get("DongleId") == "bob"
assert self.params.get("AthenadPid") == "123"
assert self.params.get("AthenadPid") == 123
def test_params_get_block(self):
def _delayed_writer():

View File

@@ -1,4 +1,5 @@
#include "common/util.h"
#include "common/swaglog.h"
#include <sys/ioctl.h>
#include <sys/stat.h>
@@ -151,11 +152,16 @@ int safe_fflush(FILE *stream) {
return ret;
}
int safe_ioctl(int fd, unsigned long request, void *argp) {
int safe_ioctl(int fd, unsigned long request, void *argp, const char* exception_msg) {
int ret;
do {
ret = ioctl(fd, request, argp);
} while ((ret == -1) && (errno == EINTR));
if (ret == -1 && exception_msg) {
LOGE("safe_ioctl error: %s %s(%d) (fd: %d request: %lx argp: %p)", exception_msg, strerror(errno), errno, fd, request, argp);
throw std::runtime_error(exception_msg);
}
return ret;
}

View File

@@ -88,7 +88,7 @@ int write_file(const char* path, const void* data, size_t size, int flags = O_WR
FILE* safe_fopen(const char* filename, const char* mode);
size_t safe_fwrite(const void * ptr, size_t size, size_t count, FILE * stream);
int safe_fflush(FILE *stream);
int safe_ioctl(int fd, unsigned long request, void *argp);
int safe_ioctl(int fd, unsigned long request, void *argp, const char* exception_msg = nullptr);
std::string readlink(const std::string& path);
bool file_exists(const std::string& fn);

View File

@@ -1 +1 @@
#define COMMA_VERSION "0.10.0"
#define COMMA_VERSION "0.10.1"

View File

@@ -4,12 +4,13 @@
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.
# 313 Supported Cars
# 334 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|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Acura ILX 2016-18">Buy Here</a></sub></details>|||
|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Acura ILX 2019">Buy Here</a></sub></details>|||
|Acura|MDX 2025|All except Type S|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 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=Acura MDX 2025">Buy Here</a></sub></details>|||
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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=Acura RDX 2016-18">Buy Here</a></sub></details>|||
|Acura|RDX 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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=Acura RDX 2019-21">Buy Here</a></sub></details>|||
|Audi|A3 2014-19|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 A3 2014-19">Buy Here</a></sub></details>|||
@@ -72,18 +73,25 @@ A supported vehicle is one that just works when you install a comma device. All
|Genesis|GV80 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M 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=Genesis GV80 2023">Buy Here</a></sub></details>|||
|GMC|Sierra 1500 2020-21|Driver Alert 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=GMC Sierra 1500 2020-21">Buy Here</a></sub></details>|<a href="https://youtu.be/5HbNoBLzRwE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Accord 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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=Honda Accord 2018-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Accord 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 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=Honda Accord 2023-25">Buy Here</a></sub></details>|||
|Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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=Honda Accord Hybrid 2018-22">Buy Here</a></sub></details>|||
|Honda|Accord Hybrid 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 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=Honda Accord Hybrid 2023-25">Buy Here</a></sub></details>|||
|Honda|City (Brazil only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|14 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 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=Honda City (Brazil only) 2023">Buy Here</a></sub></details>|||
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<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=Honda Civic 2016-18">Buy Here</a></sub></details>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch 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=Honda Civic 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch 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=Honda Civic 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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=Honda Civic Hatchback 2017-21">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback 2017-18|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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=Honda Civic Hatchback 2017-18">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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=Honda Civic Hatchback 2019-21">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch 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=Honda Civic Hatchback 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic Hatchback Hybrid 2025|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 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=Honda Civic Hatchback Hybrid 2025">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 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=Honda Civic Hatchback Hybrid (Europe only) 2023">Buy Here</a></sub></details>|||
|Honda|Civic Hybrid 2025|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 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=Honda Civic Hybrid 2025">Buy Here</a></sub></details>|||
|Honda|Clarity 2018-21|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector + Honda Clarity Proxy Board<br>- 1 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://shop.retropilot.org/product/honda-clarity-proxy-board-kit">Buy Here</a></sub></details>|||
|Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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=Honda CR-V 2015-16">Buy Here</a></sub></details>|||
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|15 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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=Honda CR-V 2017-22">Buy Here</a></sub></details>|||
|Honda|CR-V 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 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=Honda CR-V 2023-25">Buy Here</a></sub></details>|||
|Honda|CR-V Hybrid 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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=Honda CR-V Hybrid 2017-22">Buy Here</a></sub></details>|||
|Honda|CR-V Hybrid 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 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=Honda CR-V Hybrid 2023-25">Buy Here</a></sub></details>|||
|Honda|e 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 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=Honda e 2020">Buy Here</a></sub></details>|||
|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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=Honda Fit 2018-20">Buy Here</a></sub></details>|||
|Honda|Freed 2020|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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=Honda Freed 2020">Buy Here</a></sub></details>|||
@@ -94,6 +102,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec 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=Honda Odyssey 2018-20">Buy Here</a></sub></details>|||
|Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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=Honda Passport 2019-25">Buy Here</a></sub></details>|||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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=Honda Pilot 2016-22">Buy Here</a></sub></details>|||
|Honda|Pilot 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2023-25">Buy Here</a></sub></details>|||
|Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 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=Honda Ridgeline 2017-25">Buy Here</a></sub></details>|||
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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=Hyundai Azera 2022">Buy Here</a></sub></details>|||
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 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=Hyundai Azera Hybrid 2019">Buy Here</a></sub></details>|||
@@ -104,6 +113,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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=Hyundai Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 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=Hyundai Elantra GT 2017-20">Buy Here</a></sub></details>|||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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=Hyundai Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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=Hyundai Elantra Non-SCC 2022">Buy Here</a></sub></details>|||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 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=Hyundai Genesis 2015-16">Buy Here</a></sub></details>|||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 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=Hyundai i30 2017-19">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 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=Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>|||
@@ -117,10 +127,13 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C 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=Hyundai Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>|||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 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=Hyundai Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai 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=Hyundai Kona 2020">Buy Here</a></sub></details>|||
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 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=Hyundai Kona 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 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=Hyundai Kona Electric 2018-21">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 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=Hyundai Kona Electric 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 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=Hyundai Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 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=Hyundai Kona Electric Non-SCC 2019">Buy Here</a></sub></details>|||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 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=Hyundai Kona Hybrid 2020">Buy Here</a></sub></details>|||
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 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=Hyundai Kona Non-SCC 2019">Buy Here</a></sub></details>|||
|Hyundai|Nexo 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 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=Hyundai Nexo 2021">Buy Here</a></sub></details>|||
|Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 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=Hyundai Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Santa Cruz 2022-24[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 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=Hyundai Santa Cruz 2022-24">Buy Here</a></sub></details>|||
@@ -144,6 +157,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Carnival 2022-24[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 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=Kia Carnival 2022-24">Buy Here</a></sub></details>|||
|Kia|Carnival (China only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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=Kia Carnival (China only) 2023">Buy Here</a></sub></details>|||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 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=Kia Ceed 2019-21">Buy Here</a></sub></details>|||
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 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=Kia Ceed Plug-in Hybrid Non-SCC 2022">Buy Here</a></sub></details>|||
|Kia|EV6 (Southeast Asia only) 2022-24[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 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=Kia EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>|||
|Kia|EV6 (with HDA II) 2022-24[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 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=Kia EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|Kia|EV6 (without HDA II) 2022-24[<sup>6</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 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=Kia EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
@@ -179,7 +193,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Sportage Hybrid 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 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=Kia Sportage Hybrid 2023">Buy Here</a></sub></details>|||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C 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=Kia Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Kia|Stinger 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 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=Kia Stinger 2022-23">Buy Here</a></sub></details>|||
|Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 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=Kia Telluride 2020-22">Buy Here</a></sub></details>|||
|Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Telluride 2020-22">Buy Here</a></sub></details>|||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 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=Lexus CT Hybrid 2017-18">Buy Here</a></sub></details>|||
|Lexus|ES 2017-18|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=Lexus ES 2017-18">Buy Here</a></sub></details>|||
|Lexus|ES 2019-25|All|openpilot|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=Lexus ES 2019-25">Buy Here</a></sub></details>|||
@@ -212,7 +226,9 @@ A supported vehicle is one that just works when you install a comma device. All
|Nissan[<sup>7</sup>](#footnotes)|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<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=Nissan Leaf 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/vaMbtAh_0cY" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Nissan[<sup>7</sup>](#footnotes)|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<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=Nissan Rogue 2018-20">Buy Here</a></sub></details>|||
|Nissan[<sup>7</sup>](#footnotes)|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 comma power v3<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=Nissan X-Trail 2017">Buy Here</a></sub></details>|||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ram 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=Ram 1500 2019-24">Buy Here</a></sub></details>|||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|32 mph|1 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ram 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=Ram 1500 2019-24">Buy Here</a></sub></details>|||
|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|Stock|0 mph|36 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ram 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=Ram 2500 2020-24">Buy Here</a></sub></details>|||
|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|36 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ram 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=Ram 3500 2019-22">Buy Here</a></sub></details>|||
|Rivian|R1S 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 R1S 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>|
|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>|||
@@ -220,10 +236,14 @@ A supported vehicle is one that just works when you install a comma device. All
|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|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 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>|||
@@ -285,6 +305,7 @@ 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>||

View File

@@ -6,7 +6,7 @@ Development is coordinated through [Discord](https://discord.comma.ai) and GitHu
### Getting Started
* Setup your [development environment](../tools/)
* Set up your [development environment](/tools/)
* Join our [Discord](https://discord.comma.ai)
* Docs are at https://docs.comma.ai and https://blog.comma.ai
@@ -39,7 +39,7 @@ All of these are examples of good PRs:
### First contribution
[Projects / openpilot bounties](https://github.com/orgs/commaai/projects/26/views/1?pane=info) is the best place to get started and goes in-depth on what's expected when working on a bounty.
There's lot of bounties that don't require a comma 3/3X or a car.
There's lot of bounties that don't require a comma 3X or a car.
## Pull Requests

30
docs/DEBUGGING_SAFETY.md Normal file
View File

@@ -0,0 +1,30 @@
# Debugging Panda Safety with Replay Drive + LLDB
## 1. Start the debugger in VS Code
* Select **Replay drive + Safety LLDB**.
* Enter the route or segment when prompted.
[<img src="https://github.com/user-attachments/assets/b0cc320a-083e-46a7-a9f8-ca775bbe5604">](https://github.com/user-attachments/assets/b0cc320a-083e-46a7-a9f8-ca775bbe5604)
## 2. Attach LLDB
* When prompted, pick the running **`replay_drive` process**.
* ⚠️ Attach quickly, or `replay_drive` will start consuming messages.
> [!TIP]
> Add a Python breakpoint at the start of `replay_drive.py` to pause execution and give yourself time to attach LLDB.
## 3. Set breakpoints in VS Code
Breakpoints can be set directly in `modes/xxx.h` (or any C file).
No extra LLDB commands are required — just place breakpoints in the editor.
## 4. Resume execution
Once attached, you can step through both Python (on the replay) and C safety code as CAN logs are replayed.
> [!NOTE]
> * Use short routes for quicker iteration.
> * Pause `replay_drive` early to avoid wasting log messages.
## Video
View a demo of this workflow on the PR that added it: https://github.com/commaai/openpilot/pull/36055#issue-3352911578

View File

@@ -16,7 +16,7 @@ industry standards of safety for Level 2 Driver Assistance Systems. In particula
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.
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.
@@ -29,8 +29,18 @@ ensuring two main safety requirements.
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 [opendbc/safety/safety](https://github.com/commaai/opendbc/tree/master/opendbc/safety/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.
[^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.
---
### Forks of openpilot
* Do not disable or nerf [driver monitoring](https://github.com/commaai/openpilot/tree/master/selfdrive/monitoring)
* Do not disable or nerf [excessive actuation checks](https://github.com/commaai/openpilot/tree/master/selfdrive/selfdrived/helpers.py)
* If your fork modifies any of the code in `opendbc/safety/`:
* your fork cannot use the openpilot trademark
* your fork must preserve the full [safety test suite](https://github.com/commaai/opendbc/tree/master/opendbc/safety/tests) and all tests must pass, including any new coverage required by the fork's changes
Failure to comply with these standards will get you and your users banned from comma.ai servers.
**comma.ai strongly discourages the use of openpilot forks with safety code either missing or not fully meeting the above requirements.**

View File

@@ -1,11 +1,11 @@
# connect to a comma 3/3X
# connect to a comma 3X
A comma 3/3X is a normal [Linux](https://github.com/commaai/agnos-builder) computer that exposes [SSH](https://wiki.archlinux.org/title/Secure_Shell) and a [serial console](https://wiki.archlinux.org/title/Working_with_the_serial_console).
A comma 3X is a normal [Linux](https://github.com/commaai/agnos-builder) computer that exposes [SSH](https://wiki.archlinux.org/title/Secure_Shell) and a [serial console](https://wiki.archlinux.org/title/Working_with_the_serial_console).
## Serial Console
On both the comma three and 3X, the serial console is accessible from the main OBD-C port.
Connect the comma 3/3X to your computer with a normal USB C cable, or use a [comma serial](https://comma.ai/shop/comma-serial) for steady 12V power.
Connect the comma 3X to your computer with a normal USB C cable, or use a [comma serial](https://comma.ai/shop/comma-serial) for steady 12V power.
On the comma three, the serial console is exposed through a UART-to-USB chip, and `tools/scripts/serial.sh` can be used to connect.
@@ -45,7 +45,7 @@ In order to use ADB on your device, you'll need to perform the following steps u
* Here's an example command for connecting to your device using its tethered connection: `adb connect 192.168.43.1:5555`
> [!NOTE]
> The default port for ADB is 5555 on the comma 3/3X.
> The default port for ADB is 5555 on the comma 3X.
For more info on ADB, see the [Android Debug Bridge (ADB) documentation](https://developer.android.com/tools/adb).

View File

@@ -8,7 +8,7 @@ Replaying is a critical tool for openpilot development and debugging.
Just run `tools/replay/replay --demo`.
## Replaying CAN data
*Hardware required: jungle and comma 3/3X*
*Hardware required: jungle and comma 3X*
1. Connect your PC to a jungle.
2.

View File

@@ -1,11 +1,11 @@
# Turn the speed blue
*A getting started guide for openpilot development*
In 30 minutes, we'll get an openpilot development environment setup on your computer and make some changes to openpilot's UI.
In 30 minutes, we'll get an openpilot development environment set up on your computer and make some changes to openpilot's UI.
And if you have a comma 3/3X, we'll deploy the change to your device for testing.
And if you have a comma 3X, we'll deploy the change to your device for testing.
## 1. Setup your development environment
## 1. Set up your development environment
Run this to clone openpilot and install all the dependencies:
```bash

View File

@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
export VECLIB_MAXIMUM_THREADS=1
if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="12.4"
export AGNOS_VERSION="13.1"
fi
export STAGING_ROOT="/data/safe_staging"

View File

@@ -1,3 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# On any failure, run the fallback launcher
trap 'exec ./launch_chffrplus.sh' ERR
C3_LAUNCH_SH="./sunnypilot/system/hardware/c3/launch_chffrplus.sh"
MODEL="$(tr -d '\0' < "/sys/firmware/devicetree/base/model")"
export MODEL
if [ "$MODEL" = "comma tici" ]; then
# Force a failure if the launcher doesn't exist
[ -x "$C3_LAUNCH_SH" ] || false
# If it exists, run it
exec "$C3_LAUNCH_SH"
fi
exec ./launch_chffrplus.sh

View File

@@ -21,7 +21,7 @@ nav:
- What is openpilot?: getting-started/what-is-openpilot.md
- How-to:
- Turn the speed blue: how-to/turn-the-speed-blue.md
- Connect to a comma 3/3X: how-to/connect-to-comma.md
- Connect to a comma 3X: how-to/connect-to-comma.md
# - Make your first pull request: how-to/make-first-pr.md
#- Replay a drive: how-to/replay-a-drive.md
- Concepts:

2
panda

Submodule panda updated: e46680ff6f...69ab12ee2a

View File

@@ -36,6 +36,9 @@ dependencies = [
"pyopenssl < 24.3.0",
"pyaudio",
# ubloxd (TODO: just use struct)
"kaitaistruct",
# panda
"libusb1",
"spidev; platform_system == 'Linux'",
@@ -101,8 +104,9 @@ dev = [
"av",
"azure-identity",
"azure-storage-blob",
"dbus-next",
"dbus-next", # TODO: remove once we moved everything to jeepney
"dictdiffer",
"jeepney",
"matplotlib",
"opencv-python-headless",
"parameterized >=0.8, <0.9",
@@ -120,7 +124,7 @@ dev = [
tools = [
"metadrive-simulator @ https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl ; (platform_machine != 'aarch64')",
#"rerun-sdk >= 0.18", # this is pretty big, so only enable once we use it
"dearpygui>=2.1.0",
]
[project.urls]
@@ -152,12 +156,12 @@ markers = [
testpaths = [
"common",
"selfdrive",
"system/manager",
"system/updated",
"system/athena",
"system/camerad",
"system/hardware",
"system/loggerd",
"system/proclogd",
"system/tests",
"system/ubloxd",
"system/webrtc",
@@ -173,7 +177,7 @@ quiet-level = 3
# if you've got a short variable name that's getting flagged, add it here
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite"
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*"
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*, tools/plotjuggler/layouts/*"
[tool.mypy]
python_version = "3.11"
@@ -247,6 +251,7 @@ exclude = [
"teleoprtc_repo",
"third_party",
"*.ipynb",
"generated",
]
lint.flake8-implicit-str-concat.allow-multiline = false

View File

@@ -3,29 +3,34 @@
```
## release checklist
**Go to `devel-staging`**
### Go to staging
- [ ] make a GitHub issue to track release
- [ ] create release master branch
- [ ] update RELEASES.md
- [ ] update `devel-staging`: `git reset --hard origin/master-ci`
- [ ] open a pull request from `devel-staging` to `devel`
- [ ] post on Discord
**Go to `devel`**
- [ ] bump version on master: `common/version.h` and `RELEASES.md`
- [ ] before merging the pull request
- [ ] build new userdata partition from `release3-staging`
- [ ] post on Discord, tag `@release crew`
Updating staging:
1. either rebase on master or cherry-pick changes
2. run this to update: `BRANCH=devel-staging release/build_devel.sh`
3. build new userdata partition from `release3-staging`
### Go to release
- [ ] before going to release, test the following:
- [ ] update from previous release -> new release
- [ ] update from new release -> previous release
- [ ] fresh install with `openpilot-test.comma.ai`
- [ ] drive on fresh install
- [ ] no submodules or LFS
- [ ] check sentry, MTBF, etc.
**Go to `release3`**
- [ ] stress test passes in production
- [ ] publish the blog post
- [ ] `git reset --hard origin/release3-staging`
- [ ] tag the release: `git tag v0.X.X <commit-hash> && git push origin v0.X.X`
- [ ] create GitHub release
- [ ] final test install on `openpilot.comma.ai`
- [ ] update factory provisioning
- [ ] close out milestone
- [ ] close out milestone and issue
- [ ] post on Discord, X, etc.
```

View File

@@ -17,28 +17,23 @@ rm -rf $TARGET_DIR
mkdir -p $TARGET_DIR
cd $TARGET_DIR
cp -r $SOURCE_DIR/.git $TARGET_DIR
pre-commit uninstall || true
echo "[-] bringing __nightly and devel in sync T=$SECONDS"
echo "[-] setting up stripped branch sync T=$SECONDS"
cd $TARGET_DIR
git fetch --depth 1 origin __nightly
git fetch --depth 1 origin devel
git checkout -f --track origin/__nightly
git reset --hard __nightly
git checkout __nightly
git reset --hard origin/devel
git clean -xdff
git lfs uninstall
# tmp branch
git checkout --orphan tmp
# remove everything except .git
echo "[-] erasing old sunnypilot T=$SECONDS"
git submodule deinit -f --all
git rm -rf --cached .
find . -maxdepth 1 -not -path './.git' -not -name '.' -not -name '..' -exec rm -rf '{}' \;
# reset source tree
# cleanup before the copy
cd $SOURCE_DIR
git clean -xdff
git submodule foreach --recursive git clean -xdff
# do the files copy
echo "[-] copying files T=$SECONDS"
@@ -47,6 +42,7 @@ cp -pR --parents $(./release/release_files.py) $TARGET_DIR/
# in the directory
cd $TARGET_DIR
rm -rf .git/modules/
rm -f panda/board/obj/panda.bin.signed
# include source commit hash and build date in commit
@@ -85,7 +81,7 @@ fi
if [ ! -z "$BRANCH" ]; then
echo "[-] Pushing to $BRANCH T=$SECONDS"
git push -f origin __nightly:$BRANCH
git push -f origin tmp:$BRANCH
fi
echo "[-] done T=$SECONDS, ready at $TARGET_DIR"

View File

@@ -51,26 +51,19 @@ git fetch origin $DEV_BRANCH || (git checkout -b $DEV_BRANCH && git commit --all
echo "[-] committing version $VERSION T=$SECONDS"
git add -f .
git commit -a -m "sunnypilot v$VERSION release"
git branch --set-upstream-to=origin/$DEV_BRANCH
# 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=$(cat $SOURCE_DIR/common/version.h | awk -F\" '{print $2}')
SP_VERSION=$(awk -F\" '{print $2}' $SOURCE_DIR/common/version.h)
# Add built files to git
git add -f .
if [ "$EXTRA_VERSION_IDENTIFIER" = "-release" ] || [ "$EXTRA_VERSION_IDENTIFIER" = "-staging" ]; then
export VERSION=${VERSION%"$EXTRA_VERSION_IDENTIFIER"}
git commit --amend -m "sunnypilot v$VERSION"
else
git commit --amend -m "sunnypilot v$VERSION
version: sunnypilot v$SP_VERSION release
date: $DATETIME
master commit: $GIT_HASH
"
fi
# Commit with detailed message
git commit -a -m "sunnypilot v$VERSION
version: sunnypilot v$SP_VERSION (${EXTRA_VERSION_IDENTIFIER})
date: $DATETIME
master commit: $GIT_HASH
"
git branch --set-upstream-to=origin/$DEV_BRANCH
git branch -m $DEV_BRANCH
# Push!

View File

@@ -14,7 +14,7 @@ def setup_argument_parser():
parser.add_argument('--pr-data', type=str, help='PR data in JSON format')
parser.add_argument('--source-branch', type=str, default='master',
help='Source branch for merging')
parser.add_argument('--target-branch', type=str, default='master-dev-c3-new-test',
parser.add_argument('--target-branch', type=str, default='master-dev-test',
help='Target branch for merging')
parser.add_argument('--squash-script-path', type=str, required=True,
help='Path to the squash_and_merge.py script')

BIN
selfdrive/assets/icons/link.png LFS Normal file

Binary file not shown.

View File

@@ -57,7 +57,7 @@ class CarSpecificEvents:
events.add(EventName.belowSteerSpeed)
elif self.CP.brand == 'honda':
events = self.create_common_events(CS, CS_prev, pcm_enable=False)
events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.sport], pcm_enable=False)
if self.CP.pcmCruise and CS.vEgo < self.CP.minEnableSpeed:
events.add(EventName.belowEngageSpeed)

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env python3
import json
import os
import time
import threading
@@ -107,9 +106,11 @@ class Car:
with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
cached_params = _cached_params
fixed_fingerprint = json.loads(self.params.get("CarPlatformBundle") or "{}").get("platform", None)
fixed_fingerprint = (self.params.get("CarPlatformBundle") or {}).get("platform", None)
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)
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)
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
@@ -178,7 +179,7 @@ class Car:
self.params.put_nonblocking("CarParamsSPPersistent", cp_sp_bytes)
self.mock_carstate = MockCarState()
self.v_cruise_helper = VCruiseHelper(self.CP)
self.v_cruise_helper = VCruiseHelper(self.CP, self.CP_SP)
self.is_metric = self.params.get_bool("IsMetric")
self.experimental_mode = self.params.get_bool("ExperimentalMode")

View File

@@ -2,7 +2,7 @@ import math
import numpy as np
from cereal import car
from openpilot.common.conversions import Conversions as CV
from openpilot.common.constants import CV
from openpilot.sunnypilot.selfdrive.car.cruise_ext import VCruiseHelperSP
@@ -30,8 +30,8 @@ CRUISE_INTERVAL_SIGN = {
class VCruiseHelper(VCruiseHelperSP):
def __init__(self, CP):
VCruiseHelperSP.__init__(self)
def __init__(self, CP, CP_SP):
VCruiseHelperSP.__init__(self, CP, CP_SP)
self.CP = CP
self.v_cruise_kph = V_CRUISE_UNSET
self.v_cruise_cluster_kph = V_CRUISE_UNSET
@@ -46,10 +46,13 @@ class VCruiseHelper(VCruiseHelperSP):
def update_v_cruise(self, CS, enabled, is_metric):
self.v_cruise_kph_last = self.v_cruise_kph
self.get_minimum_set_speed(is_metric)
if CS.cruiseState.available:
if not self.CP.pcmCruise:
_enabled = self.update_enabled_state(CS, enabled)
if not self.CP.pcmCruise or (not self.CP_SP.pcmCruiseSpeed and _enabled):
# if stock cruise is completely disabled, then we can use our own set speed logic
self._update_v_cruise_non_pcm(CS, enabled, is_metric)
self._update_v_cruise_non_pcm(CS, _enabled, is_metric)
self.v_cruise_cluster_kph = self.v_cruise_kph
self.update_button_timers(CS, enabled)
else:
@@ -111,7 +114,7 @@ class VCruiseHelper(VCruiseHelperSP):
if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise):
self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH)
self.v_cruise_kph = np.clip(round(self.v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX)
self.v_cruise_kph = np.clip(round(self.v_cruise_kph, 1), self.v_cruise_min, V_CRUISE_MAX)
def update_button_timers(self, CS, enabled):
# increment timer for buttons still pressed

View File

@@ -60,5 +60,8 @@ def convert_carControlSP(struct: capnp.lib.capnp._DynamicStructReader) -> struct
struct_dataclass.params = [structs.CarControlSP.Param(**remove_deprecated(p)) for p in struct_dict.get('params', [])]
struct_dataclass.leadOne = structs.LeadData(**remove_deprecated(struct_dict.get('leadOne', {})))
struct_dataclass.leadTwo = structs.LeadData(**remove_deprecated(struct_dict.get('leadTwo', {})))
struct_dataclass.intelligentCruiseButtonManagement = structs.IntelligentCruiseButtonManagement(
**remove_deprecated(struct_dict.get('intelligentCruiseButtonManagement', {}))
)
return struct_dataclass

View File

@@ -1,15 +1,12 @@
import os
import math
import hypothesis.strategies as st
from hypothesis import Phase, given, settings
from parameterized import parameterized
from cereal import car, custom
from opendbc.car import DT_CTRL
from opendbc.car.car_helpers import interfaces
from opendbc.car.structs import CarParams
from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface_args
from opendbc.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface
from opendbc.car.mock.values import CAR as MOCK
from opendbc.car.values import PLATFORMS
from openpilot.selfdrive.car.helpers import convert_carControlSP
@@ -21,11 +18,6 @@ from openpilot.selfdrive.test.fuzzy_generation import FuzzyGenerator
from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces
ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()}
ALL_ECUS |= {ecu for config in FW_QUERY_CONFIGS.values() for ecu in config.extra_ecus}
ALL_REQUESTS = {tuple(r.request) for config in FW_QUERY_CONFIGS.values() for r in config.requests}
MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '60'))
@@ -37,43 +29,10 @@ class TestCarInterfaces:
phases=(Phase.reuse, Phase.generate, Phase.shrink))
@given(data=st.data())
def test_car_interfaces(self, car_name, data):
CarInterface = interfaces[car_name]
args = get_fuzzy_car_interface_args(data.draw)
car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
alpha_long=args['alpha_long'], is_release=False, docs=False)
car_params_sp = CarInterface.get_params_sp(car_params, car_name, args['fingerprints'], args['car_fw'],
alpha_long=args['alpha_long'], docs=False)
car_params = car_params.as_reader()
car_interface = CarInterface(car_params, car_params_sp)
car_interface = get_fuzzy_car_interface(car_name, data.draw)
car_params = car_interface.CP.as_reader()
car_params_sp = car_interface.CP_SP
sunnypilot_interfaces.setup_interfaces(car_interface)
assert car_params
assert car_params_sp
assert car_interface
assert car_params.mass > 1
assert car_params.wheelbase > 0
# centerToFront is center of gravity to front wheels, assert a reasonable range
assert car_params.wheelbase * 0.3 < car_params.centerToFront < car_params.wheelbase * 0.7
assert car_params.maxLateralAccel > 0
# Longitudinal sanity checks
assert len(car_params.longitudinalTuning.kpV) == len(car_params.longitudinalTuning.kpBP)
assert len(car_params.longitudinalTuning.kiV) == len(car_params.longitudinalTuning.kiBP)
# Lateral sanity checks
if car_params.steerControlType != CarParams.SteerControlType.angle:
tune = car_params.lateralTuning
if tune.which() == 'pid':
if car_name != MOCK.MOCK:
assert not math.isnan(tune.pid.kf) and tune.pid.kf > 0
assert len(tune.pid.kpV) > 0 and len(tune.pid.kpV) == len(tune.pid.kpBP)
assert len(tune.pid.kiV) > 0 and len(tune.pid.kiV) == len(tune.pid.kiBP)
elif tune.which() == 'torque':
assert not math.isnan(tune.torque.kf) and tune.torque.kf > 0
assert not math.isnan(tune.torque.friction) and tune.torque.friction > 0
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
cc_sp_msg = FuzzyGenerator.get_random_msg(data.draw, custom.CarControlSP, real_floats=True)

View File

@@ -5,8 +5,8 @@ import numpy as np
from parameterized import parameterized_class
from cereal import log
from openpilot.selfdrive.car.cruise import VCruiseHelper, V_CRUISE_MIN, V_CRUISE_MAX, V_CRUISE_INITIAL, IMPERIAL_INCREMENT
from cereal import car
from openpilot.common.conversions import Conversions as CV
from cereal import car, custom
from openpilot.common.constants import CV
from openpilot.selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver
ButtonEvent = car.CarState.ButtonEvent
@@ -49,7 +49,8 @@ class TestCruiseSpeed:
class TestVCruiseHelper:
def setup_method(self):
self.CP = car.CarParams(pcmCruise=self.pcm_cruise)
self.v_cruise_helper = VCruiseHelper(self.CP)
self.CP_SP = custom.CarParamsSP()
self.v_cruise_helper = VCruiseHelper(self.CP, self.CP_SP)
self.reset_cruise_speed_state()
def reset_cruise_speed_state(self):

View File

@@ -2,11 +2,11 @@
import math
import threading
import time
from typing import SupportsFloat
from numbers import Number
from cereal import car, log
import cereal.messaging as messaging
from openpilot.common.conversions import Conversions as CV
from openpilot.common.constants import CV
from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper
from openpilot.common.swaglog import cloudlog
@@ -21,6 +21,8 @@ from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
from openpilot.sunnypilot.modeld.modeld_base import ModelStateBase
from openpilot.sunnypilot.selfdrive.controls.controlsd_ext import ControlsExt
State = log.SelfdriveState.OpenpilotState
@@ -30,15 +32,16 @@ LaneChangeDirection = log.LaneChangeDirection
ACTUATOR_FIELDS = tuple(car.CarControl.Actuators.schema.fields.keys())
class Controls(ControlsExt):
class Controls(ControlsExt, ModelStateBase):
def __init__(self) -> None:
self.params = Params()
cloudlog.info("controlsd is waiting for CarParams")
self.CP = messaging.log_from_bytes(self.params.get("CarParams", block=True), car.CarParams)
cloudlog.info("controlsd got CarParams")
# Initialize sunnypilot controlsd extension
# Initialize sunnypilot controlsd extension and base model state
ControlsExt.__init__(self, self.CP, self.params)
ModelStateBase.__init__(self)
self.CI = interfaces[self.CP.carFingerprint](self.CP, self.CP_SP)
@@ -48,7 +51,7 @@ class Controls(ControlsExt):
poll='selfdriveState')
self.pm = messaging.PubMaster(['carControl', 'controlsState'] + self.pm_services_ext)
self.steer_limited_by_controls = False
self.steer_limited_by_safety = False
self.curvature = 0.0
self.desired_curvature = 0.0
@@ -92,9 +95,12 @@ class Controls(ControlsExt):
self.LaC.update_live_torque_params(torque_params.latAccelFactorFiltered, torque_params.latAccelOffsetFiltered,
torque_params.frictionCoefficientFiltered)
self.LaC.extension.update_limits()
self.LaC.extension.update_model_v2(self.sm['modelV2'])
calculated_lag = self.LaC.extension.lagd_torqued_main(self.CP, self.sm['liveDelay'])
self.LaC.extension.update_lateral_lag(calculated_lag)
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']
model_v2 = self.sm['modelV2']
@@ -110,7 +116,8 @@ class Controls(ControlsExt):
CC.latActive = _lat_active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
(not standstill or self.CP.steerAtStandstill)
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and self.CP.openpilotLongitudinalControl
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and \
(self.CP.openpilotLongitudinalControl or not self.CP_SP.pcmCruiseSpeed)
actuators = CC.actuators
actuators.longControlState = self.LoC.long_control_state
@@ -136,14 +143,14 @@ class Controls(ControlsExt):
actuators.curvature = self.desired_curvature
steer, steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp,
self.steer_limited_by_controls, self.desired_curvature,
self.steer_limited_by_safety, self.desired_curvature,
self.calibrated_pose, curvature_limited) # TODO what if not available
actuators.torque = float(steer)
actuators.steeringAngleDeg = float(steeringAngleDeg)
# Ensure no NaNs/Infs
for p in ACTUATOR_FIELDS:
attr = getattr(actuators, p)
if not isinstance(attr, SupportsFloat):
if not isinstance(attr, Number):
continue
if not math.isfinite(attr):
@@ -162,7 +169,7 @@ class Controls(ControlsExt):
CC.orientationNED = self.calibrated_pose.orientation.xyz.tolist()
CC.angularVelocity = self.calibrated_pose.angular_velocity.xyz.tolist()
CC.cruiseControl.override = CC.enabled and not CC.longActive and self.CP.openpilotLongitudinalControl
CC.cruiseControl.override = CC.enabled and not CC.longActive and (self.CP.openpilotLongitudinalControl or not self.CP_SP.pcmCruiseSpeed)
CC.cruiseControl.cancel = CS.cruiseState.enabled and (not CC.enabled or not self.CP.pcmCruise)
CC.cruiseControl.resume = CC.enabled and CS.cruiseState.standstill and not self.sm['longitudinalPlan'].shouldStop
@@ -183,10 +190,10 @@ class Controls(ControlsExt):
if self.sm['selfdriveState'].active:
CO = self.sm['carOutput']
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
self.steer_limited_by_controls = abs(CC.actuators.steeringAngleDeg - CO.actuatorsOutput.steeringAngleDeg) > \
self.steer_limited_by_safety = abs(CC.actuators.steeringAngleDeg - CO.actuatorsOutput.steeringAngleDeg) > \
STEER_ANGLE_SATURATION_THRESHOLD
else:
self.steer_limited_by_controls = abs(CC.actuators.torque - CO.actuatorsOutput.torque) > 1e-2
self.steer_limited_by_safety = abs(CC.actuators.torque - CO.actuatorsOutput.torque) > 1e-2
# TODO: both controlsState and carControl valids should be set by
# sm.all_checks(), but this creates a circular dependency

View File

@@ -1,7 +1,8 @@
from cereal import log
from openpilot.common.conversions import Conversions as CV
from cereal import log, custom
from openpilot.common.constants import CV
from openpilot.common.realtime import DT_MDL
from openpilot.sunnypilot.selfdrive.controls.lib.auto_lane_change import AutoLaneChangeController, AutoLaneChangeMode
from openpilot.sunnypilot.selfdrive.controls.lib.lane_turn_desire import LaneTurnController
LaneChangeState = log.LaneChangeState
LaneChangeDirection = log.LaneChangeDirection
@@ -30,6 +31,12 @@ DESIRES = {
},
}
TURN_DESIRES = {
custom.TurnDirection.none: log.Desire.none,
custom.TurnDirection.turnLeft: log.Desire.turnLeft,
custom.TurnDirection.turnRight: log.Desire.turnRight,
}
class DesireHelper:
def __init__(self):
@@ -41,13 +48,25 @@ class DesireHelper:
self.prev_one_blinker = False
self.desire = log.Desire.none
self.alc = AutoLaneChangeController(self)
self.lane_turn_controller = LaneTurnController(self)
self.lane_turn_direction = custom.TurnDirection.none
@staticmethod
def get_lane_change_direction(CS):
return LaneChangeDirection.left if CS.leftBlinker else LaneChangeDirection.right
def update(self, carstate, lateral_active, lane_change_prob):
self.alc.update_params()
self.lane_turn_controller.update_params()
v_ego = carstate.vEgo
one_blinker = carstate.leftBlinker != carstate.rightBlinker
below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN
# Lane turn controller update
self.lane_turn_controller.update_lane_turn(blindspot_left=carstate.leftBlindspot, blindspot_right=carstate.rightBlindspot,
left_blinker=carstate.leftBlinker, right_blinker=carstate.rightBlinker, v_ego=v_ego)
self.lane_turn_direction = self.lane_turn_controller.get_turn_direction()
if not lateral_active or self.lane_change_timer > LANE_CHANGE_TIME_MAX or self.alc.lane_change_set_timer == AutoLaneChangeMode.OFF:
self.lane_change_state = LaneChangeState.off
self.lane_change_direction = LaneChangeDirection.none
@@ -56,12 +75,13 @@ class DesireHelper:
if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed:
self.lane_change_state = LaneChangeState.preLaneChange
self.lane_change_ll_prob = 1.0
# Initialize lane change direction to prevent UI alert flicker
self.lane_change_direction = self.get_lane_change_direction(carstate)
# LaneChangeState.preLaneChange
elif self.lane_change_state == LaneChangeState.preLaneChange:
# Set lane change direction
self.lane_change_direction = LaneChangeDirection.left if \
carstate.leftBlinker else LaneChangeDirection.right
# Update lane change direction
self.lane_change_direction = self.get_lane_change_direction(carstate)
torque_applied = carstate.steeringPressed and \
((carstate.steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or
@@ -106,7 +126,10 @@ class DesireHelper:
self.prev_one_blinker = one_blinker
self.desire = DESIRES[self.lane_change_direction][self.lane_change_state]
if self.lane_turn_direction != custom.TurnDirection.none:
self.desire = TURN_DESIRES[self.lane_turn_direction]
else:
self.desire = DESIRES[self.lane_change_direction][self.lane_change_state]
# Send keep pulse once per second during LaneChangeStart.preLaneChange
if self.lane_change_state in (LaneChangeState.off, LaneChangeState.laneChangeStarting):

View File

@@ -1,5 +1,5 @@
import numpy as np
from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
from openpilot.common.constants import ACCELERATION_DUE_TO_GRAVITY
from openpilot.common.realtime import DT_CTRL, DT_MDL
MIN_SPEED = 1.0

View File

@@ -15,15 +15,15 @@ class LatControl(ABC):
self.steer_max = 1.0
@abstractmethod
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
pass
def reset(self):
self.sat_count = 0.
def _check_saturation(self, saturated, CS, steer_limited_by_controls, curvature_limited):
def _check_saturation(self, saturated, CS, steer_limited_by_safety, curvature_limited):
# Saturated only if control output is not being limited by car torque/angle rate limits
if (saturated or curvature_limited) and CS.vEgo > self.sat_check_min_speed and not steer_limited_by_controls and not CS.steeringPressed:
if (saturated or curvature_limited) and CS.vEgo > self.sat_check_min_speed and not steer_limited_by_safety and not CS.steeringPressed:
self.sat_count += self.sat_count_rate
else:
self.sat_count -= self.sat_count_rate

View File

@@ -3,6 +3,7 @@ import math
from cereal import log
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
# TODO This is speed dependent
STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees
@@ -10,9 +11,9 @@ class LatControlAngle(LatControl):
def __init__(self, CP, CP_SP, CI):
super().__init__(CP, CP_SP, CI)
self.sat_check_min_speed = 5.
self.use_steer_limited_by_controls = CP.brand == "tesla"
self.use_steer_limited_by_safety = CP.brand == "tesla"
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
angle_log = log.ControlsState.LateralAngleState.new_message()
if not active:
@@ -23,9 +24,9 @@ class LatControlAngle(LatControl):
angle_steers_des = math.degrees(VM.get_steer_from_curvature(-desired_curvature, CS.vEgo, params.roll))
angle_steers_des += params.angleOffsetDeg
if self.use_steer_limited_by_controls:
if self.use_steer_limited_by_safety:
# these cars' carcontrollers calculate max lateral accel and jerk, so we can rely on carOutput for saturation
angle_control_saturated = steer_limited_by_controls
angle_control_saturated = steer_limited_by_safety
else:
# for cars which use a method of limiting torque such as a torque signal (Nissan and Toyota)
# or relying on EPS (Ford Q3), carOutput does not capture maxing out torque # TODO: this can be improved

View File

@@ -13,11 +13,7 @@ class LatControlPID(LatControl):
k_f=CP.lateralTuning.pid.kf, pos_limit=self.steer_max, neg_limit=-self.steer_max)
self.get_steer_feedforward = CI.get_steer_feedforward_function()
def reset(self):
super().reset()
self.pid.reset()
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
pid_log = log.ControlsState.LateralPIDState.new_message()
pid_log.steeringAngleDeg = float(CS.steeringAngleDeg)
pid_log.steeringRateDeg = float(CS.steeringRateDeg)
@@ -29,20 +25,24 @@ class LatControlPID(LatControl):
pid_log.steeringAngleDesiredDeg = angle_steers_des
pid_log.angleError = error
if not active:
output_steer = 0.0
output_torque = 0.0
pid_log.active = False
self.pid.reset()
else:
# offset does not contribute to resistive torque
steer_feedforward = self.get_steer_feedforward(angle_steers_des_no_offset, CS.vEgo)
ff = self.get_steer_feedforward(angle_steers_des_no_offset, CS.vEgo)
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
output_torque = self.pid.update(error,
feedforward=ff,
speed=CS.vEgo,
freeze_integrator=freeze_integrator)
output_steer = self.pid.update(error, override=CS.steeringPressed,
feedforward=steer_feedforward, speed=CS.vEgo)
pid_log.active = True
pid_log.p = float(self.pid.p)
pid_log.i = float(self.pid.i)
pid_log.f = float(self.pid.f)
pid_log.output = float(output_steer)
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_steer) < 1e-3, CS, steer_limited_by_controls, curvature_limited))
pid_log.output = float(output_torque)
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited))
return output_steer, angle_steers_des, pid_log
return output_torque, angle_steers_des, pid_log

View File

@@ -2,9 +2,8 @@ import math
import numpy as np
from cereal import log
from opendbc.car import FRICTION_THRESHOLD, get_friction
from opendbc.car.interfaces import LatControlInputs
from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
from opendbc.car.lateral import FRICTION_THRESHOLD, get_friction
from openpilot.common.constants import ACCELERATION_DUE_TO_GRAVITY
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
from openpilot.common.pid import PIDController
@@ -29,19 +28,26 @@ class LatControlTorque(LatControl):
def __init__(self, CP, CP_SP, CI):
super().__init__(CP, CP_SP, CI)
self.torque_params = CP.lateralTuning.torque.as_builder()
self.pid = PIDController(self.torque_params.kp, self.torque_params.ki,
k_f=self.torque_params.kf, pos_limit=self.steer_max, neg_limit=-self.steer_max)
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
self.lateral_accel_from_torque = CI.lateral_accel_from_torque()
self.pid = PIDController(self.torque_params.kp, self.torque_params.ki,
k_f=self.torque_params.kf)
self.update_limits()
self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg
self.extension = LatControlTorqueExt(self, CP, CP_SP)
self.extension = LatControlTorqueExt(self, CP, CP_SP, CI)
def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
self.torque_params.latAccelFactor = latAccelFactor
self.torque_params.latAccelOffset = latAccelOffset
self.torque_params.friction = friction
self.update_limits()
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
def update_limits(self):
self.pid.set_limits(self.lateral_accel_from_torque(self.steer_max, self.torque_params),
self.lateral_accel_from_torque(-self.steer_max, self.torque_params))
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
pid_log = log.ControlsState.LateralTorqueState.new_message()
if not active:
output_torque = 0.0
@@ -50,10 +56,8 @@ class LatControlTorque(LatControl):
actual_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
roll_compensation = params.roll * ACCELERATION_DUE_TO_GRAVITY
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
desired_lateral_accel = desired_curvature * CS.vEgo ** 2
# desired rate is the desired rate of change in the setpoint, not the absolute desired curvature
# desired_lateral_jerk = desired_curvature_rate * CS.vEgo ** 2
desired_lateral_accel = desired_curvature * CS.vEgo ** 2
actual_lateral_accel = actual_curvature * CS.vEgo ** 2
lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2
@@ -61,36 +65,36 @@ class LatControlTorque(LatControl):
setpoint = desired_lateral_accel + low_speed_factor * desired_curvature
measurement = actual_lateral_accel + low_speed_factor * actual_curvature
gravity_adjusted_lateral_accel = desired_lateral_accel - roll_compensation
torque_from_setpoint = self.torque_from_lateral_accel(LatControlInputs(setpoint, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params,
gravity_adjusted=False)
torque_from_measurement = self.torque_from_lateral_accel(LatControlInputs(measurement, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params,
gravity_adjusted=False)
pid_log.error = float(torque_from_setpoint - torque_from_measurement)
ff = self.torque_from_lateral_accel(LatControlInputs(gravity_adjusted_lateral_accel, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params,
gravity_adjusted=True)
# do error correction in lateral acceleration space, convert at end to handle non-linear torque responses correctly
pid_log.error = float(setpoint - measurement)
ff = gravity_adjusted_lateral_accel
# latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll
ff -= self.torque_params.latAccelOffset
ff += get_friction(desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params)
# Lateral acceleration torque controller extension updates
# Overrides stock ff and pid_log.error
ff, pid_log = self.extension.update(CS, VM, params, ff, pid_log, setpoint, measurement, calibrated_pose, roll_compensation,
desired_lateral_accel, actual_lateral_accel, lateral_accel_deadzone, gravity_adjusted_lateral_accel,
desired_curvature, actual_curvature)
freeze_integrator = steer_limited_by_controls or CS.steeringPressed or CS.vEgo < 5
output_torque = self.pid.update(pid_log.error,
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
output_lataccel = self.pid.update(pid_log.error,
feedforward=ff,
speed=CS.vEgo,
freeze_integrator=freeze_integrator)
output_torque = self.torque_from_lateral_accel(output_lataccel, self.torque_params)
# Lateral acceleration torque controller extension updates
# Overrides pid_log.error and output_torque
pid_log, output_torque = self.extension.update(CS, VM, self.pid, params, ff, pid_log, setpoint, measurement, calibrated_pose, roll_compensation,
desired_lateral_accel, actual_lateral_accel, lateral_accel_deadzone, gravity_adjusted_lateral_accel,
desired_curvature, actual_curvature, steer_limited_by_safety, output_torque)
pid_log.active = True
pid_log.p = float(self.pid.p)
pid_log.i = float(self.pid.i)
pid_log.d = float(self.pid.d)
pid_log.f = float(self.pid.f)
pid_log.output = float(-output_torque)
pid_log.output = float(-output_torque) # TODO: log lat accel?
pid_log.actualLateralAccel = float(actual_lateral_accel)
pid_log.desiredLateralAccel = float(desired_lateral_accel)
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_controls, curvature_limited))
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited))
# TODO left is positive in this convention
return -output_torque, 0.0, pid_log

View File

@@ -1,6 +1,6 @@
from cereal import log
from openpilot.common.realtime import DT_CTRL
from openpilot.common.conversions import Conversions as CV
from openpilot.common.constants import CV
CAMERA_OFFSET = 0.04

View File

@@ -4,7 +4,7 @@ import numpy as np
import cereal.messaging as messaging
from opendbc.car.interfaces import ACCEL_MIN, ACCEL_MAX
from openpilot.common.conversions import Conversions as CV
from openpilot.common.constants import CV
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.realtime import DT_MDL
from openpilot.selfdrive.modeld.constants import ModelConstants
@@ -21,7 +21,7 @@ LON_MPC_STEP = 0.2 # first step is 0.2s
A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6]
A_CRUISE_MAX_BP = [0., 10.0, 25., 40.]
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
ALLOW_THROTTLE_THRESHOLD = 0.5
ALLOW_THROTTLE_THRESHOLD = 0.4
MIN_ALLOW_THROTTLE_SPEED = 2.5
# Lookup table for turns
@@ -93,12 +93,12 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
return x, v, a, j, throttle_prob
def update(self, sm):
self.mode = 'blended' if sm['selfdriveState'].experimentalMode else 'acc'
mode = 'blended' if sm['selfdriveState'].experimentalMode else 'acc'
if not self.mlsim:
self.mpc.mode = self.mode
self.mpc.mode = mode
LongitudinalPlannerSP.update(self, sm)
if dec_mpc_mode := self.get_mpc_mode():
self.mode = dec_mpc_mode
mode = dec_mpc_mode
if not self.mlsim:
self.mpc.mode = dec_mpc_mode
@@ -123,7 +123,7 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
# No change cost when user is controlling the speed, or when standstill
prev_accel_constraint = not (reset_state or sm['carState'].standstill)
if self.mode == 'acc':
if mode == 'acc':
accel_clip = [ACCEL_MIN, get_max_accel(v_ego)]
steer_angle_without_offset = sm['carState'].steeringAngleDeg - sm['liveParameters'].angleOffsetDeg
accel_clip = limit_accel_in_turns(v_ego, steer_angle_without_offset, accel_clip, self.CP)
@@ -146,6 +146,9 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
clipped_accel_coast_interp = np.interp(v_ego, [MIN_ALLOW_THROTTLE_SPEED, MIN_ALLOW_THROTTLE_SPEED*2], [accel_clip[1], clipped_accel_coast])
accel_clip[1] = min(accel_clip[1], clipped_accel_coast_interp)
# Get new v_cruise and a_desired from Smart Cruise Control and Speed Limit Assist
v_cruise, self.a_desired = LongitudinalPlannerSP.update_targets(self, sm, self.v_desired_filter.x, self.a_desired, v_cruise)
if force_slow_decel:
v_cruise = 0.0
@@ -173,7 +176,7 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
output_a_target_e2e = sm['modelV2'].action.desiredAcceleration
output_should_stop_e2e = sm['modelV2'].action.shouldStop
if self.mode == 'acc' or not self.mlsim:
if mode == 'acc' or not self.mlsim:
output_a_target = output_a_target_mpc
self.output_should_stop = output_should_stop_mpc
else:
@@ -188,7 +191,7 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
def publish(self, sm, pm):
plan_send = messaging.new_message('longitudinalPlan')
plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState', 'selfdriveState'])
plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState', 'selfdriveState', 'radarState'])
longitudinalPlan = plan_send.longitudinalPlan
longitudinalPlan.modelMonoTime = sm.logMonoTime['modelV2']

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python3
from cereal import car
from openpilot.common.gps import get_gps_location_service
from openpilot.common.params import Params
from openpilot.common.realtime import Priority, config_realtime_process
from openpilot.common.swaglog import cloudlog
@@ -16,10 +17,13 @@ def main():
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
cloudlog.info("plannerd got CarParams: %s", CP.brand)
gps_location_service = get_gps_location_service(params)
ldw = LaneDepartureWarning()
longitudinal_planner = LongitudinalPlanner(CP)
pm = messaging.PubMaster(['longitudinalPlan', 'driverAssistance', 'longitudinalPlanSP'])
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState'],
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState',
'liveMapDataSP', 'carStateSP', gps_location_service],
poll='modelV2')
while True:

View File

@@ -5,6 +5,7 @@ from opendbc.car.car_helpers import interfaces
from opendbc.car.honda.values import CAR as HONDA
from opendbc.car.toyota.values import CAR as TOYOTA
from opendbc.car.nissan.values import CAR as NISSAN
from opendbc.car.gm.values import CAR as GM
from opendbc.car.vehicle_model import VehicleModel
from openpilot.selfdrive.car.helpers import convert_to_capnp
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
@@ -17,7 +18,8 @@ from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfac
class TestLatControl:
@parameterized.expand([(HONDA.HONDA_CIVIC, LatControlPID), (TOYOTA.TOYOTA_RAV4, LatControlTorque), (NISSAN.NISSAN_LEAF, LatControlAngle)])
@parameterized.expand([(HONDA.HONDA_CIVIC, LatControlPID), (TOYOTA.TOYOTA_RAV4, LatControlTorque),
(NISSAN.NISSAN_LEAF, LatControlAngle), (GM.CHEVROLET_BOLT_EUV, LatControlTorque)])
def test_saturation(self, car_name, controller):
CarInterface = interfaces[car_name]
CP = CarInterface.get_non_essential_params(car_name)

View File

@@ -0,0 +1,70 @@
import numpy as np
from cereal import car, messaging
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY
from opendbc.car import structs
from opendbc.car.lateral import get_friction, FRICTION_THRESHOLD
from openpilot.common.realtime import DT_MDL
from openpilot.selfdrive.locationd.torqued import TorqueEstimator, MIN_BUCKET_POINTS, POINTS_PER_BUCKET, STEER_BUCKET_BOUNDS
np.random.seed(0)
LA_ERR_STD = 1.0
INPUT_NOISE_STD = 0.08
V_EGO = 30.0
WARMUP_BUCKET_POINTS = (1.5*MIN_BUCKET_POINTS).astype(int)
STRAIGHT_ROAD_LA_BOUNDS = (0.02, 0.03)
ROLL_BIAS_DEG = 2.0
ROLL_COMPENSATION_BIAS = ACCELERATION_DUE_TO_GRAVITY*float(np.sin(np.deg2rad(ROLL_BIAS_DEG)))
TORQUE_TUNE = structs.CarParams.LateralTorqueTuning(latAccelFactor=2.0, latAccelOffset=0.0, friction=0.2)
TORQUE_TUNE_BIASED = structs.CarParams.LateralTorqueTuning(latAccelFactor=2.0, latAccelOffset=-ROLL_COMPENSATION_BIAS, friction=0.2)
def generate_inputs(torque_tune, la_err_std, input_noise_std=None):
rng = np.random.default_rng(0)
steer_torques = np.concat([rng.uniform(bnd[0], bnd[1], pts) for bnd, pts in zip(STEER_BUCKET_BOUNDS, WARMUP_BUCKET_POINTS, strict=True)])
la_errs = rng.normal(scale=la_err_std, size=steer_torques.size)
frictions = np.array([get_friction(la_err, 0.0, FRICTION_THRESHOLD, torque_tune) for la_err in la_errs])
lat_accels = torque_tune.latAccelFactor*steer_torques + torque_tune.latAccelOffset + frictions
if input_noise_std is not None:
steer_torques += rng.normal(scale=input_noise_std, size=steer_torques.size)
lat_accels += rng.normal(scale=input_noise_std, size=steer_torques.size)
return steer_torques, lat_accels
def get_warmed_up_estimator(steer_torques, lat_accels):
est = TorqueEstimator(car.CarParams())
for steer_torque, lat_accel in zip(steer_torques, lat_accels, strict=True):
est.filtered_points.add_point(steer_torque, lat_accel)
return est
def simulate_straight_road_msgs(est):
carControl = messaging.new_message('carControl').carControl
carOutput = messaging.new_message('carOutput').carOutput
carState = messaging.new_message('carState').carState
livePose = messaging.new_message('livePose').livePose
carControl.latActive = True
carState.vEgo = V_EGO
carState.steeringPressed = False
ts = DT_MDL*np.arange(2*POINTS_PER_BUCKET)
steer_torques = np.concat((np.linspace(-0.03, -0.02, POINTS_PER_BUCKET), np.linspace(0.02, 0.03, POINTS_PER_BUCKET)))
lat_accels = TORQUE_TUNE.latAccelFactor * steer_torques
for t, steer_torque, lat_accel in zip(ts, steer_torques, lat_accels, strict=True):
carOutput.actuatorsOutput.torque = float(-steer_torque)
livePose.orientationNED.x = float(np.deg2rad(ROLL_BIAS_DEG))
livePose.angularVelocityDevice.z = float(lat_accel / V_EGO)
for which, msg in (('carControl', carControl), ('carOutput', carOutput), ('carState', carState), ('livePose', livePose)):
est.handle_log(t, which, msg)
def test_estimated_offset():
steer_torques, lat_accels = generate_inputs(TORQUE_TUNE_BIASED, la_err_std=LA_ERR_STD, input_noise_std=INPUT_NOISE_STD)
est = get_warmed_up_estimator(steer_torques, lat_accels)
msg = est.get_msg()
# TODO add lataccelfactor and friction check when we have more accurate estimates
assert abs(msg.liveTorqueParameters.latAccelOffsetRaw - TORQUE_TUNE_BIASED.latAccelOffset) < 0.1
def test_straight_road_roll_bias():
steer_torques, lat_accels = generate_inputs(TORQUE_TUNE, la_err_std=LA_ERR_STD, input_noise_std=INPUT_NOISE_STD)
est = get_warmed_up_estimator(steer_torques, lat_accels)
simulate_straight_road_msgs(est)
msg = est.get_msg()
assert (msg.liveTorqueParameters.latAccelOffsetRaw < -0.05) and np.isfinite(msg.liveTorqueParameters.latAccelOffsetRaw)

View File

@@ -1,23 +1,25 @@
#!/usr/bin/env python3
import argparse
from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, replay_process
from openpilot.selfdrive.test.process_replay.test_processes import EXCLUDED_PROCS
from openpilot.tools.lib.logreader import LogReader, save_log
ALLOW_PROCS = {c.proc_name for c in CONFIGS}
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Run process on route and create new logs",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--fingerprint", help="The fingerprint to use")
parser.add_argument("route", help="The route name to use")
parser.add_argument("process", nargs='+', help="The process(s) to run")
parser.add_argument("--fingerprint", help="The fingerprint to use")
parser.add_argument("--whitelist-procs", nargs='*', default=ALLOW_PROCS, help="Whitelist given processes (e.g. controlsd)")
parser.add_argument("--blacklist-procs", nargs='*', default=EXCLUDED_PROCS, help="Blacklist given processes (e.g. controlsd)")
args = parser.parse_args()
cfgs = [c for c in CONFIGS if c.proc_name in args.process]
lr = LogReader(args.route)
inputs = list(lr)
allowed_procs = set(args.whitelist_procs) - set(args.blacklist_procs)
cfgs = [c for c in CONFIGS if c.proc_name in allowed_procs]
inputs = list(LogReader(args.route))
outputs = replay_process(cfgs, inputs, fingerprint=args.fingerprint)
# Remove message generated by the process under test and merge in the new messages
@@ -25,6 +27,6 @@ if __name__ == "__main__":
inputs = [i for i in inputs if i.which() not in produces]
outputs = sorted(inputs + outputs, key=lambda x: x.logMonoTime)
fn = f"{args.route.replace('/', '_')}_{'_'.join(args.process)}.zst"
fn = f"{args.route.replace('/', '_')}_{'_'.join(allowed_procs)}.zst"
print(f"Saving log to {fn}")
save_log(fn, outputs)

View File

@@ -14,7 +14,7 @@ from typing import NoReturn
from cereal import log, car
import cereal.messaging as messaging
from openpilot.system.hardware import HARDWARE
from openpilot.common.conversions import Conversions as CV
from openpilot.common.constants import CV
from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process
from openpilot.common.transformations.orientation import rot_from_euler, euler_from_rot

View File

@@ -12,6 +12,7 @@ from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose, fft_next_good_size, parabolic_peak_interp
from openpilot.sunnypilot.livedelay.lagd_toggle import LagdToggle
BLOCK_SIZE = 100
BLOCK_NUM = 50
@@ -374,6 +375,8 @@ def main():
lag, valid_blocks = initial_lag_params
lag_learner.reset(lag, valid_blocks)
lagd_toggle = LagdToggle(CP)
while True:
sm.update()
if sm.all_checks():
@@ -392,3 +395,6 @@ def main():
if sm.frame % 1200 == 0: # cache every 60 seconds
params.put_nonblocking("LiveDelay", lag_msg_dat)
if sm.frame % 60 == 0: # read from and write to params every 3 seconds
lagd_toggle.update(lag_msg)

View File

@@ -5,7 +5,7 @@ from typing import Any
import numpy as np
from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
from openpilot.common.constants import ACCELERATION_DUE_TO_GRAVITY
from openpilot.selfdrive.locationd.models.constants import ObservationKind
from openpilot.common.swaglog import cloudlog

View File

@@ -4,14 +4,13 @@ from collections import deque, defaultdict
import cereal.messaging as messaging
from cereal import car, log
from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
from openpilot.common.constants import ACCELERATION_DUE_TO_GRAVITY
from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, DT_MDL
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator, PoseCalibrator, Pose
from openpilot.sunnypilot.livedelay.lagd_toggle import LagdToggle
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
HISTORY = 5 # secs
POINTS_PER_BUCKET = 1500
@@ -34,7 +33,7 @@ MIN_BUCKET_POINTS = np.array([100, 300, 500, 500, 500, 500, 300, 100])
MIN_ENGAGE_BUFFER = 2 # secs
VERSION = 1 # bump this to invalidate old parameter caches
ALLOWED_CARS = ['toyota', 'hyundai', 'rivian']
ALLOWED_CARS = ['toyota', 'hyundai', 'rivian', 'honda']
def slope2rot(slope):
@@ -51,7 +50,7 @@ class TorqueBuckets(PointBuckets):
break
class TorqueEstimator(ParameterEstimator, LagdToggle):
class TorqueEstimator(ParameterEstimator):
def __init__(self, CP, decimated=False, track_all_points=False):
super().__init__()
self.CP = CP
@@ -99,6 +98,7 @@ class TorqueEstimator(ParameterEstimator, LagdToggle):
# try to restore cached params
params = Params()
self.params = params
params_cache = params.get("CarParamsPrevRoute")
torque_cache = params.get("LiveTorqueParameters")
if params_cache is not None and torque_cache is not None:
@@ -180,7 +180,7 @@ class TorqueEstimator(ParameterEstimator, LagdToggle):
elif which == "liveCalibration":
self.calibrator.feed_live_calib(msg)
elif which == "liveDelay":
self.lag = self.lagd_torqued_main(self.CP, msg)
self.lag = get_lat_delay(self.params, msg.lateralDelay)
# calculate lateral accel from past steering torque
elif which == "livePose":
if len(self.raw_points['steer_torque']) == self.hist_len:

View File

@@ -13,12 +13,9 @@ class ModelConstants:
META_T_IDXS = [2., 4., 6., 8., 10.]
# model inputs constants
MODEL_FREQ = 20
HISTORY_FREQ = 5
HISTORY_LEN_SECONDS = 5
TEMPORAL_SKIP = MODEL_FREQ // HISTORY_FREQ
FULL_HISTORY_BUFFER_LEN = MODEL_FREQ * HISTORY_LEN_SECONDS
INPUT_HISTORY_BUFFER_LEN = HISTORY_FREQ * HISTORY_LEN_SECONDS
N_FRAMES = 2
MODEL_RUN_FREQ = 20
MODEL_CONTEXT_FREQ = 5 # "model_trained_fps"
FEATURE_LEN = 512

View File

@@ -3,6 +3,7 @@ import capnp
import numpy as np
from cereal import log
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan, Meta
from openpilot.sunnypilot.models.helpers import plan_x_idxs_helper
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
@@ -95,8 +96,8 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
# action
modelV2.action = action
# times at X_IDXS of edges and lines aren't used
LINE_T_IDXS: list[float] = []
# times at X_IDXS of edges and lines
LINE_T_IDXS: list[float] = plan_x_idxs_helper(ModelConstants, Plan, net_output_data)
# lane lines
modelV2.init('laneLines', 4)
@@ -149,7 +150,7 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
meta.hardBrakePredicted = hard_brake_predicted.item()
# confidence
if vipc_frame_id % (2*ModelConstants.MODEL_FREQ) == 0:
if vipc_frame_id % (2*ModelConstants.MODEL_RUN_FREQ) == 0:
# any disengage prob
brake_disengage_probs = net_output_data['meta'][0,Meta.BRAKE_DISENGAGE]
gas_disengage_probs = net_output_data['meta'][0,Meta.GAS_DISENGAGE]

View File

@@ -31,7 +31,8 @@ from openpilot.selfdrive.modeld.constants import ModelConstants, Plan
from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
from openpilot.sunnypilot.livedelay.lagd_toggle import LagdToggle
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
from openpilot.sunnypilot.modeld.modeld_base import ModelStateBase
PROCESS_NAME = "selfdrive.modeld.modeld"
@@ -79,13 +80,72 @@ class FrameMeta:
if vipc is not None:
self.frame_id, self.timestamp_sof, self.timestamp_eof = vipc.frame_id, vipc.timestamp_sof, vipc.timestamp_eof
class ModelState:
class InputQueues:
def __init__ (self, model_fps, env_fps, n_frames_input):
assert env_fps % model_fps == 0
assert env_fps >= model_fps
self.model_fps = model_fps
self.env_fps = env_fps
self.n_frames_input = n_frames_input
self.dtypes = {}
self.shapes = {}
self.q = {}
def update_dtypes_and_shapes(self, input_dtypes, input_shapes) -> None:
self.dtypes.update(input_dtypes)
if self.env_fps == self.model_fps:
self.shapes.update(input_shapes)
else:
for k in input_shapes:
shape = list(input_shapes[k])
if 'img' in k:
n_channels = shape[1] // self.n_frames_input
shape[1] = (self.env_fps // self.model_fps + (self.n_frames_input - 1)) * n_channels
else:
shape[1] = (self.env_fps // self.model_fps) * shape[1]
self.shapes[k] = tuple(shape)
def reset(self) -> None:
self.q = {k: np.zeros(self.shapes[k], dtype=self.dtypes[k]) for k in self.dtypes.keys()}
def enqueue(self, inputs:dict[str, np.ndarray]) -> None:
for k in inputs.keys():
if inputs[k].dtype != self.dtypes[k]:
raise ValueError(f'supplied input <{k}({inputs[k].dtype})> has wrong dtype, expected {self.dtypes[k]}')
input_shape = list(self.shapes[k])
input_shape[1] = -1
single_input = inputs[k].reshape(tuple(input_shape))
sz = single_input.shape[1]
self.q[k][:,:-sz] = self.q[k][:,sz:]
self.q[k][:,-sz:] = single_input
def get(self, *names) -> dict[str, np.ndarray]:
if self.env_fps == self.model_fps:
return {k: self.q[k] for k in names}
else:
out = {}
for k in names:
shape = self.shapes[k]
if 'img' in k:
n_channels = shape[1] // (self.env_fps // self.model_fps + (self.n_frames_input - 1))
out[k] = np.concatenate([self.q[k][:, s:s+n_channels] for s in np.linspace(0, shape[1] - n_channels, self.n_frames_input, dtype=int)], axis=1)
elif 'pulse' in k:
# any pulse within interval counts
out[k] = self.q[k].reshape((shape[0], shape[1] * self.model_fps // self.env_fps, self.env_fps // self.model_fps, -1)).max(axis=2)
else:
idxs = np.arange(-1, -shape[1], -self.env_fps // self.model_fps)[::-1]
out[k] = self.q[k][:, idxs]
return out
class ModelState(ModelStateBase):
frames: dict[str, DrivingModelFrame]
inputs: dict[str, np.ndarray]
output: np.ndarray
prev_desire: np.ndarray # for tracking the rising edge of the pulse
def __init__(self, context: CLContext):
ModelStateBase.__init__(self)
self.LAT_SMOOTH_SECONDS = LAT_SMOOTH_SECONDS
with open(VISION_METADATA_PATH, 'rb') as f:
vision_metadata = pickle.load(f)
@@ -100,22 +160,15 @@ class ModelState:
self.policy_output_slices = policy_metadata['output_slices']
policy_output_size = policy_metadata['output_shapes']['outputs'][1]
self.frames = {name: DrivingModelFrame(context, ModelConstants.TEMPORAL_SKIP) for name in self.vision_input_names}
self.frames = {name: DrivingModelFrame(context, ModelConstants.MODEL_RUN_FREQ//ModelConstants.MODEL_CONTEXT_FREQ) for name in self.vision_input_names}
self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
self.full_features_buffer = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32)
self.full_desire = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32)
self.full_prev_desired_curv = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32)
self.temporal_idxs = slice(-1-(ModelConstants.TEMPORAL_SKIP*(ModelConstants.INPUT_HISTORY_BUFFER_LEN-1)), None, ModelConstants.TEMPORAL_SKIP)
# policy inputs
self.numpy_inputs = {
'desire': np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32),
'traffic_convention': np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32),
'lateral_control_params': np.zeros((1, ModelConstants.LATERAL_CONTROL_PARAMS_LEN), dtype=np.float32),
'prev_desired_curv': np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32),
'features_buffer': np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32),
}
self.numpy_inputs = {k: np.zeros(self.policy_input_shapes[k], dtype=np.float32) for k in self.policy_input_shapes}
self.full_input_queues = InputQueues(ModelConstants.MODEL_CONTEXT_FREQ, ModelConstants.MODEL_RUN_FREQ, ModelConstants.N_FRAMES)
for k in ['desire_pulse', 'features_buffer']:
self.full_input_queues.update_dtypes_and_shapes({k: self.numpy_inputs[k].dtype}, {k: self.numpy_inputs[k].shape})
self.full_input_queues.reset()
# img buffers are managed in openCL transform code
self.vision_inputs: dict[str, Tensor] = {}
@@ -137,16 +190,10 @@ class ModelState:
def run(self, bufs: dict[str, VisionBuf], transforms: dict[str, np.ndarray],
inputs: dict[str, np.ndarray], prepare_only: bool) -> dict[str, np.ndarray] | None:
# Model decides when action is completed, so desire input is just a pulse triggered on rising edge
inputs['desire'][0] = 0
new_desire = np.where(inputs['desire'] - self.prev_desire > .99, inputs['desire'], 0)
self.prev_desire[:] = inputs['desire']
inputs['desire_pulse'][0] = 0
new_desire = np.where(inputs['desire_pulse'] - self.prev_desire > .99, inputs['desire_pulse'], 0)
self.prev_desire[:] = inputs['desire_pulse']
self.full_desire[0,:-1] = self.full_desire[0,1:]
self.full_desire[0,-1] = new_desire
self.numpy_inputs['desire'][:] = self.full_desire.reshape((1,ModelConstants.INPUT_HISTORY_BUFFER_LEN,ModelConstants.TEMPORAL_SKIP,-1)).max(axis=2)
self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
self.numpy_inputs['lateral_control_params'][:] = inputs['lateral_control_params']
imgs_cl = {name: self.frames[name].prepare(bufs[name], transforms[name].flatten()) for name in self.vision_input_names}
if TICI and not USBGPU:
@@ -165,18 +212,14 @@ class ModelState:
self.vision_output = self.vision_run(**self.vision_inputs).contiguous().realize().uop.base.buffer.numpy()
vision_outputs_dict = self.parser.parse_vision_outputs(self.slice_outputs(self.vision_output, self.vision_output_slices))
self.full_features_buffer[0,:-1] = self.full_features_buffer[0,1:]
self.full_features_buffer[0,-1] = vision_outputs_dict['hidden_state'][0, :]
self.numpy_inputs['features_buffer'][:] = self.full_features_buffer[0, self.temporal_idxs]
self.full_input_queues.enqueue({'features_buffer': vision_outputs_dict['hidden_state'], 'desire_pulse': new_desire})
for k in ['desire_pulse', 'features_buffer']:
self.numpy_inputs[k][:] = self.full_input_queues.get(k)[k]
self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
self.policy_output = self.policy_run(**self.policy_inputs).contiguous().realize().uop.base.buffer.numpy()
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices))
# TODO model only uses last value now
self.full_prev_desired_curv[0,:-1] = self.full_prev_desired_curv[0,1:]
self.full_prev_desired_curv[0,-1,:] = policy_outputs_dict['desired_curvature'][0, :]
self.numpy_inputs['prev_desired_curv'][:] = 0*self.full_prev_desired_curv[0, self.temporal_idxs]
combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict}
if SEND_RAW_PRED:
combined_outputs_dict['raw_pred'] = np.concatenate([self.vision_output.copy(), self.policy_output.copy()])
@@ -223,14 +266,14 @@ def main(demo=False):
cloudlog.warning(f"connected extra cam with buffer size: {vipc_client_extra.buffer_len} ({vipc_client_extra.width} x {vipc_client_extra.height})")
# messaging
pm = PubMaster(["modelV2", "drivingModelData", "cameraOdometry"])
pm = PubMaster(["modelV2", "drivingModelData", "cameraOdometry", "modelDataV2SP"])
sm = SubMaster(["deviceState", "carState", "roadCameraState", "liveCalibration", "driverMonitoringState", "carControl", "liveDelay"])
publish_state = PublishState()
params = Params()
# setup filter to track dropped frames
frame_dropped_filter = FirstOrderFilter(0., 10., 1. / ModelConstants.MODEL_FREQ)
frame_dropped_filter = FirstOrderFilter(0., 10., 1. / ModelConstants.MODEL_RUN_FREQ)
frame_id = 0
last_vipc_frame_id = 0
run_count = 0
@@ -249,8 +292,6 @@ def main(demo=False):
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
cloudlog.info("modeld got CarParams: %s", CP.brand)
modeld_lagd = LagdToggle()
# TODO this needs more thought, use .2s extra for now to estimate other delays
# TODO Move smooth seconds to action function
long_delay = CP.longitudinalActuatorDelay + LONG_SMOOTH_SECONDS
@@ -296,8 +337,9 @@ def main(demo=False):
is_rhd = sm["driverMonitoringState"].isRHD
frame_id = sm["roadCameraState"].frameId
v_ego = max(sm["carState"].vEgo, 0.)
lat_delay = modeld_lagd.lagd_main(CP, sm, model)
lateral_control_params = np.array([v_ego, lat_delay], dtype=np.float32)
if sm.frame % 60 == 0:
model.lat_delay = get_lat_delay(params, sm["liveDelay"].lateralDelay)
lat_delay = model.lat_delay + LAT_SMOOTH_SECONDS
if sm.updated["liveCalibration"] and sm.seen['roadCameraState'] and sm.seen['deviceState']:
device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32)
dc = DEVICE_CAMERAS[(str(sm['deviceState'].deviceType), str(sm['roadCameraState'].sensor))]
@@ -328,9 +370,8 @@ def main(demo=False):
bufs = {name: buf_extra if 'big' in name else buf_main for name in model.vision_input_names}
transforms = {name: model_transform_extra if 'big' in name else model_transform_main for name in model.vision_input_names}
inputs:dict[str, np.ndarray] = {
'desire': vec_desire,
'desire_pulse': vec_desire,
'traffic_convention': traffic_convention,
'lateral_control_params': lateral_control_params,
}
mt1 = time.perf_counter()
@@ -342,6 +383,7 @@ def main(demo=False):
modelv2_send = messaging.new_message('modelV2')
drivingdata_send = messaging.new_message('drivingModelData')
posenet_send = messaging.new_message('cameraOdometry')
mdv2sp_send = messaging.new_message('modelDataV2SP')
action = get_action_from_model(model_output, prev_action, lat_delay + DT_MDL, long_delay + DT_MDL, v_ego)
prev_action = action
@@ -356,6 +398,7 @@ def main(demo=False):
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob)
modelv2_send.modelV2.meta.laneChangeState = DH.lane_change_state
modelv2_send.modelV2.meta.laneChangeDirection = DH.lane_change_direction
mdv2sp_send.modelDataV2SP.laneTurnDirection = DH.lane_turn_direction
drivingdata_send.drivingModelData.meta.laneChangeState = DH.lane_change_state
drivingdata_send.drivingModelData.meta.laneChangeDirection = DH.lane_change_direction
@@ -363,6 +406,7 @@ def main(demo=False):
pm.send('modelV2', modelv2_send)
pm.send('drivingModelData', drivingdata_send)
pm.send('cameraOdometry', posenet_send)
pm.send('modelDataV2SP', mdv2sp_send)
last_vipc_frame_id = meta_main.frame_id

View File

@@ -22,9 +22,10 @@ class Parser:
self.ignore_missing = ignore_missing
def check_missing(self, outs, name):
if name not in outs and not self.ignore_missing:
missing = name not in outs
if missing and not self.ignore_missing:
raise ValueError(f"Missing output {name}")
return name not in outs
return missing
def parse_categorical_crossentropy(self, name, outs, out_shape=None):
if self.check_missing(outs, name):
@@ -84,6 +85,13 @@ class Parser:
outs[name] = pred_mu_final.reshape(final_shape)
outs[name + '_stds'] = pred_std_final.reshape(final_shape)
def is_mhp(self, outs, name, shape):
if self.check_missing(outs, name):
return False
if outs[name].shape[1] == 2 * shape:
return False
return True
def parse_vision_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]:
self.parse_mdn('pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
self.parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(ModelConstants.WIDE_FROM_DEVICE_WIDTH,))
@@ -94,17 +102,17 @@ class Parser:
self.parse_categorical_crossentropy('desire_pred', outs, out_shape=(ModelConstants.DESIRE_PRED_LEN,ModelConstants.DESIRE_PRED_WIDTH))
self.parse_binary_crossentropy('meta', outs)
self.parse_binary_crossentropy('lead_prob', outs)
self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION,
out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH))
lead_mhp = self.is_mhp(outs, 'lead', ModelConstants.LEAD_MHP_SELECTION * ModelConstants.LEAD_TRAJ_LEN * ModelConstants.LEAD_WIDTH)
lead_in_N, lead_out_N = (ModelConstants.LEAD_MHP_N, ModelConstants.LEAD_MHP_SELECTION) if lead_mhp else (0, 0)
lead_out_shape = (ModelConstants.LEAD_TRAJ_LEN, ModelConstants.LEAD_WIDTH) if lead_mhp else \
(ModelConstants.LEAD_MHP_SELECTION, ModelConstants.LEAD_TRAJ_LEN, ModelConstants.LEAD_WIDTH)
self.parse_mdn('lead', outs, in_N=lead_in_N, out_N=lead_out_N, out_shape=lead_out_shape)
return outs
def parse_policy_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]:
self.parse_mdn('plan', outs, in_N=ModelConstants.PLAN_MHP_N, out_N=ModelConstants.PLAN_MHP_SELECTION,
out_shape=(ModelConstants.IDX_N,ModelConstants.PLAN_WIDTH))
if 'lat_planner_solution' in outs:
self.parse_mdn('lat_planner_solution', outs, in_N=0, out_N=0, out_shape=(ModelConstants.IDX_N,ModelConstants.LAT_PLANNER_SOLUTION_WIDTH))
if 'desired_curvature' in outs:
self.parse_mdn('desired_curvature', outs, in_N=0, out_N=0, out_shape=(ModelConstants.DESIRED_CURV_WIDTH,))
plan_mhp = self.is_mhp(outs, 'plan', ModelConstants.IDX_N * ModelConstants.PLAN_WIDTH)
plan_in_N, plan_out_N = (ModelConstants.PLAN_MHP_N, ModelConstants.PLAN_MHP_SELECTION) if plan_mhp else (0, 0)
self.parse_mdn('plan', outs, in_N=plan_in_N, out_N=plan_out_N, out_shape=(ModelConstants.IDX_N, ModelConstants.PLAN_WIDTH))
self.parse_categorical_crossentropy('desire_state', outs, out_shape=(ModelConstants.DESIRE_PRED_WIDTH,))
return outs

View File

@@ -84,6 +84,13 @@ Panda *connect(std::string serial="", uint32_t index=0) {
panda->set_can_fd_auto(i, true);
}
bool is_supported_panda = std::find(SUPPORTED_PANDA_TYPES.begin(), SUPPORTED_PANDA_TYPES.end(), panda->hw_type) != SUPPORTED_PANDA_TYPES.end();
if (!is_supported_panda) {
LOGW("panda %s is not supported (hw_type: %i), skipping firmware check...", panda->hw_serial().c_str(), static_cast<uint16_t>(panda->hw_type));
return panda.release();
}
if (!panda->up_to_date() && !getenv("BOARDD_SKIP_FW_CHECK")) {
throw std::runtime_error("Panda firmware out of date. Run pandad.py to update.");
}
@@ -166,7 +173,6 @@ void fill_panda_state(cereal::PandaState::Builder &ps, cereal::PandaState::Panda
ps.setHarnessStatus(cereal::PandaState::HarnessStatus(health.car_harness_status_pkt));
ps.setInterruptLoad(health.interrupt_load_pkt);
ps.setFanPower(health.fan_power);
ps.setFanStallCount(health.fan_stall_count);
ps.setSafetyRxChecksInvalid((bool)(health.safety_rx_checks_invalid_pkt));
ps.setSpiErrorCount(health.spi_error_count_pkt);
ps.setSbu1Voltage(health.sbu1_voltage_mV / 1000.0f);

View File

@@ -8,6 +8,14 @@
void pandad_main_thread(std::vector<std::string> serials);
// deprecated devices
static const std::vector<cereal::PandaState::PandaType> SUPPORTED_PANDA_TYPES = {
cereal::PandaState::PandaType::RED_PANDA,
cereal::PandaState::PandaType::TRES,
cereal::PandaState::PandaType::CUATRO,
};
class PandaSafety {
public:
PandaSafety(const std::vector<Panda *> &pandas) : pandas_(pandas) {}

View File

@@ -29,6 +29,12 @@ def flash_panda(panda_serial: str) -> Panda:
HARDWARE.recover_internal_panda()
raise
# skip flashing if the detected panda is not supported
supported_panda = check_panda_support(panda)
if not supported_panda:
cloudlog.warning(f"Panda {panda_serial} is not supported (hw_type: {panda.get_type()}), skipping flash...")
return panda
fw_signature = get_expected_signature(panda)
internal_panda = panda.is_internal()
@@ -61,6 +67,14 @@ def flash_panda(panda_serial: str) -> Panda:
return panda
def check_panda_support(panda) -> bool:
hw_type = panda.get_type()
if hw_type in Panda.SUPPORTED_DEVICES:
return True
return False
def main() -> None:
# signal pandad to close the relay and exit
def signal_handler(signum, frame):
@@ -85,11 +99,6 @@ def main() -> None:
cloudlog.event("pandad.flash_and_connect", count=count)
params.remove("PandaSignatures")
# TODO: remove this in the next AGNOS
# wait until USB is up before counting
if time.monotonic() < 35.:
no_internal_panda_count = 0
# Handle missing internal panda
if no_internal_panda_count > 0:
if no_internal_panda_count == 3:
@@ -139,6 +148,12 @@ def main() -> None:
params.put("PandaSignatures", b','.join(p.get_signature() for p in pandas))
for panda in pandas:
# skip health check if the detected panda is not supported
supported_panda = check_panda_support(panda)
if not supported_panda:
cloudlog.warning(f"Panda {panda.get_usb_serial()} is not supported (hw_type: {panda.get_type()}), skipping health check...")
continue
# check health for lost heartbeat
health = panda.health()
if health["heartbeat_lost"]:

View File

@@ -66,58 +66,44 @@ PandaSpiHandle::PandaSpiHandle(std::string serial) : PandaCommsHandle(serial) {
// 50MHz is the max of the 845. note that some older
// revs of the comma three may not support this speed
uint32_t spi_speed = 50000000;
if (!util::file_exists(SPI_DEVICE)) {
goto fail;
}
spi_fd = open(SPI_DEVICE.c_str(), O_RDWR);
if (spi_fd < 0) {
LOGE("failed opening SPI device %d", spi_fd);
goto fail;
}
// SPI settings
ret = util::safe_ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode);
if (ret < 0) {
LOGE("failed setting SPI mode %d", ret);
goto fail;
}
ret = util::safe_ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
if (ret < 0) {
LOGE("failed setting SPI speed");
goto fail;
}
ret = util::safe_ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word);
if (ret < 0) {
LOGE("failed setting SPI bits per word");
goto fail;
}
// get hw UID/serial
ret = control_read(0xc3, 0, 0, uid, uid_len, 100);
if (ret == uid_len) {
std::stringstream stream;
for (int i = 0; i < uid_len; i++) {
stream << std::hex << std::setw(2) << std::setfill('0') << int(uid[i]);
try {
if (!util::file_exists(SPI_DEVICE)) {
throw std::runtime_error("Error connecting to panda: SPI device not found");
}
hw_serial = stream.str();
} else {
LOGD("failed to get serial %d", ret);
goto fail;
}
if (!serial.empty() && (serial != hw_serial)) {
goto fail;
}
spi_fd = open(SPI_DEVICE.c_str(), O_RDWR);
if (spi_fd < 0) {
LOGE("failed opening SPI device %d", spi_fd);
throw std::runtime_error("Error connecting to panda: failed to open SPI device");
}
// SPI settings
util::safe_ioctl(spi_fd, SPI_IOC_WR_MODE, &spi_mode, "failed setting SPI mode");
util::safe_ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed, "failed setting SPI speed");
util::safe_ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits_per_word, "failed setting SPI bits per word");
// get hw UID/serial
ret = control_read(0xc3, 0, 0, uid, uid_len, 100);
if (ret == uid_len) {
std::stringstream stream;
for (int i = 0; i < uid_len; i++) {
stream << std::hex << std::setw(2) << std::setfill('0') << int(uid[i]);
}
hw_serial = stream.str();
} else {
LOGD("failed to get serial %d", ret);
throw std::runtime_error("Error connecting to panda: failed to get serial");
}
if (!serial.empty() && (serial != hw_serial)) {
throw std::runtime_error("Error connecting to panda: serial mismatch");
}
} catch (...) {
cleanup();
throw;
}
return;
fail:
cleanup();
throw std::runtime_error("Error connecting to panda");
}
PandaSpiHandle::~PandaSpiHandle() {

View File

@@ -22,8 +22,6 @@ class TestPandad:
if len(Panda.list()) == 0:
self._run_test(60)
self.spi = HARDWARE.get_device_type() != 'tici'
def teardown_method(self):
managed_processes['pandad'].stop()
@@ -106,11 +104,9 @@ class TestPandad:
# - 0.2s pandad -> pandad
# - plus some buffer
print("startup times", ts, sum(ts) / len(ts))
assert 0.1 < (sum(ts)/len(ts)) < (0.7 if self.spi else 5.0)
assert 0.1 < (sum(ts)/len(ts)) < 0.7
def test_protocol_version_check(self):
if not self.spi:
pytest.skip("SPI test")
# flash old fw
fn = os.path.join(HERE, "bootstub.panda_h7_spiv0.bin")
self._flash_bootstub_and_test(fn, expect_mismatch=True)

View File

@@ -6,7 +6,6 @@ import random
import cereal.messaging as messaging
from cereal.services import SERVICE_LIST
from openpilot.system.hardware import HARDWARE
from openpilot.selfdrive.test.helpers import with_processes
from openpilot.selfdrive.pandad.tests.test_pandad_loopback import setup_pandad, send_random_can_messages
@@ -16,8 +15,6 @@ JUNGLE_SPAM = "JUNGLE_SPAM" in os.environ
class TestBoarddSpi:
@classmethod
def setup_class(cls):
if HARDWARE.get_device_type() == 'tici':
pytest.skip("only for spi pandas")
os.environ['STARTED'] = '1'
os.environ['SPI_ERR_PROB'] = '0.001'
if not JUNGLE_SPAM:

View File

@@ -29,10 +29,6 @@
"text": "Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support.",
"severity": 1
},
"Offroad_StorageMissing": {
"text": "NVMe drive not mounted.",
"severity": 1
},
"Offroad_CarUnrecognized": {
"text": "sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai.",
"severity": 0
@@ -46,8 +42,13 @@
"severity": 0
},
"Offroad_ExcessiveActuation": {
"text": "openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support.",
"text": "openpilot detected excessive %1 actuation on your last drive. Please contact support at https://comma.ai/support and share your device's Dongle ID for troubleshooting.",
"severity": 1,
"_comment": "Set extra field to lateral or longitudinal."
},
"Offroad_TiciSupport": {
"text": "<b>Unsupported branch detected</b> - The current version of <b><u>%1</u></b> branch is no longer supported on the comma three. Please go to <b>[Device > Software]</b> and install a supported branch with <b><u>-tici</u></b> in the branch name for the comma three.",
"severity": 1,
"_comment": "Set extra field to the current branch name."
}
}

View File

@@ -4,10 +4,12 @@ import os
from cereal import log, car
import cereal.messaging as messaging
from openpilot.common.conversions import Conversions as CV
from openpilot.common.constants import CV
from openpilot.common.git import get_short_branch
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
from openpilot.system.micd import SAMPLE_RATE, SAMPLE_BUFFER
from openpilot.selfdrive.ui.feedback.feedbackd import FEEDBACK_MAX_DURATION
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
NoEntryAlert, SoftDisableAlert, UserSoftDisableAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, \
@@ -40,6 +42,7 @@ class Events(EventsBase):
return log.OnroadEvent
# ********** helper functions **********
def get_display_speed(speed_ms: float, metric: bool) -> str:
speed = int(round(speed_ms * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)))
@@ -80,7 +83,7 @@ def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.S
f"Steer Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 0.4)
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 0.4)
def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
@@ -92,6 +95,14 @@ def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messag
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2)
def audio_feedback_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
duration = FEEDBACK_MAX_DURATION - ((sm['audioFeedback'].blockNum + 1) * SAMPLE_BUFFER / SAMPLE_RATE)
return NormalPermanentAlert(
"Recording Audio Feedback",
f"{round(duration)} second{'s' if round(duration) != 1 else ''} remaining. Press again to save early.",
priority=Priority.LOW)
# *** debug alerts ***
def out_of_space_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
@@ -203,6 +214,7 @@ def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messagin
return NormalPermanentAlert("Invalid LKAS setting", text)
EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# ********** events with no alerts **********
@@ -824,9 +836,13 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
ET.WARNING: personality_changed_alert,
},
EventName.userFlag: {
EventName.userBookmark: {
ET.PERMANENT: NormalPermanentAlert("Bookmark Saved", duration=1.5),
},
EventName.audioFeedback: {
ET.PERMANENT: audio_feedback_alert,
},
}

View File

@@ -0,0 +1,54 @@
import math
from enum import StrEnum, auto
from cereal import car, messaging
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.locationd.helpers import Pose
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY
from opendbc.car.lateral import ISO_LATERAL_ACCEL
from opendbc.car.interfaces import ACCEL_MIN, ACCEL_MAX
MIN_EXCESSIVE_ACTUATION_COUNT = int(0.25 / DT_CTRL)
MIN_LATERAL_ENGAGE_BUFFER = int(1 / DT_CTRL)
class ExcessiveActuationType(StrEnum):
LONGITUDINAL = auto()
LATERAL = auto()
class ExcessiveActuationCheck:
def __init__(self):
self._excessive_counter = 0
self._engaged_counter = 0
def update(self, sm: messaging.SubMaster, CS: car.CarState, calibrated_pose: Pose) -> ExcessiveActuationType | None:
# CS.aEgo can be noisy to bumps in the road, transitioning from standstill, losing traction, etc.
# longitudinal
accel_calibrated = calibrated_pose.acceleration.x
excessive_long_actuation = sm['carControl'].longActive and (accel_calibrated > ACCEL_MAX * 2 or accel_calibrated < ACCEL_MIN * 2)
# lateral
yaw_rate = calibrated_pose.angular_velocity.yaw
roll = sm['liveParameters'].roll
roll_compensated_lateral_accel = (CS.vEgo * yaw_rate) - (math.sin(roll) * ACCELERATION_DUE_TO_GRAVITY)
# Prevent false positives after overriding
excessive_lat_actuation = False
self._engaged_counter = self._engaged_counter + 1 if sm['carControl'].latActive and not CS.steeringPressed else 0
if self._engaged_counter > MIN_LATERAL_ENGAGE_BUFFER:
if abs(roll_compensated_lateral_accel) > ISO_LATERAL_ACCEL * 2:
excessive_lat_actuation = True
# livePose acceleration can be noisy due to bad mounting or aliased livePose measurements
livepose_valid = abs(CS.aEgo - accel_calibrated) < 2
self._excessive_counter = self._excessive_counter + 1 if livepose_valid and (excessive_long_actuation or excessive_lat_actuation) else 0
excessive_type = None
if self._excessive_counter > MIN_EXCESSIVE_ACTUATION_COUNT:
if excessive_long_actuation:
excessive_type = ExcessiveActuationType.LONGITUDINAL
else:
excessive_type = ExcessiveActuationType.LATERAL
return excessive_type

View File

@@ -7,7 +7,6 @@ import cereal.messaging as messaging
from cereal import car, log, custom
from msgq.visionipc import VisionIpcClient, VisionStreamType
from opendbc.car.interfaces import ACCEL_MIN, ACCEL_MAX
from openpilot.common.params import Params
@@ -18,15 +17,16 @@ from openpilot.common.gps import get_gps_location_service
from openpilot.selfdrive.car.car_specific import CarSpecificEvents
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
from openpilot.selfdrive.selfdrived.events import Events, ET
from openpilot.selfdrive.selfdrived.helpers import ExcessiveActuationCheck
from openpilot.selfdrive.selfdrived.state import StateMachine
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroad_alert
from openpilot.system.hardware import HARDWARE
from openpilot.system.version import get_build_metadata
from openpilot.sunnypilot.mads.mads import ModularAssistiveDrivingSystem
from openpilot.sunnypilot.selfdrive.car.car_specific import CarSpecificEventsSP
from openpilot.sunnypilot.selfdrive.car.cruise_helpers import CruiseHelper
from openpilot.sunnypilot.selfdrive.car.intelligent_cruise_button_management.controller import IntelligentCruiseButtonManagement
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
REPLAY = "REPLAY" in os.environ
@@ -34,7 +34,6 @@ SIMULATION = "SIMULATION" in os.environ
TESTING_CLOSET = "TESTING_CLOSET" in os.environ
LONGITUDINAL_PERSONALITY_MAP = {v: k for k, v in log.LongitudinalPersonality.schema.enumerants.items()}
MIN_EXCESSIVE_ACTUATION_COUNT = int(0.25 / DT_CTRL)
ThermalStatus = log.DeviceState.ThermalStatus
State = log.SelfdriveState.OpenpilotState
@@ -48,21 +47,6 @@ SafetyModel = car.CarParams.SafetyModel
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
def check_excessive_actuation(sm: messaging.SubMaster, CS: car.CarState, calibrator: PoseCalibrator, counter: int) -> tuple[int, bool]:
# CS.aEgo can be noisy to bumps in the road, transitioning from standstill, losing traction, etc.
device_pose = Pose.from_live_pose(sm['livePose'])
calibrated_pose = calibrator.build_calibrated_pose(device_pose)
accel_calibrated = calibrated_pose.acceleration.x
# livePose acceleration can be noisy due to bad mounting or aliased livePose measurements
accel_valid = abs(CS.aEgo - accel_calibrated) < 2
excessive_actuation = accel_calibrated > ACCEL_MAX * 2 or accel_calibrated < ACCEL_MIN * 2
counter = counter + 1 if sm['carControl'].longActive and excessive_actuation and accel_valid else 0
return counter, counter > MIN_EXCESSIVE_ACTUATION_COUNT
class SelfdriveD(CruiseHelper):
def __init__(self, CP=None, CP_SP=None):
self.params = Params()
@@ -85,7 +69,11 @@ class SelfdriveD(CruiseHelper):
self.CP_SP = CP_SP
self.car_events = CarSpecificEvents(self.CP)
self.calibrator = PoseCalibrator()
self.pose_calibrator = PoseCalibrator()
self.calibrated_pose: Pose | None = None
self.excessive_actuation_check = ExcessiveActuationCheck()
self.excessive_actuation = self.params.get("Offroad_ExcessiveActuation") is not None
# Setup sockets
self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents'] + ['selfdriveStateSP', 'onroadEventsSP'])
@@ -98,7 +86,7 @@ class SelfdriveD(CruiseHelper):
# TODO: de-couple selfdrived with card/conflate on carState without introducing controls mismatches
self.car_state_sock = messaging.sub_sock('carState', timeout=20)
ignore = self.sensor_packets + self.gps_packets + ['alertDebug']
ignore = self.sensor_packets + self.gps_packets + ['alertDebug'] + ['modelDataV2SP']
if SIMULATION:
ignore += ['driverCameraState', 'managerState']
if REPLAY:
@@ -107,8 +95,8 @@ class SelfdriveD(CruiseHelper):
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'livePose', 'liveDelay',
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userFlag'] + \
self.camera_packets + self.sensor_packets + self.gps_packets,
'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userBookmark', 'audioFeedback'] + \
self.camera_packets + self.sensor_packets + self.gps_packets + ['modelDataV2SP', 'longitudinalPlanSP'],
ignore_alive=ignore, ignore_avg_freq=ignore,
ignore_valid=ignore, frequency=int(1/DT_CTRL))
@@ -143,18 +131,10 @@ class SelfdriveD(CruiseHelper):
self.experimental_mode = False
self.personality = self.params.get("LongitudinalPersonality", return_default=True)
self.recalibrating_seen = False
self.excessive_actuation = self.params.get("Offroad_ExcessiveActuation") is not None
self.excessive_actuation_counter = 0
self.state_machine = StateMachine()
self.rk = Ratekeeper(100, print_delay_threshold=None)
# some comma three with NVMe experience NVMe dropouts mid-drive that
# cause loggerd to crash on write, so ignore it only on that platform
self.ignored_processes = set()
nvme_expected = os.path.exists('/dev/nvme0n1') or (not os.path.isfile("/persist/comma/living-in-the-moment"))
if HARDWARE.get_device_type() == 'tici' and nvme_expected:
self.ignored_processes = {'loggerd', }
self.ignored_processes.update({'mapd'})
self.ignored_processes = {'mapd', }
# Determine startup event
is_remote = build_metadata.openpilot.comma_remote or build_metadata.openpilot.sunnypilot_remote
@@ -176,6 +156,7 @@ class SelfdriveD(CruiseHelper):
self.events_sp_prev = []
self.mads = ModularAssistiveDrivingSystem(self)
self.icbm = IntelligentCruiseButtonManagement(self.CP, self.CP_SP)
self.car_events_sp = CarSpecificEventsSP(self.CP, self.params)
@@ -205,9 +186,12 @@ class SelfdriveD(CruiseHelper):
self.events.add(EventName.selfdriveInitializing)
return
# Check for user flag (bookmark) press
if self.sm.updated['userFlag']:
self.events.add(EventName.userFlag)
# Check for user bookmark press (bookmark button or end of LKAS button feedback)
if self.sm.updated['userBookmark']:
self.events.add(EventName.userBookmark)
if self.sm.updated['audioFeedback']:
self.events.add(EventName.audioFeedback)
# Don't add any more events while in dashcam mode
if self.CP.passive:
@@ -220,6 +204,7 @@ class SelfdriveD(CruiseHelper):
if not self.CP.notCar:
self.events.add_from_msg(self.sm['driverMonitoringState'].events)
self.events_sp.add_from_msg(self.sm['longitudinalPlanSP'].events)
# Add car events, ignore if CAN isn't valid
if CS.canValid:
@@ -276,17 +261,25 @@ class SelfdriveD(CruiseHelper):
if self.sm['driverAssistance'].leftLaneDeparture or self.sm['driverAssistance'].rightLaneDeparture:
self.events.add(EventName.ldw)
# Check for excessive (longitudinal) actuation
# ******************************************************************************************
# NOTE: To fork maintainers.
# Disabling or nerfing safety features will get you and your users banned from our servers.
# We recommend that you do not change these numbers from the defaults.
if self.sm.updated['liveCalibration']:
self.calibrator.feed_live_calib(self.sm['liveCalibration'])
self.pose_calibrator.feed_live_calib(self.sm['liveCalibration'])
if self.sm.updated['livePose']:
device_pose = Pose.from_live_pose(self.sm['livePose'])
self.calibrated_pose = self.pose_calibrator.build_calibrated_pose(device_pose)
self.excessive_actuation_counter, excessive_actuation = check_excessive_actuation(self.sm, CS, self.calibrator, self.excessive_actuation_counter)
if not self.excessive_actuation and excessive_actuation:
set_offroad_alert("Offroad_ExcessiveActuation", True, extra_text="longitudinal")
self.excessive_actuation = True
if self.calibrated_pose is not None:
excessive_actuation = self.excessive_actuation_check.update(self.sm, CS, self.calibrated_pose)
if not self.excessive_actuation and excessive_actuation is not None:
set_offroad_alert("Offroad_ExcessiveActuation", True, extra_text=str(excessive_actuation))
self.excessive_actuation = True
if self.excessive_actuation:
self.events.add(EventName.excessiveActuation)
# ******************************************************************************************
# Handle lane change
if self.sm['modelV2'].meta.laneChangeState == LaneChangeState.preLaneChange:
@@ -303,6 +296,13 @@ class SelfdriveD(CruiseHelper):
LaneChangeState.laneChangeFinishing):
self.events.add(EventName.laneChange)
# Handle lane turn
lane_turn_direction = self.sm['modelDataV2SP'].laneTurnDirection
if lane_turn_direction == custom.TurnDirection.turnLeft:
self.events_sp.add(custom.OnroadEventSP.EventName.laneTurnLeft)
elif lane_turn_direction == custom.TurnDirection.turnRight:
self.events_sp.add(custom.OnroadEventSP.EventName.laneTurnRight)
for i, pandaState in enumerate(self.sm['pandaStates']):
# All pandas must match the list of safetyConfigs, and if outside this list, must be silent or noOutput
if i < len(self.CP.safetyConfigs):
@@ -339,13 +339,12 @@ class SelfdriveD(CruiseHelper):
self.events.add(EventName.cameraFrameRate)
if not REPLAY and self.rk.lagging:
self.events.add(EventName.selfdrivedLagging)
if not self.sm.valid['radarState']:
if self.sm['radarState'].radarErrors.canError:
self.events.add(EventName.canError)
elif self.sm['radarState'].radarErrors.radarUnavailableTemporary:
self.events.add(EventName.radarTempUnavailable)
else:
self.events.add(EventName.radarFault)
if self.sm['radarState'].radarErrors.canError:
self.events.add(EventName.canError)
elif self.sm['radarState'].radarErrors.radarUnavailableTemporary:
self.events.add(EventName.radarTempUnavailable)
elif any(self.sm['radarState'].radarErrors.to_dict().values()):
self.events.add(EventName.radarFault)
if not self.sm.valid['pandaStates']:
self.events.add(EventName.usbError)
if CS.canTimeout:
@@ -445,6 +444,8 @@ class SelfdriveD(CruiseHelper):
self.events.add(EventName.personalityChanged)
self.experimental_mode_switched = False
self.icbm.run(CS, self.sm['carControl'], self.is_metric)
def data_sample(self):
_car_state = messaging.recv_one(self.car_state_sock)
CS = _car_state.carState if _car_state else self.CS_prev
@@ -549,6 +550,11 @@ class SelfdriveD(CruiseHelper):
mads.active = self.mads.active
mads.available = self.mads.enabled_toggle
icbm = ss_sp.intelligentCruiseButtonManagement
icbm.state = self.icbm.state
icbm.sendButton = self.icbm.cruise_button
icbm.vTarget = self.icbm.v_target
self.pm.send('selfdriveStateSP', ss_sp_msg)
# onroadEventsSP - logged every second or on change

View File

@@ -67,6 +67,9 @@ class Plant:
lp = messaging.new_message('liveParameters')
car_control = messaging.new_message('carControl')
model = messaging.new_message('modelV2')
car_state_sp = messaging.new_message('carStateSP')
live_map_data_sp = messaging.new_message('liveMapDataSP')
gps_data = messaging.new_message('gpsLocation')
a_lead = (v_lead - self.v_lead_prev)/self.ts
self.v_lead_prev = v_lead
@@ -133,7 +136,10 @@ class Plant:
'controlsState': control.controlsState,
'selfdriveState': ss.selfdriveState,
'liveParameters': lp.liveParameters,
'modelV2': model.modelV2}
'modelV2': model.modelV2,
'carStateSP': car_state_sp.carStateSP,
'liveMapDataSP': live_map_data_sp.liveMapDataSP,
'gpsLocation': gps_data.gpsLocation}
self.planner.update(sm)
self.acceleration = self.planner.output_a_target
self.speed = self.speed + self.acceleration * self.ts

View File

@@ -4,8 +4,9 @@ import time
import copy
import heapq
import signal
from collections import Counter, OrderedDict
from collections import Counter
from dataclasses import dataclass, field
from itertools import islice
from typing import Any
from collections.abc import Callable, Iterable
from tqdm import tqdm
@@ -16,12 +17,13 @@ import cereal.messaging as messaging
from cereal import car
from cereal.services import SERVICE_LIST
from msgq.visionipc import VisionIpcServer, get_endpoint_name as vipc_get_endpoint_name
from opendbc.car.can_definitions import CanData
from opendbc.car.car_helpers import get_car, interfaces
from openpilot.common.params import Params
from openpilot.common.prefix import OpenpilotPrefix
from openpilot.common.timeout import Timeout
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.car.card import can_comm_callbacks, convert_to_capnp
from openpilot.selfdrive.car.card import convert_to_capnp
from openpilot.system.manager.process_config import managed_processes
from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams
from openpilot.selfdrive.test.process_replay.migration import migrate_all
@@ -30,22 +32,10 @@ from openpilot.tools.lib.logreader import LogIterable
from openpilot.tools.lib.framereader import FrameReader
# Numpy gives different results based on CPU features after version 19
NUMPY_TOLERANCE = 1e-7
NUMPY_TOLERANCE = 1e-2
PROC_REPLAY_DIR = os.path.dirname(os.path.abspath(__file__))
FAKEDATA = os.path.join(PROC_REPLAY_DIR, "fakedata/")
class DummySocket:
def __init__(self):
self.data: list[bytes] = []
def receive(self, non_blocking: bool = False) -> bytes | None:
if non_blocking:
return None
return self.data.pop()
def send(self, data: bytes):
self.data.append(data)
class LauncherWithCapture:
def __init__(self, capture: ProcessOutputCapture, launcher: Callable):
@@ -63,8 +53,7 @@ class ReplayContext:
self.pubs = cfg.pubs
self.main_pub = cfg.main_pub
self.main_pub_drained = cfg.main_pub_drained
self.unlocked_pubs = cfg.unlocked_pubs
assert(len(self.pubs) != 0 or self.main_pub is not None)
assert len(self.pubs) != 0 or self.main_pub is not None
def __enter__(self):
self.open_context()
@@ -79,9 +68,8 @@ class ReplayContext:
messaging.set_fake_prefix(self.proc_name)
if self.main_pub is None:
self.events = OrderedDict()
pubs_with_events = [pub for pub in self.pubs if pub not in self.unlocked_pubs]
for pub in pubs_with_events:
self.events = {}
for pub in self.pubs:
self.events[pub] = messaging.fake_event_handle(pub, enable=True)
else:
self.events = {self.main_pub: messaging.fake_event_handle(self.main_pub, enable=True)}
@@ -138,16 +126,21 @@ class ProcessConfig:
processing_time: float = 0.001
timeout: int = 30
simulation: bool = True
# Set to service process receives on first
main_pub: str | None = None
main_pub_drained: bool = True
main_pub_drained: bool = False
vision_pubs: list[str] = field(default_factory=list)
ignore_alive_pubs: list[str] = field(default_factory=list)
unlocked_pubs: list[str] = field(default_factory=list)
def __post_init__(self):
# If the process is polling a service, we can just lock that one to speed up replay
if self.main_pub is None and isinstance(self.should_recv_callback, MessageBasedRcvCallback):
self.main_pub = self.should_recv_callback.trigger_msg_type
class ProcessContainer:
def __init__(self, cfg: ProcessConfig):
self.prefix = OpenpilotPrefix(clean_dirs_on_exit=False)
self.prefix = OpenpilotPrefix(create_dirs_on_enter=False, clean_dirs_on_exit=False)
self.cfg = copy.deepcopy(cfg)
self.process = copy.deepcopy(managed_processes[cfg.proc_name])
self.msg_queue: list[capnp._DynamicStructReader] = []
@@ -229,6 +222,7 @@ class ProcessContainer:
fingerprint: str | None, capture_output: bool
):
with self.prefix as p:
self.prefix.create_dirs()
self._setup_env(params_config, environ_config)
if self.cfg.config_callback is not None:
@@ -254,11 +248,6 @@ class ProcessContainer:
if self.cfg.init_callback is not None:
self.cfg.init_callback(self.rc, self.pm, all_msgs, fingerprint)
# wait for process to startup
with Timeout(10, error_msg=f"timed out waiting for process to start: {repr(self.cfg.proc_name)}"):
while not all(self.pm.all_readers_updated(s) for s in self.cfg.pubs if s not in self.cfg.ignore_alive_pubs):
time.sleep(0)
def stop(self):
with self.prefix:
self.process.signal(signal.SIGKILL)
@@ -267,28 +256,42 @@ class ProcessContainer:
self.prefix.clean_dirs()
self._clean_env()
def get_output_msgs(self, start_time: int):
assert self.rc and self.sockets
output_msgs = []
self.rc.wait_for_recv_called()
for socket in self.sockets:
ms = messaging.drain_sock(socket)
for m in ms:
m = m.as_builder()
m.logMonoTime = start_time + int(self.cfg.processing_time * 1e9)
output_msgs.append(m.as_reader())
return output_msgs
def run_step(self, msg: capnp._DynamicStructReader, frs: dict[str, FrameReader] | None) -> list[capnp._DynamicStructReader]:
assert self.rc and self.pm and self.sockets and self.process.proc
output_msgs = []
with self.prefix, Timeout(self.cfg.timeout, error_msg=f"timed out testing process {repr(self.cfg.proc_name)}"):
end_of_cycle = True
if self.cfg.should_recv_callback is not None:
end_of_cycle = self.cfg.should_recv_callback(msg, self.cfg, self.cnt)
self.msg_queue.append(msg)
if end_of_cycle:
self.rc.wait_for_recv_called()
end_of_cycle = True
if self.cfg.should_recv_callback is not None:
end_of_cycle = self.cfg.should_recv_callback(msg, self.cfg, self.cnt)
self.msg_queue.append(msg)
if end_of_cycle:
with self.prefix, Timeout(self.cfg.timeout, error_msg=f"timed out testing process {repr(self.cfg.proc_name)}"):
# call recv to let sub-sockets reconnect, after we know the process is ready
if self.cnt == 0:
for s in self.sockets:
messaging.recv_one_or_none(s)
# empty recv on drained pub indicates the end of messages, only do that if there're any
# certain processes use drain_sock. need to cause empty recv to break from this loop
trigger_empty_recv = False
if self.cfg.main_pub and self.cfg.main_pub_drained:
trigger_empty_recv = next((True for m in self.msg_queue if m.which() == self.cfg.main_pub), False)
trigger_empty_recv = any(m.which() == self.cfg.main_pub for m in self.msg_queue)
# get output msgs from previous inputs
output_msgs = self.get_output_msgs(msg.logMonoTime)
for m in self.msg_queue:
self.pm.send(m.which(), m.as_builder())
@@ -303,14 +306,8 @@ class ProcessContainer:
self.msg_queue = []
self.rc.unlock_sockets()
self.rc.wait_for_next_recv(trigger_empty_recv)
for socket in self.sockets:
ms = messaging.drain_sock(socket)
for m in ms:
m = m.as_builder()
m.logMonoTime = msg.logMonoTime + int(self.cfg.processing_time * 1e9)
output_msgs.append(m.as_reader())
if trigger_empty_recv:
self.rc.unlock_sockets()
self.cnt += 1
assert self.process.proc.is_alive()
@@ -320,7 +317,7 @@ class ProcessContainer:
def card_fingerprint_callback(rc, pm, msgs, fingerprint):
print("start fingerprinting")
params = Params()
canmsgs = [msg for msg in msgs if msg.which() == "can"][:300]
canmsgs = list(islice((m for m in msgs if m.which() == "can"), 300))
# card expects one arbitrary can and pandaState
rc.send_sync(pm, "can", messaging.new_message("can", 1))
@@ -345,36 +342,27 @@ def get_car_params_callback(rc, pm, msgs, fingerprint):
CP = CarInterface.get_non_essential_params(fingerprint)
CP_SP = CarInterface.get_non_essential_params_sp(CP, fingerprint)
else:
can = DummySocket()
sendcan = DummySocket()
canmsgs = [msg for msg in msgs if msg.which() == "can"]
can_msgs = ([CanData(can.address, can.dat, can.src) for can in m.can] for m in msgs if m.which() == "can")
cached_params_raw = params.get("CarParamsCache")
has_cached_cp = cached_params_raw is not None
assert len(canmsgs) != 0, "CAN messages are required for fingerprinting"
assert os.environ.get("SKIP_FW_QUERY", False) or has_cached_cp, \
assert next(can_msgs, None), "CAN messages are required for fingerprinting"
assert os.environ.get("SKIP_FW_QUERY", False) or cached_params_raw is not None, \
"CarParamsCache is required for fingerprinting. Make sure to keep carParams msgs in the logs."
for m in canmsgs[:300]:
can.send(m.as_builder().to_bytes())
can_callbacks = can_comm_callbacks(can, sendcan)
def can_recv(wait_for_one: bool = False) -> list[list[CanData]]:
return [next(can_msgs, [])]
cached_params = None
if has_cached_cp:
if cached_params_raw is not None:
with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
cached_params = _cached_params
_CI = get_car(*can_callbacks, lambda obd: None, Params().get_bool("AlphaLongitudinalEnabled"), False, cached_params=cached_params)
_CI = get_car(can_recv, lambda _msgs: None, lambda obd: None, params.get_bool("AlphaLongitudinalEnabled"), False, cached_params=cached_params)
CP, CP_SP = _CI.CP, _CI.CP_SP
params.put("CarParams", CP.to_bytes())
params.put("CarParamsSP", convert_to_capnp(CP_SP).to_bytes())
def selfdrived_rcv_callback(msg, cfg, frame):
return (frame - 1) == 0 or msg.which() == 'carState'
def card_rcv_callback(msg, cfg, frame):
# no sendcan until card is initialized
if msg.which() != "can":
@@ -389,21 +377,6 @@ def card_rcv_callback(msg, cfg, frame):
return len(socks) > 0
def calibration_rcv_callback(msg, cfg, frame):
# calibrationd publishes 1 calibrationData every 5 cameraOdometry packets.
# should_recv always true to increment frame
return (frame - 1) == 0 or msg.which() == 'cameraOdometry'
def torqued_rcv_callback(msg, cfg, frame):
# should_recv always true to increment frame
return (frame - 1) == 0 or msg.which() == 'livePose'
def dmonitoringmodeld_rcv_callback(msg, cfg, frame):
return msg.which() == "driverCameraState"
class ModeldCameraSyncRcvCallback:
def __init__(self):
self.road_present = False
@@ -428,26 +401,13 @@ class ModeldCameraSyncRcvCallback:
class MessageBasedRcvCallback:
def __init__(self, trigger_msg_type):
def __init__(self, trigger_msg_type: str, first_frame: bool = False):
self.trigger_msg_type = trigger_msg_type
self.first_frame = first_frame
def __call__(self, msg, cfg, frame):
return msg.which() == self.trigger_msg_type
class FrequencyBasedRcvCallback:
def __init__(self, trigger_msg_type):
self.trigger_msg_type = trigger_msg_type
def __call__(self, msg, cfg, frame):
if msg.which() != self.trigger_msg_type:
return False
resp_sockets = [
s for s in cfg.subs
if frame % max(1, int(SERVICE_LIST[msg.which()].frequency / SERVICE_LIST[s].frequency)) == 0
]
return bool(len(resp_sockets))
# publish on first frame or trigger msg
return ((frame - 1) == 0 and self.first_frame) or msg.which() == self.trigger_msg_type
def selfdrived_config_callback(params, cfg, lr):
@@ -462,16 +422,16 @@ CONFIGS = [
proc_name="selfdrived",
pubs=[
"carState", "deviceState", "pandaStates", "peripheralState", "liveCalibration", "driverMonitoringState",
"longitudinalPlan", "livePose", "liveDelay", "liveParameters", "radarState",
"modelV2", "driverCameraState", "roadCameraState", "wideRoadCameraState", "managerState",
"liveTorqueParameters", "accelerometer", "gyroscope", "carOutput",
"gpsLocationExternal", "gpsLocation", "controlsState", "carControl", "driverAssistance", "alertDebug",
"longitudinalPlan", "livePose", "liveDelay", "liveParameters", "radarState", "modelV2",
"driverCameraState", "roadCameraState", "wideRoadCameraState", "managerState", "liveTorqueParameters",
"accelerometer", "gyroscope", "carOutput", "gpsLocationExternal", "gpsLocation", "controlsState",
"carControl", "driverAssistance", "alertDebug", "audioFeedback",
],
subs=["selfdriveState", "onroadEvents"],
ignore=["logMonoTime"],
config_callback=selfdrived_config_callback,
init_callback=get_car_params_callback,
should_recv_callback=selfdrived_rcv_callback,
should_recv_callback=MessageBasedRcvCallback("carState", True),
tolerance=NUMPY_TOLERANCE,
processing_time=0.004,
),
@@ -496,6 +456,7 @@ CONFIGS = [
tolerance=NUMPY_TOLERANCE,
processing_time=0.004,
main_pub="can",
main_pub_drained=True,
),
ProcessConfig(
proc_name="radard",
@@ -503,7 +464,7 @@ CONFIGS = [
subs=["radarState"],
ignore=["logMonoTime"],
init_callback=get_car_params_callback,
should_recv_callback=FrequencyBasedRcvCallback("modelV2"),
should_recv_callback=MessageBasedRcvCallback("modelV2"),
),
ProcessConfig(
proc_name="plannerd",
@@ -511,7 +472,7 @@ CONFIGS = [
subs=["longitudinalPlan", "driverAssistance"],
ignore=["logMonoTime", "longitudinalPlan.processingDelay", "longitudinalPlan.solverExecutionTime"],
init_callback=get_car_params_callback,
should_recv_callback=FrequencyBasedRcvCallback("modelV2"),
should_recv_callback=MessageBasedRcvCallback("modelV2"),
tolerance=NUMPY_TOLERANCE,
),
ProcessConfig(
@@ -520,14 +481,14 @@ CONFIGS = [
subs=["liveCalibration"],
ignore=["logMonoTime"],
init_callback=get_car_params_callback,
should_recv_callback=calibration_rcv_callback,
should_recv_callback=MessageBasedRcvCallback("cameraOdometry", True),
),
ProcessConfig(
proc_name="dmonitoringd",
pubs=["driverStateV2", "liveCalibration", "carState", "modelV2", "selfdriveState"],
subs=["driverMonitoringState"],
ignore=["logMonoTime"],
should_recv_callback=FrequencyBasedRcvCallback("driverStateV2"),
should_recv_callback=MessageBasedRcvCallback("driverStateV2"),
tolerance=NUMPY_TOLERANCE,
),
ProcessConfig(
@@ -539,7 +500,6 @@ CONFIGS = [
ignore=["logMonoTime"],
should_recv_callback=MessageBasedRcvCallback("cameraOdometry"),
tolerance=NUMPY_TOLERANCE,
unlocked_pubs=["accelerometer", "gyroscope"],
),
ProcessConfig(
proc_name="paramsd",
@@ -547,7 +507,7 @@ CONFIGS = [
subs=["liveParameters"],
ignore=["logMonoTime"],
init_callback=get_car_params_callback,
should_recv_callback=FrequencyBasedRcvCallback("livePose"),
should_recv_callback=MessageBasedRcvCallback("livePose"),
tolerance=NUMPY_TOLERANCE,
processing_time=0.004,
),
@@ -572,7 +532,7 @@ CONFIGS = [
subs=["liveTorqueParameters"],
ignore=["logMonoTime"],
init_callback=get_car_params_callback,
should_recv_callback=torqued_rcv_callback,
should_recv_callback=MessageBasedRcvCallback("livePose", True),
tolerance=NUMPY_TOLERANCE,
),
ProcessConfig(
@@ -584,7 +544,6 @@ CONFIGS = [
tolerance=NUMPY_TOLERANCE,
processing_time=0.020,
main_pub=vipc_get_endpoint_name("camerad", meta_from_camera_state("roadCameraState").stream),
main_pub_drained=False,
vision_pubs=["roadCameraState", "wideRoadCameraState"],
ignore_alive_pubs=["wideRoadCameraState"],
init_callback=get_car_params_callback,
@@ -594,11 +553,10 @@ CONFIGS = [
pubs=["liveCalibration", "driverCameraState"],
subs=["driverStateV2"],
ignore=["logMonoTime", "driverStateV2.modelExecutionTime", "driverStateV2.gpuExecutionTime"],
should_recv_callback=dmonitoringmodeld_rcv_callback,
should_recv_callback=MessageBasedRcvCallback("driverCameraState"),
tolerance=NUMPY_TOLERANCE,
processing_time=0.020,
main_pub=vipc_get_endpoint_name("camerad", meta_from_camera_state("driverCameraState").stream),
main_pub_drained=False,
vision_pubs=["driverCameraState"],
ignore_alive_pubs=["driverCameraState"],
),
@@ -637,7 +595,7 @@ def get_custom_params_from_lr(lr: LogIterable, initial_state: str = "first") ->
if len(live_calibration) > 0:
custom_params["CalibrationParams"] = live_calibration[msg_index].as_builder().to_bytes()
if len(live_parameters) > 0:
custom_params["LiveParameters"] = live_parameters[msg_index].as_builder().to_bytes()
custom_params["LiveParametersV2"] = live_parameters[msg_index].as_builder().to_bytes()
if len(live_torque_parameters) > 0:
custom_params["LiveTorqueParameters"] = live_torque_parameters[msg_index].as_builder().to_bytes()
@@ -706,8 +664,8 @@ def _replay_multi_process(
all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime)
log_msgs = []
containers = []
try:
containers = []
for cfg in cfgs:
container = ProcessContainer(cfg)
containers.append(container)
@@ -742,6 +700,11 @@ def _replay_multi_process(
internal_pub_queue.append(m)
heapq.heappush(internal_pub_index_heap, (m.logMonoTime, len(internal_pub_queue) - 1))
log_msgs.extend(output_msgs)
# flush last set of messages from each process
for container in containers:
last_time = log_msgs[-1].logMonoTime if len(log_msgs) > 0 else int(time.monotonic() * 1e9)
log_msgs.extend(container.get_output_msgs(last_time))
finally:
for container in containers:
container.stop()

View File

@@ -1 +1 @@
c289a0359d1b1f26cf4d9e73a2c04b2bbfec840f
afcab1abb62b9d5678342956cced4712f44e909e

View File

@@ -63,7 +63,7 @@ segments = [
]
# dashcamOnly makes don't need to be tested until a full port is done
excluded_interfaces = ["mock", "body"]
excluded_interfaces = ["mock", "body", "psa"]
BASE_URL = "https://commadataci.blob.core.windows.net/openpilotci/"
REF_COMMIT_FN = os.path.join(PROC_REPLAY_DIR, "ref_commit")

View File

@@ -54,6 +54,7 @@ while true; do
# /data/ciui.py &
#fi
awk '{print \$1}' /proc/uptime > /var/tmp/power_watchdog
sleep 5s
done

View File

@@ -18,7 +18,6 @@ from openpilot.common.timeout import Timeout
from openpilot.common.params import Params
from openpilot.selfdrive.selfdrived.events import EVENTS, ET
from openpilot.selfdrive.test.helpers import set_params_enabled, release_only
from openpilot.system.hardware import HARDWARE
from openpilot.system.hardware.hw import Paths
from openpilot.tools.lib.logreader import LogReader
from openpilot.tools.lib.log_time_series import msgs_to_time_series
@@ -33,7 +32,7 @@ CPU usage budget
TEST_DURATION = 25
LOG_OFFSET = 8
MAX_TOTAL_CPU = 280. # total for all 8 cores
MAX_TOTAL_CPU = 300. # total for all 8 cores
PROCS = {
# Baseline CPU usage by process
"selfdrive.controls.controlsd": 16.0,
@@ -55,31 +54,22 @@ PROCS = {
"selfdrive.locationd.paramsd": 9.0,
"selfdrive.locationd.lagd": 11.0,
"selfdrive.ui.soundd": 3.0,
"selfdrive.ui.feedback.feedbackd": 1.0,
"selfdrive.monitoring.dmonitoringd": 4.0,
"./proclogd": 2.0,
"system.proclogd": 3.0,
"system.logmessaged": 1.0,
"system.tombstoned": 0,
"./logcatd": 1.0,
"system.journald": 1.0,
"system.micd": 5.0,
"system.timed": 0,
"selfdrive.pandad.pandad": 0,
"system.statsd": 1.0,
"system.loggerd.uploader": 15.0,
"system.loggerd.deleter": 1.0,
"./pandad": 19.0,
"system.qcomgpsd.qcomgpsd": 1.0,
}
PROCS.update({
"tici": {
"./pandad": 5.0,
"./ubloxd": 1.0,
"system.ubloxd.pigeond": 6.0,
},
"tizi": {
"./pandad": 19.0,
"system.qcomgpsd.qcomgpsd": 1.0,
}
}.get(HARDWARE.get_device_type(), {}))
TIMINGS = {
# rtols: max/min, rsd
"can": [2.5, 0.35],
@@ -332,20 +322,18 @@ class TestOnroad:
assert np.all(eof_sof_diff > 0)
assert np.all(eof_sof_diff < 50*1e6)
first_fid = {c: min(self.ts[c]['frameId']) for c in cams}
first_fid = {min(self.ts[c]['frameId']) for c in cams}
assert len(first_fid) == 1, "Cameras don't start on same frame ID"
if cam.endswith('CameraState'):
# camerad guarantees that all cams start on frame ID 0
# (note loggerd also needs to start up fast enough to catch it)
assert set(first_fid.values()) == {0, }, "Cameras don't start on frame ID 0"
else:
# encoder guarantees all cams start on the same frame ID
assert len(set(first_fid.values())) == 1, "Cameras don't start on same frame ID"
assert next(iter(first_fid)) < 100, "Cameras start on frame ID too high"
# we don't do a full segment rotation, so these might not match exactly
last_fid = {c: max(self.ts[c]['frameId']) for c in cams}
assert max(last_fid.values()) - min(last_fid.values()) < 10
last_fid = {max(self.ts[c]['frameId']) for c in cams}
assert max(last_fid) - min(last_fid) < 10
start, end = min(first_fid.values()), min(last_fid.values())
start, end = min(first_fid), min(last_fid)
for i in range(end-start):
ts = {c: round(self.ts[c]['timestampSof'][i]/1e6, 1) for c in cams}
diff = (max(ts.values()) - min(ts.values()))

View File

@@ -70,14 +70,8 @@ if GetOption('extras'):
qt_src.remove("main.cc") # replaced by test_runner
qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs)
qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs)
# setup
qt_env.Program("qt/setup/setup", ["qt/setup/setup.cc", asset_obj],
LIBS=qt_libs + ['curl', 'common'])
# build installers
if arch != "Darwin":
# build installers
raylib_env = env.Clone()
raylib_env['LIBPATH'] += [f'#third_party/raylib/{arch}/']
raylib_env['LINKFLAGS'].append('-Wl,-strip-debug')
@@ -109,7 +103,3 @@ if GetOption('extras'):
f = raylib_env.Program(f"installer/installers/installer_{name}", [obj, cont, inter], LIBS=raylib_libs)
# keep installers small
assert f[0].get_size() < 1900*1e3, f[0].get_size()
# build watch3
if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'):
qt_env.Program("watch3", ["watch3.cc"], LIBS=qt_libs + ['common', 'msgq', 'visionipc'])

View File

@@ -0,0 +1,72 @@
#!/usr/bin/env python3
import cereal.messaging as messaging
from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog
from cereal import car
from openpilot.system.micd import SAMPLE_RATE, SAMPLE_BUFFER
FEEDBACK_MAX_DURATION = 10.0
ButtonType = car.CarState.ButtonEvent.Type
def main():
params = Params()
pm = messaging.PubMaster(['userBookmark', 'audioFeedback'])
sm = messaging.SubMaster(['rawAudioData', 'bookmarkButton', 'carState', 'selfdriveStateSP'])
should_record_audio = False
block_num = 0
waiting_for_release = False
early_stop_triggered = False
while True:
sm.update()
should_send_bookmark = False
# TODO: https://github.com/commaai/openpilot/issues/36015
# only allow the LKAS button to record feedback when MADS is disabled
if False and sm.updated['carState'] and sm['carState'].canValid and not sm['selfdriveStateSP'].mads.available:
for be in sm['carState'].buttonEvents:
if be.type == ButtonType.lkas:
if be.pressed:
if not should_record_audio:
if params.get_bool("RecordAudioFeedback"): # Start recording on first press if toggle set
should_record_audio = True
block_num = 0
waiting_for_release = False
early_stop_triggered = False
cloudlog.info("LKAS button pressed - starting 10-second audio feedback")
else:
should_send_bookmark = True # immediately send bookmark if toggle false
cloudlog.info("LKAS button pressed - bookmarking")
elif should_record_audio and not waiting_for_release: # Wait for release of second press to stop recording early
waiting_for_release = True
elif waiting_for_release: # Second press released
waiting_for_release = False
early_stop_triggered = True
cloudlog.info("LKAS button released - ending recording early")
if should_record_audio and sm.updated['rawAudioData']:
raw_audio = sm['rawAudioData']
msg = messaging.new_message('audioFeedback', valid=True)
msg.audioFeedback.audio.data = raw_audio.data
msg.audioFeedback.audio.sampleRate = raw_audio.sampleRate
msg.audioFeedback.blockNum = block_num
block_num += 1
if (block_num * SAMPLE_BUFFER / SAMPLE_RATE) >= FEEDBACK_MAX_DURATION or early_stop_triggered: # Check for timeout or early stop
should_send_bookmark = True # send bookmark at end of audio segment
should_record_audio = False
early_stop_triggered = False
cloudlog.info("10-second recording completed or second button press - stopping audio feedback")
pm.send('audioFeedback', msg)
if sm.updated['bookmarkButton']:
cloudlog.info("Bookmark button pressed!")
should_send_bookmark = True
if should_send_bookmark:
msg = messaging.new_message('userBookmark', valid=True)
pm.send('userBookmark', msg)
if __name__ == '__main__':
main()

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