Compare commits
564 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0acc54adc4 | |||
| d75a149266 | |||
| a1fc8dd40a | |||
| 9a2c4f505c | |||
| fdf97f4ac7 | |||
| 1253cb9819 | |||
| 79e1fe4d68 | |||
| 41f1c5d067 | |||
| 764b41ec28 | |||
| 460107c089 | |||
| 7f86fef7c6 | |||
| be15b31696 | |||
| 8472ae5317 | |||
| 951d7e9cd0 | |||
| 3676ae4da3 | |||
| ae25a13594 | |||
| 1a202a55c1 | |||
| f55e6a3b81 | |||
| e2ec5be6ee | |||
| 7f35d0a909 | |||
| 1bade14fda | |||
| dd0c474e6c | |||
| e5fe1d2885 | |||
| ee716a6d9d | |||
| 1b82e77ed9 | |||
| 88dcaa51c4 | |||
| b9ad854451 | |||
| ac71c30ad5 | |||
| abf2801122 | |||
| 3d9b483e10 | |||
| 998eb8cde2 | |||
| 780f1222ad | |||
| f22b6681d6 | |||
| d574013d7b | |||
| a2028cbfd5 | |||
| ebc916e25c | |||
| 0234cadec3 | |||
| 65490bb3c5 | |||
| 35e1e8ecd2 | |||
| ea57336005 | |||
| 403610eed9 | |||
| 88757c12b3 | |||
| ee036482b8 | |||
| 827aa2e4fa | |||
| 389b8ca30d | |||
| caa9153974 | |||
| 694fc378dd | |||
| 3846130d8e | |||
| 7c9530f743 | |||
| 95d33164fd | |||
| 77d051f5ec | |||
| eb04935b95 | |||
| 0067cf3eb1 | |||
| 81516216b1 | |||
| 3b01733900 | |||
| 7ebd841a0b | |||
| 599325718e | |||
| 139b0ae3b6 | |||
| 74a2e3178f | |||
| b1f457bdc8 | |||
| 78e20cff39 | |||
| ec72cdca00 | |||
| e6c97c3846 | |||
| 2c86c023fe | |||
| e0d0896dcf | |||
| 332a21965d | |||
| dc9ffd2f10 | |||
| 5c2b7882bf | |||
| 7cd9568423 | |||
| 18467c8383 | |||
| 574fd03208 | |||
| 28028aef17 | |||
| c907dd9e70 | |||
| 8a26b4383f | |||
| f0f7e86dcc | |||
| bbbe94bc3e | |||
| 16cd20f4eb | |||
| f3689ef561 | |||
| a6695e4489 | |||
| dfb56abf91 | |||
| 35ed8a0886 | |||
| b4ebba384b | |||
| 7a6463b2b4 | |||
| e3b17d10f3 | |||
| ce947ffe9a | |||
| e2df83089f | |||
| c4362bd958 | |||
| 29536324c1 | |||
| 23cbfe9eb3 | |||
| 9ee0a8a2b1 | |||
| 00b5424407 | |||
| d98b33adc8 | |||
| 1c09ae99eb | |||
| 292f2ea288 | |||
| 5791afda15 | |||
| 2280ac50b7 | |||
| f96aa247cc | |||
| 005a6e4f17 | |||
| 19630c5af9 | |||
| 4c2bb9f380 | |||
| d36103791c | |||
| 840db1f1b7 | |||
| 5f1e7649e3 | |||
| 7ce29ef08e | |||
| 8c544d9139 | |||
| 0b5fd7287e | |||
| 3f0b56b364 | |||
| 5e4df41b2f | |||
| f6cd009c77 | |||
| 86ac700805 | |||
| c6c6a441eb | |||
| 60a4102892 | |||
| baa4e801fe | |||
| 49586fc30e | |||
| 1bf8e04f54 | |||
| b933825231 | |||
| 2967cada71 | |||
| 5c24527683 | |||
| 8a05d212ec | |||
| 61fe705160 | |||
| 7d400112df | |||
| 0739d5d7b2 | |||
| 4da8d16514 | |||
| 8e9be48b7b | |||
| e1a05deadd | |||
| 94cd4c9046 | |||
| a8afaf39d4 | |||
| a4fac38cf9 | |||
| f256225f29 | |||
| 4c6f7da404 | |||
| fe6aff0131 | |||
| e17e66180c | |||
| 3e601b5e8f | |||
| 66ddfece82 | |||
| 2f744f5df4 | |||
| 884de6e457 | |||
| dafde02da3 | |||
| f55d04c172 | |||
| 4178f7c1e1 | |||
| d39b31aed1 | |||
| 28e5d1bb49 | |||
| 3d73512c07 | |||
| 9f1b72ac79 | |||
| ba792d576a | |||
| 5da573ff39 | |||
| ef73ee7b37 | |||
| 96c91c486e | |||
| f2c73039d7 | |||
| e7657d896f | |||
| d7e7659852 | |||
| eb09294fc2 | |||
| 68bcb6b8da | |||
| 8d9e431f43 | |||
| 042ccb9244 | |||
| fb994ae782 | |||
| 7e9843b5e6 | |||
| f820b7cd94 | |||
| ed153141fc | |||
| 0320fb385a | |||
| be814ed447 | |||
| 32dfb3f8f2 | |||
| 3c74a61c97 | |||
| bef6d7f0bb | |||
| b92e71a2b6 | |||
| e9e8f4df38 | |||
| 3918039e29 | |||
| 1da08460cb | |||
| af1b7e5c59 | |||
| 576cba217d | |||
| cfb23eb2d1 | |||
| 926793b17f | |||
| 0d126e1e9e | |||
| db3ef3e1d8 | |||
| 61ebb5b668 | |||
| 4eba5fe68d | |||
| cd1d7eb4d2 | |||
| 221f81bbd3 | |||
| 2a074eefac | |||
| ca57d329e2 | |||
| af137bac58 | |||
| 1d370a0880 | |||
| d6cece756c | |||
| 88e445ef15 | |||
| 7fdd5c4a7d | |||
| 90010754d6 | |||
| c8df0bd1d0 | |||
| d689a4e653 | |||
| 5f191321fd | |||
| 6743487d78 | |||
| 91c5c5eca7 | |||
| 2a49f94872 | |||
| 073fc89ad4 | |||
| e867aa40db | |||
| 7997fccdfa | |||
| f0ccb84ae3 | |||
| 084871ed5b | |||
| 2378f311d2 | |||
| 03d6233743 | |||
| 4cc48b75e8 | |||
| 46f3fdc090 | |||
| 239b228ca6 | |||
| e86d74b347 | |||
| 15e0a906ad | |||
| 002ab5637b | |||
| 397c1e373c | |||
| 1148c65d23 | |||
| 63f0d775bc | |||
| 43b0b0f022 | |||
| e85e401d07 | |||
| 3c4150c542 | |||
| fe40905849 | |||
| ff0fed07ed | |||
| 28cf3155e2 | |||
| 115047d858 | |||
| 4430944b29 | |||
| 318d1204e5 | |||
| 17ac1d3c7b | |||
| 7f398e1cf9 | |||
| 8fbe382fa7 | |||
| 633fef5a96 | |||
| 8c4930d2d3 | |||
| de4bc31ba6 | |||
| 543cd4460a | |||
| 205a78f02d | |||
| 9b25bfc618 | |||
| 9cf57cc4e4 | |||
| 7e71fd7bae | |||
| 86bd337952 | |||
| fba521ecc6 | |||
| 9d7f618bc5 | |||
| 0f72467558 | |||
| 65ece2081a | |||
| 6ccf2cbfde | |||
| d3cdd837fa | |||
| eb805e889e | |||
| 331ea60422 | |||
| fd88990006 | |||
| a58baf48fe | |||
| 9520153b6a | |||
| d33c5bccc6 | |||
| 6810c5b644 | |||
| 4df85062c5 | |||
| a1f53c70e6 | |||
| ee3544d283 | |||
| 1f9970ba3d | |||
| 7638572e38 | |||
| 5e6290c4a2 | |||
| b38c580c2e | |||
| cfc85f016b | |||
| a6b17fb1f6 | |||
| abe4780fdb | |||
| 33e7baee40 | |||
| 3d8c78d6b3 | |||
| 05dc0b51e6 | |||
| 3713e4d5ea | |||
| adb04b5dc5 | |||
| 1a165c6580 | |||
| 426072bd87 | |||
| 5f04517677 | |||
| 8017c25f0b | |||
| 3646ca0a14 | |||
| adca970ca9 | |||
| 5052b55c44 | |||
| 10b3a22897 | |||
| cee84381f3 | |||
| b0b4ae9c15 | |||
| 28eed156e0 | |||
| b9080d2362 | |||
| ab0b26d2b8 | |||
| 846be323d5 | |||
| 51a93cf9aa | |||
| 70624ffc81 | |||
| 8c1176ca83 | |||
| b75cdd1542 | |||
| 2c30421b16 | |||
| 77bafb0708 | |||
| 1421551297 | |||
| 7aeefaad65 | |||
| a07060b24b | |||
| 4b54c0b3cd | |||
| 2d466e70cd | |||
| 1346704426 | |||
| 7f9e41ce2e | |||
| bc54ed794b | |||
| 6239cf6780 | |||
| a7828eba3c | |||
| dfa2e9146f | |||
| ea7e701052 | |||
| f9ee7bff00 | |||
| cb53e6579f | |||
| d9a8846d58 | |||
| 123ef46af3 | |||
| 1ca1cf3922 | |||
| 1733b04741 | |||
| 6f143f6c45 | |||
| d6eb1265a0 | |||
| 37351cbdc1 | |||
| 10ea451831 | |||
| da12a34ff6 | |||
| 5fe9f1459c | |||
| 0830f62b36 | |||
| 2cad6dfa58 | |||
| 05d5056e8c | |||
| 303f1cf9cf | |||
| 977dd033c4 | |||
| 23c20bce8f | |||
| 5d668701cb | |||
| 582743fdb5 | |||
| 5b909c7d52 | |||
| e82d5419a8 | |||
| bd9d5f363d | |||
| f78e7ed175 | |||
| f36866c898 | |||
| 57b9e75d6d | |||
| 075e6ff3e6 | |||
| b69c71eda9 | |||
| 0c24126a6b | |||
| 2b12a499f7 | |||
| bd8a99ba28 | |||
| b53b505d2e | |||
| 3c4c4d1f7f | |||
| fcc671297e | |||
| ea94a6d89f | |||
| abe76065a9 | |||
| dbda641cee | |||
| 5f24078a48 | |||
| 8009b11516 | |||
| 8c25741e46 | |||
| fe24bdc689 | |||
| ae85ee0932 | |||
| 33987d4cc9 | |||
| 2a1403a46b | |||
| a3c0e2bd25 | |||
| 26a67641d2 | |||
| d6465e39bd | |||
| 7ca440fe51 | |||
| c4759c0a50 | |||
| 77066a2260 | |||
| 2192cc170c | |||
| fb977e45cd | |||
| 73db7e8e3a | |||
| a4179a7c23 | |||
| 5d80858a16 | |||
| 02373fcb05 | |||
| 93cd19e3a5 | |||
| c066fdd7a3 | |||
| 3a97bde863 | |||
| 595041ffc0 | |||
| 4f3a186a6f | |||
| 8184186dd3 | |||
| 7931561416 | |||
| e62756596b | |||
| 43e1409fd2 | |||
| dd54ec9aa8 | |||
| aaff6aebca | |||
| be33d29d7a | |||
| a03a931737 | |||
| fc0daa9693 | |||
| ad0a882c1c | |||
| 1c011e6024 | |||
| b1ecfd55ce | |||
| 62670e66bf | |||
| 11ec5bf25e | |||
| 9807bd99db | |||
| d2583d64f0 | |||
| 4028cb6121 | |||
| b0831fb117 | |||
| 3a70708228 | |||
| 76c53e4742 | |||
| 8049731553 | |||
| 7b5d4d031a | |||
| 5a518243dd | |||
| 84a3b10da9 | |||
| 48cf7eb6d9 | |||
| 702c4392a4 | |||
| 3831bf19e4 | |||
| f09ee083a2 | |||
| 13e5e708c2 | |||
| 86ab1dca18 | |||
| 63bf098017 | |||
| e03f1282a8 | |||
| b3908e3c82 | |||
| dd034bbfb7 | |||
| 5051ff0b84 | |||
| 6d9629b0e1 | |||
| ac83318ac4 | |||
| 97da129e11 | |||
| aa744e8437 | |||
| 8a530621b4 | |||
| 2afff9a0cb | |||
| 90c2aee6c3 | |||
| e78b80c8fe | |||
| 17d71d2829 | |||
| bc70c94f75 | |||
| e909f634f5 | |||
| 371c1366d4 | |||
| bb9dda9764 | |||
| ea0b8920f5 | |||
| bf4026ed7e | |||
| 21d5d7d07a | |||
| 80bc5833e7 | |||
| fb2f2d9cb2 | |||
| 011b1a6e6a | |||
| 8fdcddec8a | |||
| e757d9bae7 | |||
| 2590cf8615 | |||
| ef262ff9eb | |||
| 51328609d2 | |||
| 9bff8ccd0f | |||
| 49317e3903 | |||
| 0586f86ad0 | |||
| a70911d639 | |||
| bdf868ddc2 | |||
| ecfe201a57 | |||
| 1cd7b04e6f | |||
| 7f07f47302 | |||
| 8bf78399e2 | |||
| 2f2b9c782e | |||
| 51fa7b227a | |||
| 35f819c823 | |||
| 36bebb1aa0 | |||
| f16df8e4b7 | |||
| 3777bf7fb9 | |||
| 9dc8ecf722 | |||
| 492ba68cfc | |||
| 5600a82889 | |||
| 31ab43ce41 | |||
| db35dcd0b5 | |||
| 3985103974 | |||
| 3b89c5fe29 | |||
| 67d6186bbd | |||
| abe39e5076 | |||
| f32e3ae799 | |||
| 7948a61b0e | |||
| 6c62a31466 | |||
| 56b8a1a5db | |||
| f46f00b373 | |||
| 2ae7d99143 | |||
| 09a9ba6de1 | |||
| 3fed87dbb7 | |||
| 10eb70daf7 | |||
| 6a354ddab7 | |||
| 33ee7530b3 | |||
| 36ccbc8bbe | |||
| 99d51bf02c | |||
| 05e932b088 | |||
| ce4bac8218 | |||
| bd0ab957b1 | |||
| 5ccff25d88 | |||
| a1d36961cf | |||
| a2b48efa20 | |||
| 8971e2c177 | |||
| c028688a65 | |||
| 531e62fc03 | |||
| b97e5b0e03 | |||
| 8e00ce672d | |||
| 54517c0638 | |||
| f058b5d64e | |||
| e34ee43eea | |||
| 5dba9187e5 | |||
| 169132c6cc | |||
| afd5877be8 | |||
| d87191c1c1 | |||
| e687be939e | |||
| 6ac75e492a | |||
| 613ccf4b74 | |||
| 7e0f0165f4 | |||
| 4086795c29 | |||
| b1e2e0f565 | |||
| a2bb41e0ec | |||
| 44ef143ae7 | |||
| 4f8a232382 | |||
| e61ea66415 | |||
| dcbff66f0c | |||
| 9634e7b8af | |||
| 573db49deb | |||
| 2e45a7c2fd | |||
| c56c8a719c | |||
| 5030824572 | |||
| 0b41d1c6e8 | |||
| a7d3eb87c7 | |||
| 07e75c7cb8 | |||
| 2f5c0bd016 | |||
| 7a387962c6 | |||
| 749d192f54 | |||
| d2d4802ad0 | |||
| ae4e848285 | |||
| e0ab068273 | |||
| 6f2af97381 | |||
| eb3833037f | |||
| 1d0538bdef | |||
| 6f073aed5f | |||
| e25f788318 | |||
| 4b0d0b0f1e | |||
| f845c69b43 | |||
| 8d3bf1f41a | |||
| f65e6bc30e | |||
| 7f14bdfb22 | |||
| 2a55ff4f55 | |||
| 8e88366955 | |||
| afd61352d0 | |||
| 7a4a8c9a4a | |||
| 631691c212 | |||
| 31ef352234 | |||
| 4cae08e636 | |||
| 2a9986d948 | |||
| 5b2bcf6bf2 | |||
| 335237aea0 | |||
| c055fdc853 | |||
| 3d36a0f70d | |||
| 17cab9bb50 | |||
| c5f73a748e | |||
| 3527c1da67 | |||
| 99fbd4b150 | |||
| fa353401f4 | |||
| d3aad9ca46 | |||
| 05e4d908df | |||
| 3b1e9017c5 | |||
| 460d9af5b7 | |||
| e6e073d099 | |||
| 30ab9f8482 | |||
| 3d9f394533 | |||
| c2af245b85 | |||
| 0addee2b4b | |||
| 9cd60de0b9 | |||
| fc8cfe1280 | |||
| e44d84a7f9 | |||
| 291c04163a | |||
| edf90f3e76 | |||
| 361ffb5e54 | |||
| 0f0acc190b | |||
| ba3067a560 | |||
| a5d99e0ebb | |||
| 2de13bea91 | |||
| 7ded7a0720 | |||
| 102687e1ac | |||
| 31c682d407 | |||
| f99939426f | |||
| b3c7a0c871 | |||
| 51207aaae2 | |||
| 96eee13836 | |||
| 06fbaacefe | |||
| 86a5ac383e | |||
| 6ce66dee4f | |||
| b643aca8d6 | |||
| 78ccef28a8 | |||
| 919303ec08 | |||
| 5b50cc2954 | |||
| 62d4f464a0 | |||
| 2647a4b4a9 | |||
| e323191299 | |||
| cc32a6bf9f | |||
| c0942dbf9f | |||
| 95c6d5140a | |||
| 32a0b10983 | |||
| 90c873ab1d | |||
| 2ad82cbfb0 | |||
| da95fd3019 | |||
| d3b91f266a | |||
| 9e06525642 | |||
| 816c18a4ec | |||
| 252531e1bb | |||
| 5f7143df02 | |||
| 2629417320 |
@@ -11,7 +11,6 @@
|
||||
"DISPLAY": "${localEnv:DISPLAY}",
|
||||
"PYTHONPATH": "${containerWorkspaceFolder}",
|
||||
"TERM": "xterm-256color",
|
||||
"CARLA_HOST": "host.docker.internal",
|
||||
"force_color_prompt": "1"
|
||||
},
|
||||
"runArgs": [
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
* text=auto
|
||||
|
||||
# to move existing files into LFS:
|
||||
# git add --renormalize .
|
||||
*.dlc filter=lfs diff=lfs merge=lfs -text
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.svg filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.gif filter=lfs diff=lfs merge=lfs -text
|
||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
*.wav filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
selfdrive/car/tests/test_models_segs.txt filter=lfs diff=lfs merge=lfs -text
|
||||
selfdrive/assets/fonts/*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
selfdrive/assets/training/*.png filter=lfs diff=lfs merge=lfs -text
|
||||
system/hardware/tici/updater filter=lfs diff=lfs merge=lfs -text
|
||||
selfdrive/ui/qt/spinner_larch64 filter=lfs diff=lfs merge=lfs -text
|
||||
selfdrive/ui/qt/text_larch64 filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/**/*.a filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/**/*.so filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/**/*.so.* filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/**/*.dylib filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/acados/*/t_renderer filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/bootstrap/bootstrap-icons.svg filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/qt5/larch64/bin/lrelease filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/qt5/larch64/bin/lupdate filter=lfs diff=lfs merge=lfs -text
|
||||
third_party/catch2/include/catch2/catch.hpp filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
@@ -8,7 +8,7 @@ assignees: ''
|
||||
|
||||
**Checklist**
|
||||
|
||||
- [ ] added to README
|
||||
- [ ] added entry to CarInfo in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs
|
||||
- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
|
||||
- [ ] route with openpilot:
|
||||
- [ ] route with stock system:
|
||||
|
||||
@@ -6,6 +6,8 @@ labels: 'fingerprint'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
Discord username: []
|
||||
**Car**
|
||||
Which car (make, model, year) this fingerprint is for
|
||||
|
||||
Route: []
|
||||
**Route**
|
||||
A route with the fingerprint
|
||||
@@ -28,5 +28,4 @@ Longitudinal:
|
||||
Lateral:
|
||||
* Straight driving at ~25, ~45 and ~65mph
|
||||
* Turns driving at ~25, ~45 and ~65mph
|
||||
|
||||
-->
|
||||
-->
|
||||
@@ -0,0 +1,30 @@
|
||||
import pathlib
|
||||
|
||||
GITHUB_FOLDER = pathlib.Path(__file__).parent
|
||||
|
||||
PULL_REQUEST_TEMPLATES = (GITHUB_FOLDER / "PULL_REQUEST_TEMPLATE")
|
||||
|
||||
order = ["fingerprint", "car_bugfix", "bugfix", "car_port", "refactor"]
|
||||
|
||||
def create_pull_request_template():
|
||||
with open(GITHUB_FOLDER / "pull_request_template.md", "w") as f:
|
||||
f.write("<!-- Please copy and paste the relevant template -->\n\n")
|
||||
|
||||
for t in order:
|
||||
template = PULL_REQUEST_TEMPLATES / f"{t}.md"
|
||||
text = template.read_text()
|
||||
|
||||
# Remove metadata for GitHub
|
||||
start = text.find("---")
|
||||
end = text.find("---", start+1)
|
||||
text = text[end + 4:]
|
||||
|
||||
# Remove comments
|
||||
text = text.replace("<!-- ", "").replace("-->", "")
|
||||
|
||||
f.write(f"<!--- ***** Template: {template.stem.replace('_', ' ').title()} *****\n")
|
||||
f.write(text)
|
||||
f.write("\n\n")
|
||||
f.write("-->\n\n")
|
||||
|
||||
create_pull_request_template()
|
||||
@@ -1,65 +1,79 @@
|
||||
CI / testing:
|
||||
- all:
|
||||
- changed-files: ['.github/**', '**/test_*', 'Jenkinsfile']
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: "{.github/**,**/test_*,Jenkinsfile}"
|
||||
|
||||
car:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/**']
|
||||
car:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/**'
|
||||
|
||||
body:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/body/*']
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/body/*'
|
||||
|
||||
chrysler:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/chrysler/*']
|
||||
ford:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/ford/*']
|
||||
gm:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/gm/*']
|
||||
honda:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/honda/*']
|
||||
hyundai:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/hyundai/*']
|
||||
mazda:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/mazda/*']
|
||||
nissan:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/nissan/*']
|
||||
subaru:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/subaru/*']
|
||||
tesla:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/tesla/*']
|
||||
toyota:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/toyota/*']
|
||||
volkswagen:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/car/volkswagen/*']
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/chrysler/*'
|
||||
|
||||
ford:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/ford/*'
|
||||
|
||||
gm:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/gm/*'
|
||||
|
||||
honda:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/honda/*'
|
||||
|
||||
hyundai:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/hyundai/*'
|
||||
|
||||
mazda:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/mazda/*'
|
||||
|
||||
nissan:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/nissan/*'
|
||||
|
||||
subaru:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/subaru/*'
|
||||
|
||||
tesla:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/telsa/*'
|
||||
|
||||
toyota:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/toyota/*'
|
||||
|
||||
volkswagen:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/volkswagen/*'
|
||||
|
||||
fingerprint:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/car/*/fingerprints.py'
|
||||
|
||||
simulation:
|
||||
- all:
|
||||
- changed-files: ['tools/sim/**']
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'tools/sim/**'
|
||||
|
||||
ui:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/ui/**']
|
||||
tools:
|
||||
- all:
|
||||
- changed-files: ['tools/**']
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/ui/**'
|
||||
|
||||
tools:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'tools/**'
|
||||
|
||||
multilanguage:
|
||||
- all:
|
||||
- changed-files: ['selfdrive/ui/translations/**']
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/ui/translations/**'
|
||||
|
||||
research:
|
||||
- all:
|
||||
- changed-files: [
|
||||
'selfdrive/modeld/models/**',
|
||||
'selfdrive/test/process_replay/model_replay_ref_commit',
|
||||
]
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: "{selfdrive/modeld/models/**,selfdrive/test/process_replay/model_replay_ref_commit}"
|
||||
|
||||
@@ -10,39 +10,59 @@ A route with the fingerprint
|
||||
|
||||
-->
|
||||
|
||||
<!--- ***** Template: Car bug fix *****
|
||||
<!--- ***** Template: Car Bugfix *****
|
||||
|
||||
**Description** [](A description of the bug and the fix. Also link any relevant issues.)
|
||||
**Description**
|
||||
|
||||
**Verification** [](Explain how you tested this bug fix.)
|
||||
A description of the bug and the fix. Also link the issue if it exists.
|
||||
|
||||
**Verification**
|
||||
|
||||
Explain how you tested this bug fix.
|
||||
|
||||
**Route**
|
||||
|
||||
Route: [a route with the bug fix]
|
||||
|
||||
-->
|
||||
|
||||
<!--- ***** Template: Bug fix *****
|
||||
|
||||
**Description** [](A description of the bug and the fix. Also link any relevant issues.)
|
||||
|
||||
**Verification** [](Explain how you tested this bug fix.)
|
||||
|
||||
-->
|
||||
|
||||
<!--- ***** Template: Car port *****
|
||||
<!--- ***** Template: Bugfix *****
|
||||
|
||||
**Description**
|
||||
|
||||
A description of the bug and the fix. Also link the issue if it exists.
|
||||
|
||||
**Verification**
|
||||
|
||||
Explain how you tested this bug fix.
|
||||
|
||||
|
||||
-->
|
||||
|
||||
<!--- ***** Template: Car Port *****
|
||||
|
||||
**Checklist**
|
||||
|
||||
- [ ] added entry to CarInfo in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs
|
||||
- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
|
||||
- [ ] route with openpilot:
|
||||
- [ ] route with stock system:
|
||||
- [ ] car harness used (if comma doesn't sell it, put N/A):
|
||||
|
||||
|
||||
-->
|
||||
|
||||
<!--- ***** Template: Refactor *****
|
||||
|
||||
**Description** [](A description of the refactor, including the goals it accomplishes.)
|
||||
**Description**
|
||||
|
||||
A description of the refactor, including the goals it accomplishes.
|
||||
|
||||
**Verification**
|
||||
|
||||
Explain how you tested the refactor for regressions.
|
||||
|
||||
**Verification** [](Explain how you tested the refactor for regressions.)
|
||||
|
||||
-->
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
name: 'automatically cache based on current runner'
|
||||
|
||||
inputs:
|
||||
path:
|
||||
description: 'path to cache'
|
||||
required: true
|
||||
key:
|
||||
description: 'key'
|
||||
required: true
|
||||
restore-keys:
|
||||
description: 'restore-keys'
|
||||
required: true
|
||||
save:
|
||||
description: 'whether to save the cache'
|
||||
default: 'false'
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: setup namespace cache
|
||||
if: ${{ contains(runner.name, 'nsc') }}
|
||||
uses: namespacelabs/nscloud-cache-action@v1
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
|
||||
- name: setup github cache
|
||||
if: ${{ !contains(runner.name, 'nsc') && inputs.save != 'false' }}
|
||||
uses: 'actions/cache@v3'
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
key: ${{ inputs.key }}
|
||||
restore-keys: ${{ inputs.restore-keys }}
|
||||
|
||||
- name: setup github cache
|
||||
if: ${{ !contains(runner.name, 'nsc') && inputs.save == 'false' }}
|
||||
uses: 'actions/cache/restore@v3'
|
||||
with:
|
||||
path: ${{ inputs.path }}
|
||||
key: ${{ inputs.key }}
|
||||
restore-keys: ${{ inputs.restore-keys }}
|
||||
|
||||
# make the directory manually in case we didn't get a hit, so it doesn't fail on future steps
|
||||
- id: scons-cache-setup
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p ${{ inputs.path }}
|
||||
sudo chmod -R 777 ${{ inputs.path }}
|
||||
sudo chown -R $USER ${{ inputs.path }}
|
||||
@@ -0,0 +1,200 @@
|
||||
name: "PR review"
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened, synchronize, edited, edited]
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
name: apply labels
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: false
|
||||
- uses: actions/labeler@v5.0.0
|
||||
with:
|
||||
dot: true
|
||||
configuration-path: .github/labeler.yaml
|
||||
|
||||
pr_branch_check:
|
||||
name: check branch
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
steps:
|
||||
- uses: Vankka/pr-target-branch-action@69ab6dd5c221de3548b3b6c4d102c1f4913d3baa
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
target: /^(?!master$).*/
|
||||
exclude: /commaai:.*/
|
||||
change-to: ${{ github.base_ref }}
|
||||
already-exists-action: close_this
|
||||
already-exists-comment: "Your PR should be made against the `master` branch"
|
||||
|
||||
check-pr-template:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
actions: read
|
||||
if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot'
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
// Comment to add to the PR if no template has been used
|
||||
const NO_TEMPLATE_MESSAGE =
|
||||
"It looks like you didn't use one of the Pull Request templates. Please check [the contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md). \
|
||||
Also make sure that you didn't modify any of the checkboxes or headings within the template.";
|
||||
// body data for future requests
|
||||
const body_data = {
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
};
|
||||
|
||||
// Utility function to extract all headings
|
||||
const extractHeadings = (markdown) => {
|
||||
const headingRegex = /^(#{1,6})\s+(.+)$/gm;
|
||||
const boldTextRegex = /^(?:\*\*|__)(.+?)(?:\*\*|__)\s*$/gm;
|
||||
const headings = [];
|
||||
let headingMatch;
|
||||
while ((headingMatch = headingRegex.exec(markdown))) {
|
||||
headings.push(headingMatch[2].trim());
|
||||
}
|
||||
let boldMatch;
|
||||
while ((boldMatch = boldTextRegex.exec(markdown))) {
|
||||
headings.push(boldMatch[1].trim());
|
||||
}
|
||||
return headings;
|
||||
};
|
||||
|
||||
// Utility function to extract all check box descriptions
|
||||
const extractCheckBoxTexts = (markdown) => {
|
||||
const checkboxRegex = /^\s*-\s*\[( |x)\]\s+(.+)$/gm;
|
||||
const checkboxes = [];
|
||||
let match;
|
||||
while ((match = checkboxRegex.exec(markdown))) {
|
||||
checkboxes.push(match[2].trim());
|
||||
}
|
||||
return checkboxes;
|
||||
};
|
||||
|
||||
// Utility function to check if a list is a subset of another list
|
||||
isSubset = (subset, superset) => {
|
||||
return subset.every((item) => superset.includes(item));
|
||||
};
|
||||
|
||||
// Get filenames of all currently checked-in PR templates
|
||||
const template_contents = await github.rest.repos.getContent({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
path: ".github/PULL_REQUEST_TEMPLATE",
|
||||
});
|
||||
var template_filenames = [];
|
||||
for (const content of template_contents.data) {
|
||||
template_filenames.push(content.path);
|
||||
}
|
||||
console.debug("Received template filenames: " + template_filenames);
|
||||
// Retrieve templates
|
||||
var templates = [];
|
||||
for (const template_filename of template_filenames) {
|
||||
const template_response = await github.rest.repos.getContent({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
path: template_filename,
|
||||
});
|
||||
// Convert Base64 content back
|
||||
const decoded_template = atob(template_response.data.content);
|
||||
const headings = extractHeadings(decoded_template);
|
||||
const checkboxes = extractCheckBoxTexts(decoded_template);
|
||||
if (!headings.length && !checkboxes.length) {
|
||||
console.warn(
|
||||
"Invalid template! Contains neither headings nor checkboxes, ignoring it: \n" +
|
||||
decoded_template
|
||||
);
|
||||
} else {
|
||||
templates.push({ headings: headings, checkboxes: checkboxes });
|
||||
}
|
||||
}
|
||||
// Retrieve the PR Body
|
||||
const pull_request = await github.rest.issues.get({
|
||||
...body_data,
|
||||
});
|
||||
const pull_request_text = pull_request.data.body;
|
||||
console.debug("Received Pull Request body: \n" + pull_request_text);
|
||||
|
||||
/* Check if the PR Body matches one of the templates
|
||||
A template is defined by all headings and checkboxes it contains
|
||||
We extract all Headings and Checkboxes from the PR text and check if any of the templates is a subset of that
|
||||
*/
|
||||
const pr_headings = extractHeadings(pull_request_text);
|
||||
const pr_checkboxes = extractCheckBoxTexts(pull_request_text);
|
||||
console.debug("Found Headings in PR body:\n" + pr_headings);
|
||||
console.debug("Found Checkboxes in PR body:\n" + pr_checkboxes);
|
||||
var template_found = false;
|
||||
// Iterate over each template to check if it applies
|
||||
for (const template of templates) {
|
||||
console.log(
|
||||
"Checking for headings: [" +
|
||||
template.headings +
|
||||
"] and checkboxes: [" +
|
||||
template.checkboxes + "]"
|
||||
);
|
||||
if (
|
||||
isSubset(template.checkboxes, pr_checkboxes) &&
|
||||
isSubset(template.headings, pr_headings)
|
||||
) {
|
||||
console.debug("Found matching template!");
|
||||
template_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
// List comments from previous runs
|
||||
var existing_comments = [];
|
||||
const comments = await github.rest.issues.listComments({
|
||||
...body_data,
|
||||
});
|
||||
for (const comment of comments.data) {
|
||||
if (comment.body === NO_TEMPLATE_MESSAGE) {
|
||||
existing_comments.push(comment);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a comment to the PR that it is not using a the template (but only if this comment does not exist already)
|
||||
if (!template_found) {
|
||||
var comment_already_sent = false;
|
||||
|
||||
// Add an 'in-bot-review' label since this PR doesn't have the template
|
||||
github.rest.issues.addLabels({
|
||||
...body_data,
|
||||
labels: ["in-bot-review"],
|
||||
});
|
||||
|
||||
if (existing_comments.length < 1) {
|
||||
github.rest.issues.createComment({
|
||||
...body_data,
|
||||
body: NO_TEMPLATE_MESSAGE,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// If template has been found, delete any old comment about missing template
|
||||
for (const existing_comment of existing_comments) {
|
||||
github.rest.issues.deleteComment({
|
||||
...body_data,
|
||||
comment_id: existing_comment.id,
|
||||
});
|
||||
}
|
||||
// Remove the 'in-bot-review' label after the review is done and the PR has passed
|
||||
github.rest.issues.removeLabel({
|
||||
...body_data,
|
||||
name: "in-bot-review",
|
||||
}).catch((error) => {
|
||||
console.log("Label 'in-bot-review' not found, ignoring");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,13 +7,15 @@ on:
|
||||
env:
|
||||
BASE_IMAGE: openpilot-base
|
||||
DOCKER_REGISTRY: ghcr.io/commaai
|
||||
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/sh -c
|
||||
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/bash -c
|
||||
|
||||
jobs:
|
||||
badges:
|
||||
name: create badges
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -23,6 +25,8 @@ jobs:
|
||||
run: |
|
||||
${{ env.RUN }} "scons -j$(nproc) && python selfdrive/ui/translations/create_badges.py"
|
||||
|
||||
rm .gitattributes
|
||||
|
||||
git checkout --orphan badges
|
||||
git rm -rf --cached .
|
||||
git config user.email "badge-researcher@comma.ai"
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
name: 'compile openpilot'
|
||||
|
||||
inputs:
|
||||
cache_key_prefix:
|
||||
description: 'Prefix for caching key'
|
||||
required: false
|
||||
default: 'scons'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
@@ -24,4 +18,4 @@ runs:
|
||||
if: github.ref == 'refs/heads/master'
|
||||
with:
|
||||
path: .ci_cache/scons_cache
|
||||
key: ${{ inputs.cache_key_prefix }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
|
||||
@@ -15,7 +15,7 @@ env:
|
||||
|
||||
BUILD: selfdrive/test/docker_build.sh base
|
||||
|
||||
RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -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/sh -c
|
||||
RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -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:
|
||||
docs:
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
${{ env.RUN }} "scons -j$(nproc)"
|
||||
- name: Build docs
|
||||
run: |
|
||||
${{ env.RUN }} "apt update && apt install -y doxygen && cd docs && make html"
|
||||
${{ env.RUN }} "apt update && apt install -y doxygen && cd docs && make -j$(nproc) html"
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
|
||||
@@ -50,9 +50,10 @@ jobs:
|
||||
cd openpilot-docs
|
||||
|
||||
git checkout --orphan tmp
|
||||
git rm -rf --cached .
|
||||
git rm -rf .
|
||||
|
||||
cp -r ../build/docs/html/ docs/
|
||||
cp -r ../docs/README.md .
|
||||
touch docs/.nojekyll
|
||||
echo -n docs.comma.ai > docs/CNAME
|
||||
git add -f .
|
||||
@@ -60,4 +61,4 @@ jobs:
|
||||
git commit -m "build docs"
|
||||
|
||||
# docs live in different repo to not bloat openpilot's full clone size
|
||||
git push -f origin gh-pages
|
||||
git push -f origin tmp:gh-pages
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
pull_request_target:
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: false
|
||||
- uses: actions/labeler@v5.0.0-alpha.1
|
||||
with:
|
||||
dot: true
|
||||
configuration-path: .github/labeler.yaml
|
||||
@@ -15,14 +15,19 @@ jobs:
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
env:
|
||||
PUSH_IMAGE: true
|
||||
permissions:
|
||||
checks: read
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Wait for green check mark
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
uses: lewagon/wait-on-check-action@e2558238c09778af25867eb5de5a3ce4bbae3dcd
|
||||
uses: lewagon/wait-on-check-action@595dabb3acf442d47e29c9ec9ba44db0c6bdd18f
|
||||
with:
|
||||
ref: master
|
||||
wait-interval: 30
|
||||
running-workflow-name: 'build prebuilt'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
check-regexp: ^((?!.*(build master-ci).*).)*$
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
@@ -14,6 +14,9 @@ jobs:
|
||||
image: ghcr.io/commaai/openpilot-base:latest
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
permissions:
|
||||
checks: read
|
||||
contents: write
|
||||
steps:
|
||||
- name: Install wait-on-check-action dependencies
|
||||
run: |
|
||||
@@ -21,11 +24,12 @@ jobs:
|
||||
sudo apt-get install -y libyaml-dev
|
||||
- name: Wait for green check mark
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
uses: lewagon/wait-on-check-action@e2558238c09778af25867eb5de5a3ce4bbae3dcd
|
||||
uses: lewagon/wait-on-check-action@595dabb3acf442d47e29c9ec9ba44db0c6bdd18f
|
||||
with:
|
||||
ref: master
|
||||
wait-interval: 30
|
||||
running-workflow-name: 'build master-ci'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
check-regexp: ^((?!.*(build prebuilt).*).)*$
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
@@ -2,12 +2,36 @@ name: repo maintenance
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 15 * * 2"
|
||||
- cron: "0 12 * * 1" # every Monday at 12am UTC (4am PST)
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
updates:
|
||||
name: updates
|
||||
bump_submodules:
|
||||
name: bump_submodules
|
||||
runs-on: ubuntu-20.04
|
||||
container:
|
||||
image: ghcr.io/commaai/openpilot-base:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: bump submodules
|
||||
run: |
|
||||
git config --global --add safe.directory '*'
|
||||
git -c submodule."tinygrad".update=none submodule update --remote
|
||||
git add .
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_CREATE_PR_PAT }}
|
||||
commit-message: bump submodules
|
||||
title: 'Bump submodules'
|
||||
branch: auto-bump-submodules
|
||||
base: master
|
||||
delete-branch: true
|
||||
body: 'Automatic PR from repo-maintenance -> bump_submodules'
|
||||
package_updates:
|
||||
name: package_updates
|
||||
runs-on: ubuntu-20.04
|
||||
container:
|
||||
image: ghcr.io/commaai/openpilot-base:latest
|
||||
@@ -30,3 +54,4 @@ jobs:
|
||||
branch: auto-package-updates
|
||||
base: master
|
||||
delete-branch: true
|
||||
body: 'Automatic PR from repo-maintenance -> package_updates'
|
||||
|
||||
@@ -20,14 +20,13 @@ env:
|
||||
DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
|
||||
BUILD: selfdrive/test/docker_build.sh base
|
||||
|
||||
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -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/sh -c
|
||||
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PRE_COMMIT_HOME=/tmp/pre-commit -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/pre-commit:/tmp/pre-commit -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
|
||||
|
||||
BUILD_CL: selfdrive/test/docker_build.sh cl
|
||||
|
||||
RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONWARNINGS=error -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 $CL_BASE_IMAGE /bin/sh -c
|
||||
RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e CI=1 -e PYTHONWARNINGS=error -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 $CL_BASE_IMAGE /bin/bash -c
|
||||
|
||||
PYTEST: pytest --continue-on-collection-errors --cov --cov-report=xml --cov-append --durations=0 --durations-min=5 --hypothesis-seed 0
|
||||
XDIST: -n auto --dist=loadscope
|
||||
|
||||
jobs:
|
||||
build_release:
|
||||
@@ -43,6 +42,7 @@ jobs:
|
||||
- name: Build devel
|
||||
timeout-minutes: 1
|
||||
run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh
|
||||
- uses: ./.github/workflows/setup-pre-commit
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Check submodules
|
||||
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
|
||||
@@ -52,13 +52,13 @@ jobs:
|
||||
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
|
||||
run: |
|
||||
cd $STRIPPED_DIR
|
||||
${{ env.RUN }} "CI=1 python selfdrive/manager/build.py"
|
||||
${{ env.RUN }} "python selfdrive/manager/build.py"
|
||||
- name: Run tests
|
||||
timeout-minutes: 3
|
||||
run: |
|
||||
cd $STRIPPED_DIR
|
||||
${{ env.RUN }} "release/check-dirty.sh && \
|
||||
MAX_EXAMPLES=5 $PYTEST $XDIST selfdrive/car"
|
||||
MAX_EXAMPLES=5 $PYTEST selfdrive/car"
|
||||
- name: pre-commit
|
||||
timeout-minutes: 3
|
||||
run: |
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
cp pyproject.toml $STRIPPED_DIR
|
||||
cp poetry.lock $STRIPPED_DIR
|
||||
cd $STRIPPED_DIR
|
||||
${{ env.RUN }} "unset PYTHONWARNINGS && SKIP=check-added-large-files pre-commit run --all"
|
||||
${{ env.RUN }} "unset PYTHONWARNINGS && SKIP=check-added-large-files pre-commit run --all && chmod -R 777 /tmp/pre-commit"
|
||||
|
||||
build:
|
||||
strategy:
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && '["x86_64", "aarch64"]' || '["x86_64"]' ) }}
|
||||
runs-on: ${{ (matrix.arch == 'aarch64') && 'buildjet-2vcpu-ubuntu-2204-arm' || 'ubuntu-20.04' }}
|
||||
runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-20.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -84,18 +84,15 @@ jobs:
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
with:
|
||||
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
|
||||
cache_key_prefix: scons_${{ matrix.arch }}
|
||||
- uses: ./.github/workflows/compile-openpilot
|
||||
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache
|
||||
with:
|
||||
cache_key_prefix: scons_${{ matrix.arch }}
|
||||
|
||||
docker_push:
|
||||
name: docker push
|
||||
strategy:
|
||||
matrix:
|
||||
arch: ${{ fromJson( (github.repository == 'commaai/openpilot') && '["x86_64", "aarch64"]' || '["x86_64"]' ) }}
|
||||
runs-on: ${{ (matrix.arch == 'aarch64') && 'buildjet-2vcpu-ubuntu-2204-arm' || 'ubuntu-20.04' }}
|
||||
runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-20.04' }}
|
||||
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -134,15 +131,18 @@ jobs:
|
||||
|
||||
static_analysis:
|
||||
name: static analysis
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-20.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: ./.github/workflows/setup-pre-commit
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: pre-commit
|
||||
timeout-minutes: 4
|
||||
run: ${{ env.RUN }} "unset PYTHONWARNINGS && pre-commit run --all"
|
||||
run: ${{ env.RUN }} "unset PYTHONWARNINGS && pre-commit run --all && chmod -R 777 /tmp/pre-commit"
|
||||
|
||||
valgrind:
|
||||
name: valgrind
|
||||
@@ -164,34 +164,40 @@ jobs:
|
||||
|
||||
unit_tests:
|
||||
name: unit tests
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-20.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
with:
|
||||
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
|
||||
- name: Build openpilot
|
||||
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 10 || 30) }} # allow more time when we missed the scons cache
|
||||
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||
- name: Run unit tests
|
||||
timeout-minutes: 15
|
||||
run: |
|
||||
${{ env.RUN }} "$PYTEST $XDIST --timeout 30 -o cpp_files=test_* -m 'not slow' && \
|
||||
${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
|
||||
export MAPBOX_TOKEN='pk.eyJ1Ijoiam5ld2IiLCJhIjoiY2xxNW8zZXprMGw1ZzJwbzZneHd2NHljbSJ9.gV7VPRfbXFetD-1OVF0XZg' && \
|
||||
$PYTEST --timeout 60 -m 'not slow' -n $(nproc) && \
|
||||
./selfdrive/ui/tests/create_test_translations.sh && \
|
||||
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
|
||||
./selfdrive/ui/tests/test_translations.py && \
|
||||
./system/camerad/test/ae_gray_test && \
|
||||
./selfdrive/test/process_replay/test_fuzzy.py"
|
||||
./selfdrive/ui/tests/test_translations.py"
|
||||
- name: "Upload coverage to Codecov"
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
process_replay:
|
||||
name: process replay
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'buildjet-8vcpu-ubuntu-2004' || 'ubuntu-20.04' }}
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-20.04' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -211,8 +217,9 @@ jobs:
|
||||
- name: Run replay
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
|
||||
${{ env.RUN }} "coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
|
||||
chmod -R 777 /tmp/comma_download_cache && \
|
||||
coverage combine && \
|
||||
coverage xml"
|
||||
- name: Print diff
|
||||
id: print-diff
|
||||
@@ -227,11 +234,13 @@ jobs:
|
||||
- name: Upload reference logs
|
||||
if: ${{ failure() && steps.print-diff.outcome == 'success' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }}
|
||||
run: |
|
||||
${{ env.RUN }} "unset PYTHONWARNINGS && CI=1 AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only"
|
||||
${{ env.RUN }} "unset PYTHONWARNINGS && AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only"
|
||||
- name: "Upload coverage to Codecov"
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
regen:
|
||||
name: regen
|
||||
@@ -257,7 +266,7 @@ jobs:
|
||||
- name: Run regen
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
${{ env.RUN_CL }} "ONNXCPU=1 $PYTEST $XDIST selfdrive/test/process_replay/test_regen.py && \
|
||||
${{ env.RUN_CL }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \
|
||||
chmod -R 777 /tmp/comma_download_cache"
|
||||
|
||||
test_modeld:
|
||||
@@ -278,10 +287,11 @@ jobs:
|
||||
${{ env.RUN }} "scons -j$(nproc)"
|
||||
# PYTHONWARNINGS triggers a SyntaxError in onnxruntime
|
||||
- name: Run model replay with ONNX
|
||||
timeout-minutes: 3
|
||||
timeout-minutes: 4
|
||||
run: |
|
||||
${{ env.RUN_CL }} "unset PYTHONWARNINGS && \
|
||||
ONNXCPU=1 CI=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \
|
||||
ONNXCPU=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \
|
||||
coverage combine && \
|
||||
coverage xml"
|
||||
- name: Run unit tests
|
||||
timeout-minutes: 4
|
||||
@@ -292,10 +302,14 @@ jobs:
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
test_cars:
|
||||
name: cars
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
|
||||
((github.event_name != 'pull_request') ||
|
||||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-20.04' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -316,7 +330,7 @@ jobs:
|
||||
- name: Test car models
|
||||
timeout-minutes: 25
|
||||
run: |
|
||||
${{ env.RUN }} "$PYTEST $XDIST selfdrive/car/tests/test_models.py && \
|
||||
${{ env.RUN }} "$PYTEST selfdrive/car/tests/test_models.py && \
|
||||
chmod -R 777 /tmp/comma_download_cache"
|
||||
env:
|
||||
NUM_JOBS: 5
|
||||
@@ -325,6 +339,8 @@ jobs:
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.job }}
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
car_docs_diff:
|
||||
name: PR comments
|
||||
@@ -379,3 +395,25 @@ jobs:
|
||||
repo: context.repo.repo,
|
||||
comment_id: ${{ steps.fc.outputs.comment-id }}
|
||||
})
|
||||
|
||||
# need to figure out some stuff with tkinter before enabling this
|
||||
|
||||
# create_ui_report:
|
||||
# name: Create UI Report
|
||||
# runs-on: ubuntu-20.04
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# with:
|
||||
# submodules: true
|
||||
# - uses: ./.github/workflows/setup-with-retry
|
||||
# - name: Build openpilot
|
||||
# run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||
# - name: Create Test Report
|
||||
# run: ${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \
|
||||
# export MAPBOX_TOKEN='pk.eyJ1Ijoiam5ld2IiLCJhIjoiY2xxNW8zZXprMGw1ZzJwbzZneHd2NHljbSJ9.gV7VPRfbXFetD-1OVF0XZg' && \
|
||||
# python selfdrive/ui/tests/test_ui/run.py"
|
||||
# - name: Upload Test Report
|
||||
# uses: actions/upload-artifact@v2
|
||||
# with:
|
||||
# name: report
|
||||
# path: selfdrive/ui/tests/test_ui
|
||||
@@ -0,0 +1,12 @@
|
||||
name: 'set up pre-commit environment'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: ./.github/workflows/auto-cache
|
||||
with:
|
||||
path: .ci_cache/pre-commit
|
||||
key: pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }}
|
||||
restore-keys: |
|
||||
pre-commit-
|
||||
save: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' }}
|
||||
@@ -5,10 +5,6 @@ inputs:
|
||||
description: 'Auth token for Docker Hub, required for BuildJet jobs'
|
||||
required: false
|
||||
default: ''
|
||||
cache_key_prefix:
|
||||
description: 'Prefix for caching key'
|
||||
required: false
|
||||
default: 'scons_x86_64'
|
||||
sleep_time:
|
||||
description: 'Time to sleep between retries'
|
||||
required: false
|
||||
@@ -22,7 +18,6 @@ runs:
|
||||
continue-on-error: true
|
||||
with:
|
||||
docker_hub_pat: ${{ inputs.docker_hub_pat }}
|
||||
cache_key_prefix: ${{ inputs.cache_key_prefix }}
|
||||
is_retried: true
|
||||
- if: steps.setup1.outcome == 'failure'
|
||||
shell: bash
|
||||
@@ -33,7 +28,6 @@ runs:
|
||||
continue-on-error: true
|
||||
with:
|
||||
docker_hub_pat: ${{ inputs.docker_hub_pat }}
|
||||
cache_key_prefix: ${{ inputs.cache_key_prefix }}
|
||||
is_retried: true
|
||||
- if: steps.setup2.outcome == 'failure'
|
||||
shell: bash
|
||||
@@ -43,5 +37,4 @@ runs:
|
||||
uses: ./.github/workflows/setup
|
||||
with:
|
||||
docker_hub_pat: ${{ inputs.docker_hub_pat }}
|
||||
cache_key_prefix: ${{ inputs.cache_key_prefix }}
|
||||
is_retried: true
|
||||
|
||||
@@ -5,10 +5,6 @@ inputs:
|
||||
description: 'Auth token for Docker Hub, required for BuildJet jobs'
|
||||
required: true
|
||||
default: ''
|
||||
cache_key_prefix:
|
||||
description: 'Prefix for caching key'
|
||||
required: true
|
||||
default: 'scons_x86_64'
|
||||
is_retried:
|
||||
description: 'A mock param that asserts that we use the setup-with-retry instead of this action directly'
|
||||
required: false
|
||||
@@ -47,19 +43,14 @@ runs:
|
||||
run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
|
||||
- shell: bash
|
||||
run: echo "$CACHE_COMMIT_DATE"
|
||||
- id: restore-scons-cache
|
||||
uses: actions/cache/restore@v3
|
||||
- id: scons-cache
|
||||
uses: ./.github/workflows/auto-cache
|
||||
with:
|
||||
path: .ci_cache/scons_cache
|
||||
key: ${{ inputs.cache_key_prefix }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
key: scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ inputs.cache_key_prefix }}-${{ env.CACHE_COMMIT_DATE }}-
|
||||
${{ inputs.cache_key_prefix }}-
|
||||
# if we didn't get a cache hit, make the directory manually so it doesn't fail on future steps
|
||||
- id: scons-cache-setup
|
||||
shell: bash
|
||||
if: steps.restore-scons-cache.outputs.cache-hit != 'true'
|
||||
run: mkdir -p $GITHUB_WORKSPACE/.ci_cache/scons_cache
|
||||
scons-${{ runner.arch }}-${{ env.CACHE_COMMIT_DATE }}
|
||||
scons-${{ runner.arch }}
|
||||
# as suggested here: https://github.com/moby/moby/issues/32816#issuecomment-910030001
|
||||
- id: normalize-file-permissions
|
||||
shell: bash
|
||||
@@ -67,12 +58,6 @@ runs:
|
||||
run: |
|
||||
find . -type f -executable -not -perm 755 -exec chmod 755 {} \;
|
||||
find . -type f -not -executable -not -perm 644 -exec chmod 644 {} \;
|
||||
- id: setup-buildx-action
|
||||
if: contains(runner.name, 'buildjet')
|
||||
name: Set up Docker Buildx on buildjet to ensure a consistent cache
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
driver: docker-container
|
||||
# build our docker image
|
||||
- shell: bash
|
||||
run: eval ${{ env.BUILD }}
|
||||
@@ -0,0 +1,28 @@
|
||||
name: stale
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
DAYS_BEFORE_PR_CLOSE: 7
|
||||
DAYS_BEFORE_PR_STALE: 30
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
exempt-milestones: true
|
||||
|
||||
# pull request config
|
||||
stale-pr-message: 'This PR has had no activity for ${{ env.DAYS_BEFORE_PR_STALE }} days. It will be automatically closed in ${{ env.DAYS_BEFORE_PR_CLOSE }} days if there is no activity.'
|
||||
close-pr-message: 'This PR has been automatically closed due to inactivity. Feel free to re-open once activity resumes.'
|
||||
delete-branch: ${{ github.event.pull_request.head.repo.full_name == 'commaai/openpilot' }} # only delete branches on the main repo
|
||||
exempt-pr-labels: "ignore stale,needs testing,car port" # if wip or it needs testing from the community, don't mark as stale
|
||||
days-before-pr-stale: ${{ env.DAYS_BEFORE_PR_STALE }}
|
||||
days-before-pr-close: ${{ env.DAYS_BEFORE_PR_CLOSE }}
|
||||
|
||||
# issue config
|
||||
days-before-issue-stale: -1 # ignore issues for now
|
||||
@@ -17,11 +17,11 @@ env:
|
||||
|
||||
BUILD: selfdrive/test/docker_build.sh base
|
||||
|
||||
RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -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/sh -c
|
||||
RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -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
|
||||
|
||||
BUILD_CL: selfdrive/test/docker_build.sh cl
|
||||
|
||||
RUN_CL: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/sh -c
|
||||
RUN_CL: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v $GITHUB_WORKSPACE/.ci_cache/scons_cache:/tmp/scons_cache -v $GITHUB_WORKSPACE/.ci_cache/comma_download_cache:/tmp/comma_download_cache -v $GITHUB_WORKSPACE/.ci_cache/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/bash -c
|
||||
|
||||
|
||||
jobs:
|
||||
@@ -81,11 +81,29 @@ jobs:
|
||||
- name: Run dev container
|
||||
run: |
|
||||
mkdir -p /tmp/devcontainer_scons_cache/
|
||||
cp -r $GITHUB_WORKSPACE/.ci_cache/scons_cache/* /tmp/devcontainer_scons_cache/
|
||||
cp -r $GITHUB_WORKSPACE/.ci_cache/scons_cache/. /tmp/devcontainer_scons_cache/
|
||||
devcontainer up --workspace-folder .
|
||||
- name: Test environment
|
||||
run: |
|
||||
devcontainer exec --workspace-folder . scons -j$(nproc)
|
||||
devcontainer exec --workspace-folder . scons -j$(nproc) cereal/ common/
|
||||
devcontainer exec --workspace-folder . pip install pip-install-test
|
||||
devcontainer exec --workspace-folder . touch /home/batman/.comma/auth.json
|
||||
devcontainer exec --workspace-folder . sudo touch /root/test.txt
|
||||
devcontainer exec --workspace-folder . sudo touch /root/test.txt
|
||||
|
||||
notebooks:
|
||||
name: notebooks
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.repository == 'commaai/openpilot'
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: ./.github/workflows/setup-with-retry
|
||||
- name: Build openpilot
|
||||
timeout-minutes: 5
|
||||
run: ${{ env.RUN }} "scons -j$(nproc)"
|
||||
- name: Test notebooks
|
||||
timeout-minutes: 2
|
||||
run: |
|
||||
${{ env.RUN }} "pip install nbmake && pytest --nbmake tools/car_porting/examples/"
|
||||
@@ -46,7 +46,6 @@ selfdrive/boardd/boardd
|
||||
selfdrive/logcatd/logcatd
|
||||
selfdrive/mapd/default_speeds_by_region.json
|
||||
system/proclogd/proclogd
|
||||
selfdrive/ui/_ui
|
||||
selfdrive/ui/translations/alerts_generated.h
|
||||
selfdrive/ui/translations/tmp
|
||||
selfdrive/test/longitudinal_maneuvers/out
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
[submodule "opendbc"]
|
||||
path = opendbc
|
||||
url = ../../sunnyhaibin/opendbc.git
|
||||
[submodule "laika_repo"]
|
||||
path = laika_repo
|
||||
url = ../../commaai/laika.git
|
||||
[submodule "cereal"]
|
||||
path = cereal
|
||||
url = ../../sunnyhaibin/cereal.git
|
||||
@@ -16,6 +13,9 @@
|
||||
[submodule "body"]
|
||||
path = body
|
||||
url = ../../commaai/body.git
|
||||
[submodule "teleoprtc_repo"]
|
||||
path = teleoprtc_repo
|
||||
url = ../../commaai/teleoprtc
|
||||
[submodule "tinygrad"]
|
||||
path = tinygrad_repo
|
||||
url = https://github.com/geohot/tinygrad.git
|
||||
|
||||
@@ -19,14 +19,15 @@ repos:
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-shebang-scripts-are-executable
|
||||
- id: check-added-large-files
|
||||
exclude: '(docs/CARS.md)|(poetry.lock)|(third_party/acados/include/blasfeo/include/blasfeo_d_kernel.h)'
|
||||
args:
|
||||
- --maxkb=500
|
||||
- --maxkb=120
|
||||
- --enforce-all
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.2.6
|
||||
hooks:
|
||||
- id: codespell
|
||||
exclude: '^(third_party/)|(body/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)'
|
||||
exclude: '^(third_party/)|(body/)|(cereal/)|(panda/)|(opendbc/)|(rednose/)|(rednose_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)'
|
||||
args:
|
||||
# if you've got a short variable name that's getting flagged, add it here
|
||||
- -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints
|
||||
@@ -38,13 +39,15 @@ repos:
|
||||
entry: mypy
|
||||
language: system
|
||||
types: [python]
|
||||
args: ['--explicit-package-bases']
|
||||
exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)'
|
||||
args:
|
||||
- --local-partial-types
|
||||
- --explicit-package-bases
|
||||
exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(xx/)'
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.1.4
|
||||
rev: v0.1.14
|
||||
hooks:
|
||||
- id: ruff
|
||||
exclude: '^(third_party/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)'
|
||||
exclude: '^(third_party/)|(cereal/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: cppcheck
|
||||
@@ -78,6 +81,7 @@ repos:
|
||||
entry: selfdrive/ui/tests/test_translations.py
|
||||
language: script
|
||||
pass_filenames: false
|
||||
files: 'selfdrive/ui/translations/*'
|
||||
- repo: https://github.com/python-poetry/poetry
|
||||
rev: '1.7.0'
|
||||
hooks:
|
||||
@@ -86,6 +90,6 @@ repos:
|
||||
args:
|
||||
- --lock
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.27.1
|
||||
rev: 0.27.3
|
||||
hooks:
|
||||
- id: check-github-workflows
|
||||
|
||||
@@ -13,9 +13,8 @@ COPY SConstruct ${OPENPILOT_PATH}
|
||||
COPY ./openpilot ${OPENPILOT_PATH}/openpilot
|
||||
COPY ./third_party ${OPENPILOT_PATH}/third_party
|
||||
COPY ./site_scons ${OPENPILOT_PATH}/site_scons
|
||||
COPY ./laika ${OPENPILOT_PATH}/laika
|
||||
COPY ./laika_repo ${OPENPILOT_PATH}/laika_repo
|
||||
COPY ./rednose ${OPENPILOT_PATH}/rednose
|
||||
COPY ./rednose_repo/site_scons ${OPENPILOT_PATH}/rednose_repo/site_scons
|
||||
COPY ./tools ${OPENPILOT_PATH}/tools
|
||||
COPY ./release ${OPENPILOT_PATH}/release
|
||||
COPY ./common ${OPENPILOT_PATH}/common
|
||||
|
||||
@@ -4,7 +4,7 @@ ENV PYTHONUNBUFFERED 1
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends sudo tzdata locales ssh && \
|
||||
apt-get install -y --no-install-recommends sudo tzdata locales ssh pulseaudio && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
|
||||
@@ -40,7 +40,9 @@ COPY --chown=$USER tools/install_python_dependencies.sh /tmp/tools/
|
||||
RUN cd /tmp && \
|
||||
tools/install_python_dependencies.sh && \
|
||||
rm -rf /tmp/* && \
|
||||
rm -rf /home/$USER/.cache
|
||||
rm -rf /home/$USER/.cache && \
|
||||
find /home/$USER/pyenv -type d -name ".git" | xargs rm -rf && \
|
||||
rm -rf /home/$USER/pyenv/versions/3.11.4/lib/python3.11/test
|
||||
|
||||
USER root
|
||||
RUN sudo git config --global --add safe.directory /tmp/openpilot
|
||||
@@ -1,3 +1,14 @@
|
||||
def retryWithDelay(int maxRetries, int delay, Closure body) {
|
||||
for (int i = 0; i < maxRetries; i++) {
|
||||
try {
|
||||
return body()
|
||||
} catch (Exception e) {
|
||||
sleep(delay)
|
||||
}
|
||||
}
|
||||
throw Exception("Failed after ${maxRetries} retries")
|
||||
}
|
||||
|
||||
def device(String ip, String step_label, String cmd) {
|
||||
withCredentials([file(credentialsId: 'id_rsa', variable: 'key_file')]) {
|
||||
def ssh_cmd = """
|
||||
@@ -14,6 +25,9 @@ export GIT_BRANCH=${env.GIT_BRANCH}
|
||||
export GIT_COMMIT=${env.GIT_COMMIT}
|
||||
export AZURE_TOKEN='${env.AZURE_TOKEN}'
|
||||
export MAPBOX_TOKEN='${env.MAPBOX_TOKEN}'
|
||||
# only use 1 thread for tici tests since most require HIL
|
||||
export PYTEST_ADDOPTS="-n 0"
|
||||
|
||||
|
||||
export GIT_SSH_COMMAND="ssh -i /data/gitkey"
|
||||
|
||||
@@ -21,7 +35,9 @@ source ~/.bash_profile
|
||||
if [ -f /TICI ]; then
|
||||
source /etc/profile
|
||||
|
||||
rm -rf /tmp/tmp*
|
||||
rm -rf ~/.commacache
|
||||
rm -rf /dev/shm/*
|
||||
|
||||
if ! systemctl is-active --quiet systemd-resolved; then
|
||||
echo "restarting resolved"
|
||||
@@ -53,13 +69,14 @@ END"""
|
||||
}
|
||||
}
|
||||
|
||||
def deviceStage(String stageName, String deviceType, List env, def steps) {
|
||||
def deviceStage(String stageName, String deviceType, List extra_env, def steps) {
|
||||
stage(stageName) {
|
||||
if (currentBuild.result != null) {
|
||||
return
|
||||
}
|
||||
|
||||
def extra = env.collect { "export ${it}" }.join('\n');
|
||||
def extra = extra_env.collect { "export ${it}" }.join('\n');
|
||||
def branch = env.BRANCH_NAME ?: 'master';
|
||||
|
||||
docker.image('ghcr.io/commaai/alpine-ssh').inside('--user=root') {
|
||||
lock(resource: "", label: deviceType, inversePrecedence: true, variable: 'device_ip', quantity: 1) {
|
||||
@@ -68,6 +85,10 @@ def deviceStage(String stageName, String deviceType, List env, def steps) {
|
||||
device(device_ip, "git checkout", extra + "\n" + readFile("selfdrive/test/setup_device_ci.sh"))
|
||||
}
|
||||
steps.each { item ->
|
||||
if (branch != "master" && item.size() == 3 && !hasDirectoryChanged(item[2])) {
|
||||
println "Skipped '${item[0]}', no relevant changes were detected."
|
||||
return;
|
||||
}
|
||||
device(device_ip, item[0], item[1])
|
||||
}
|
||||
}
|
||||
@@ -85,26 +106,31 @@ def pcStage(String stageName, Closure body) {
|
||||
|
||||
checkout scm
|
||||
|
||||
def dockerArgs = '--user=batman -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/scons_cache:/tmp/scons_cache';
|
||||
docker.build("openpilot-base:build-${env.GIT_COMMIT}", "-f Dockerfile.openpilot_base .").inside(dockerArgs) {
|
||||
timeout(time: 20, unit: 'MINUTES') {
|
||||
try {
|
||||
// TODO: remove these after all jenkins jobs are running as batman (merged with master)
|
||||
sh "sudo chown -R batman:batman /tmp/scons_cache"
|
||||
sh "sudo chown -R batman:batman /tmp/comma_download_cache"
|
||||
def dockerArgs = "--user=batman -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/scons_cache:/tmp/scons_cache -e PYTHONPATH=${env.WORKSPACE}";
|
||||
|
||||
sh "git config --global --add safe.directory '*'"
|
||||
sh "git submodule update --init --recursive"
|
||||
sh "git lfs pull"
|
||||
body()
|
||||
} finally {
|
||||
sh "rm -rf ${env.WORKSPACE}/* || true"
|
||||
sh "rm -rf .* || true"
|
||||
def openpilot_base = retryWithDelay (3, 15) {
|
||||
return docker.build("openpilot-base:build-${env.GIT_COMMIT}", "-f Dockerfile.openpilot_base .")
|
||||
}
|
||||
|
||||
lock(resource: "", label: 'pc', inversePrecedence: true, quantity: 1) {
|
||||
openpilot_base.inside(dockerArgs) {
|
||||
timeout(time: 20, unit: 'MINUTES') {
|
||||
try {
|
||||
retryWithDelay (3, 15) {
|
||||
sh "git config --global --add safe.directory '*'"
|
||||
sh "git submodule update --init --recursive"
|
||||
sh "git lfs pull"
|
||||
}
|
||||
body()
|
||||
} finally {
|
||||
sh "rm -rf ${env.WORKSPACE}/* || true"
|
||||
sh "rm -rf .* || true"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def setupCredentials() {
|
||||
@@ -117,6 +143,21 @@ def setupCredentials() {
|
||||
}
|
||||
}
|
||||
|
||||
def hasDirectoryChanged(List<String> paths) {
|
||||
for (change in currentBuild.changeSets) {
|
||||
for (item in change.items) {
|
||||
for (affectedPath in item.affectedPaths) {
|
||||
for (path in paths) {
|
||||
if (affectedPath.startsWith(path)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
node {
|
||||
env.CI = "1"
|
||||
env.PYTHONWARNINGS = "error"
|
||||
@@ -128,7 +169,7 @@ node {
|
||||
env.GIT_COMMIT = checkout(scm).GIT_COMMIT
|
||||
|
||||
def excludeBranches = ['master-ci', 'devel', 'devel-staging', 'release3', 'release3-staging',
|
||||
'dashcam3', 'dashcam3-staging', 'testing-closet*', 'hotfix-*']
|
||||
'testing-closet*', 'hotfix-*']
|
||||
def excludeRegex = excludeBranches.join('|').replaceAll('\\*', '.*')
|
||||
|
||||
if (env.BRANCH_NAME != 'master') {
|
||||
@@ -140,7 +181,7 @@ node {
|
||||
try {
|
||||
if (env.BRANCH_NAME == 'devel-staging') {
|
||||
deviceStage("build release3-staging", "tici-needs-can", [], [
|
||||
["build release3-staging & dashcam3-staging", "RELEASE_BRANCH=release3-staging DASHCAM_BRANCH=dashcam3-staging $SOURCE_DIR/release/build_release.sh"],
|
||||
["build release3-staging", "RELEASE_BRANCH=release3-staging $SOURCE_DIR/release/build_release.sh"],
|
||||
])
|
||||
}
|
||||
|
||||
@@ -154,23 +195,23 @@ node {
|
||||
parallel (
|
||||
// tici tests
|
||||
'onroad tests': {
|
||||
deviceStage("onroad", "tici-needs-can", ["SKIP_COPY=1"], [
|
||||
["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR ./build_devel.sh"],
|
||||
deviceStage("onroad", "tici-needs-can", [], [
|
||||
// TODO: ideally, this test runs in master-ci, but it takes 5+m to build it
|
||||
//["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR $SOURCE_DIR/scripts/retry.sh ./build_devel.sh"],
|
||||
["build openpilot", "cd selfdrive/manager && ./build.py"],
|
||||
["check dirty", "release/check-dirty.sh"],
|
||||
["onroad tests", "pytest selfdrive/test/test_onroad.py -s"],
|
||||
["time to onroad", "cd selfdrive/test/ && pytest test_time_to_onroad.py"],
|
||||
["time to onroad", "pytest selfdrive/test/test_time_to_onroad.py"],
|
||||
])
|
||||
},
|
||||
'HW + Unit Tests': {
|
||||
deviceStage("tici", "tici-common", ["UNSAFE=1"], [
|
||||
["build", "cd selfdrive/manager && ./build.py"],
|
||||
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
|
||||
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py", ["panda/", "selfdrive/boardd/"]],
|
||||
["test power draw", "./system/hardware/tici/tests/test_power_draw.py"],
|
||||
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"],
|
||||
["test pigeond", "pytest system/sensord/tests/test_pigeond.py"],
|
||||
["test manager", "pytest selfdrive/manager/test/test_manager.py"],
|
||||
["test nav", "pytest selfdrive/navd/tests/"],
|
||||
])
|
||||
},
|
||||
'loopback': {
|
||||
@@ -194,27 +235,27 @@ node {
|
||||
'sensord': {
|
||||
deviceStage("LSM + MMC", "tici-lsmc", ["UNSAFE=1"], [
|
||||
["build", "cd selfdrive/manager && ./build.py"],
|
||||
["test sensord", "cd system/sensord/tests && pytest test_sensord.py"],
|
||||
["test sensord", "pytest system/sensord/tests/test_sensord.py"],
|
||||
])
|
||||
deviceStage("BMX + LSM", "tici-bmx-lsm", ["UNSAFE=1"], [
|
||||
["build", "cd selfdrive/manager && ./build.py"],
|
||||
["test sensord", "cd system/sensord/tests && pytest test_sensord.py"],
|
||||
["test sensord", "pytest system/sensord/tests/test_sensord.py"],
|
||||
])
|
||||
},
|
||||
'replay': {
|
||||
deviceStage("tici", "tici-replay", ["UNSAFE=1"], [
|
||||
["build", "cd selfdrive/manager && ./build.py"],
|
||||
["model replay", "cd selfdrive/test/process_replay && ./model_replay.py"],
|
||||
["model replay", "selfdrive/test/process_replay/model_replay.py"],
|
||||
])
|
||||
},
|
||||
'tizi': {
|
||||
deviceStage("tizi", "tizi", ["UNSAFE=1"], [
|
||||
["build openpilot", "cd selfdrive/manager && ./build.py"],
|
||||
["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
|
||||
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
|
||||
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py", ["panda/", "selfdrive/boardd/"]],
|
||||
["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"],
|
||||
["test hw", "pytest system/hardware/tici/tests/test_hardware.py"],
|
||||
["test rawgpsd", "pytest system/sensord/rawgps/test_rawgps.py"],
|
||||
["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py", ["system/qcomgpsd/"]],
|
||||
])
|
||||
},
|
||||
|
||||
@@ -223,15 +264,16 @@ node {
|
||||
pcStage("PC tests") {
|
||||
// tests that our build system's dependencies are configured properly,
|
||||
// needs a machine with lots of cores
|
||||
sh label: "test multi-threaded build", script: "scons --no-cache --random -j42"
|
||||
sh label: "test multi-threaded build",
|
||||
script: '''#!/bin/bash
|
||||
scons --no-cache --random -j$(nproc)'''
|
||||
}
|
||||
},
|
||||
'car tests': {
|
||||
pcStage("car tests") {
|
||||
sh "scons -j30"
|
||||
sh label: "test_models.py", script: "INTERNAL_SEG_CNT=250 INTERNAL_SEG_LIST=selfdrive/car/tests/test_models_segs.txt FILEREADER_CACHE=1 \
|
||||
pytest -n42 --dist=loadscope selfdrive/car/tests/test_models.py"
|
||||
sh label: "test_car_interfaces.py", script: "MAX_EXAMPLES=100 pytest -n42 selfdrive/car/tests/test_car_interfaces.py"
|
||||
sh label: "build", script: "selfdrive/manager/build.py"
|
||||
sh label: "run car tests", script: "cd selfdrive/car/tests && MAX_EXAMPLES=300 INTERNAL_SEG_CNT=300 FILEREADER_CACHE=1 \
|
||||
INTERNAL_SEG_LIST=selfdrive/car/tests/test_models_segs.txt pytest test_models.py test_car_interfaces.py"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
Version 0.9.5 (2023-11-16)
|
||||
Version 0.9.6 (20XX-XX-XX)
|
||||
========================
|
||||
* New driving model
|
||||
* Vision model trained on more data
|
||||
* Improved driving performance
|
||||
* AGNOS 9
|
||||
* comma body streaming and controls over WebRTC
|
||||
* Hyundai Staria 2023 support thanks to sunnyhaibin!
|
||||
* Kia Niro Plug-in Hybrid 2022 support thanks to sunnyhaibin!
|
||||
* Toyota RAV4 2023-24 support
|
||||
* Toyota RAV4 Hybrid 2023-24 support
|
||||
|
||||
Version 0.9.5 (2023-11-17)
|
||||
========================
|
||||
* New driving model
|
||||
* Improved navigate on openpilot performance using navigation instructions as an additional model input
|
||||
@@ -8,11 +20,12 @@ Version 0.9.5 (2023-11-16)
|
||||
* Hyundai Azera 2022 support thanks to sunnyhaibin!
|
||||
* Hyundai Azera Hybrid 2020 support thanks to chanhojung and haram-KONA!
|
||||
* Hyundai Custin 2023 support thanks to sunnyhaibin and Saber422!
|
||||
* Hyundai Ioniq 6 2023 support thanks to sunnyhaibin, alamo3, and sshane!
|
||||
* Hyundai Ioniq 6 2023 support thanks to sunnyhaibin and alamo3!
|
||||
* Hyundai Kona Electric 2023 (Korean version) support thanks to sunnyhaibin and haram-KONA!
|
||||
* Kia K8 Hybrid (with HDA II) 2023 support thanks to sunnyhaibin!
|
||||
* Kia Sorento Hybrid 2023 support thanks to sunnyhaibin!
|
||||
* Kia Optima Hybrid 2019 support
|
||||
* Kia Sorento Hybrid 2023 support thanks to sunnyhaibin!
|
||||
* Lexus GS F 2016 support thanks to snyperifle!
|
||||
* Lexus IS 2023 support thanks to L3R5!
|
||||
|
||||
Version 0.9.4 (2023-07-27)
|
||||
|
||||
@@ -9,11 +9,16 @@ import SCons.Errors
|
||||
|
||||
SCons.Warnings.warningAsException(True)
|
||||
|
||||
# pending upstream fix - https://github.com/SCons/scons/issues/4461
|
||||
#SetOption('warn', 'all')
|
||||
|
||||
TICI = os.path.isfile('/TICI')
|
||||
AGNOS = TICI
|
||||
|
||||
Decider('MD5-timestamp')
|
||||
|
||||
SetOption('num_jobs', int(os.cpu_count()/2))
|
||||
|
||||
AddOption('--kaitai',
|
||||
action='store_true',
|
||||
help='Regenerate kaitai struct parsers')
|
||||
@@ -38,6 +43,12 @@ AddOption('--compile_db',
|
||||
action='store_true',
|
||||
help='build clang compilation database')
|
||||
|
||||
AddOption('--ccflags',
|
||||
action='store',
|
||||
type='string',
|
||||
default='',
|
||||
help='pass arbitrary flags over the command line')
|
||||
|
||||
AddOption('--snpe',
|
||||
action='store_true',
|
||||
help='use SNPE on PC')
|
||||
@@ -56,7 +67,7 @@ AddOption('--pc-thneed',
|
||||
AddOption('--minimal',
|
||||
action='store_false',
|
||||
dest='extras',
|
||||
default=os.path.islink(Dir('#laika/').abspath),
|
||||
default=os.path.islink(Dir('#rednose/').abspath), # minimal by default on release branch (where rednose is not a link)
|
||||
help='the minimum build to run openpilot. no tests, tools, etc.')
|
||||
|
||||
## Architecture name breakdown (arch)
|
||||
@@ -110,10 +121,7 @@ else:
|
||||
cflags = []
|
||||
cxxflags = []
|
||||
cpppath = []
|
||||
rpath += [
|
||||
Dir("#cereal").abspath,
|
||||
Dir("#common").abspath
|
||||
]
|
||||
rpath += []
|
||||
|
||||
# MacOS
|
||||
if arch == "Darwin":
|
||||
@@ -138,8 +146,6 @@ else:
|
||||
f"#third_party/acados/{arch}/lib",
|
||||
f"#third_party/libyuv/{arch}/lib",
|
||||
f"#third_party/mapbox-gl-native-qt/{arch}",
|
||||
"#cereal",
|
||||
"#common",
|
||||
"/usr/lib",
|
||||
"/usr/local/lib",
|
||||
]
|
||||
@@ -170,6 +176,10 @@ if arch != "Darwin":
|
||||
cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
|
||||
cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
|
||||
|
||||
ccflags_option = GetOption('ccflags')
|
||||
if ccflags_option:
|
||||
ccflags += ccflags_option.split(' ')
|
||||
|
||||
env = Environment(
|
||||
ENV=lenv,
|
||||
CCFLAGS=[
|
||||
@@ -219,10 +229,13 @@ env = Environment(
|
||||
"#opendbc/can",
|
||||
"#selfdrive/boardd",
|
||||
"#common",
|
||||
"#rednose/helpers",
|
||||
],
|
||||
CYTHONCFILESUFFIX=".cpp",
|
||||
COMPILATIONDB_USE_ABSPATH=True,
|
||||
tools=["default", "cython", "compilation_db"],
|
||||
REDNOSE_ROOT="#",
|
||||
tools=["default", "cython", "compilation_db", "rednose_filter"],
|
||||
toolpath=["#rednose_repo/site_scons/site_tools"],
|
||||
)
|
||||
|
||||
if arch == "Darwin":
|
||||
@@ -284,8 +297,11 @@ else:
|
||||
qt_env['QTDIR'] = qt_install_prefix
|
||||
qt_dirs = [
|
||||
f"{qt_install_headers}",
|
||||
f"{qt_install_headers}/QtGui/5.12.8/QtGui",
|
||||
]
|
||||
|
||||
qt_gui_path = os.path.join(qt_install_headers, "QtGui")
|
||||
qt_gui_dirs = [d for d in os.listdir(qt_gui_path) if os.path.isdir(os.path.join(qt_gui_path, d))]
|
||||
qt_dirs += [f"{qt_install_headers}/QtGui/{qt_gui_dirs[0]}/QtGui", ] if qt_gui_dirs else []
|
||||
qt_dirs += [f"{qt_install_headers}/Qt{m}" for m in qt_modules]
|
||||
|
||||
qt_libs = [f"Qt5{m}" for m in qt_modules]
|
||||
@@ -357,31 +373,7 @@ SConscript([
|
||||
'panda/SConscript',
|
||||
])
|
||||
|
||||
# Build rednose library and ekf models
|
||||
rednose_deps = [
|
||||
"#selfdrive/locationd/models/constants.py",
|
||||
"#selfdrive/locationd/models/gnss_helpers.py",
|
||||
]
|
||||
|
||||
rednose_config = {
|
||||
'generated_folder': '#selfdrive/locationd/models/generated',
|
||||
'to_build': {
|
||||
'gnss': ('#selfdrive/locationd/models/gnss_kf.py', True, [], rednose_deps),
|
||||
'live': ('#selfdrive/locationd/models/live_kf.py', True, ['live_kf_constants.h'], rednose_deps),
|
||||
'car': ('#selfdrive/locationd/models/car_kf.py', True, [], rednose_deps),
|
||||
},
|
||||
}
|
||||
|
||||
if arch != "larch64":
|
||||
rednose_config['to_build'].update({
|
||||
'loc_4': ('#selfdrive/locationd/models/loc_kf.py', True, [], rednose_deps),
|
||||
'lane': ('#selfdrive/locationd/models/lane_kf.py', True, [], rednose_deps),
|
||||
'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', False, [], []),
|
||||
'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', False, [], []),
|
||||
'feature_handler_5': ('#rednose/helpers/feature_handler.py', False, [], []),
|
||||
})
|
||||
|
||||
Export('rednose_config')
|
||||
# Build rednose library
|
||||
SConscript(['rednose/SConscript'])
|
||||
|
||||
# Build system services
|
||||
|
||||
@@ -9,4 +9,5 @@ coverage:
|
||||
ignore:
|
||||
- "**/test_*.py"
|
||||
- "selfdrive/test/**"
|
||||
- "system/version.py" # codecov changes depending on if we are in a branch or not
|
||||
- "system/version.py" # codecov changes depending on if we are in a branch or not
|
||||
- "tools"
|
||||
|
||||
@@ -2,7 +2,6 @@ Import('env', 'envCython', 'arch')
|
||||
|
||||
common_libs = [
|
||||
'params.cc',
|
||||
'statlog.cc',
|
||||
'swaglog.cc',
|
||||
'util.cc',
|
||||
'i2c.cc',
|
||||
@@ -24,18 +23,17 @@ Export('_common', '_gpucommon')
|
||||
|
||||
if GetOption('extras'):
|
||||
env.Program('tests/test_common',
|
||||
['tests/test_runner.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc', 'tests/test_ratekeeper.cc'],
|
||||
['tests/test_runner.cc', 'tests/test_params.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc'],
|
||||
LIBS=[_common, 'json11', 'zmq', 'pthread'])
|
||||
|
||||
# Cython bindings
|
||||
params_python = envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq', 'json11'])
|
||||
|
||||
SConscript([
|
||||
'kalman/SConscript',
|
||||
'transformations/SConscript'
|
||||
'transformations/SConscript',
|
||||
])
|
||||
|
||||
Import('simple_kalman_python', 'transformations_python')
|
||||
common_python = [params_python, simple_kalman_python, transformations_python]
|
||||
Import('transformations_python')
|
||||
common_python = [params_python, transformations_python]
|
||||
|
||||
Export('common_python')
|
||||
|
||||
@@ -2,7 +2,7 @@ import jwt
|
||||
import os
|
||||
import requests
|
||||
from datetime import datetime, timedelta
|
||||
from openpilot.common.basedir import PERSIST
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.system.version import get_version
|
||||
|
||||
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
|
||||
@@ -10,7 +10,7 @@ API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
|
||||
class Api():
|
||||
def __init__(self, dongle_id):
|
||||
self.dongle_id = dongle_id
|
||||
with open(PERSIST+'/comma/id_rsa') as f:
|
||||
with open(Paths.persist_root()+'/comma/id_rsa') as f:
|
||||
self.private_key = f.read()
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from openpilot.system.hardware import PC
|
||||
|
||||
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))
|
||||
|
||||
if PC:
|
||||
PERSIST = os.path.join(str(Path.home()), ".comma", "persist")
|
||||
else:
|
||||
PERSIST = "/persist"
|
||||
|
||||
@@ -1,55 +1,8 @@
|
||||
import os
|
||||
import sys
|
||||
import fcntl
|
||||
import hashlib
|
||||
import platform
|
||||
from cffi import FFI
|
||||
|
||||
|
||||
def suffix():
|
||||
if platform.system() == "Darwin":
|
||||
return ".dylib"
|
||||
else:
|
||||
return ".so"
|
||||
|
||||
def ffi_wrap(name, c_code, c_header, tmpdir="/tmp/ccache", cflags="", libraries=None):
|
||||
if libraries is None:
|
||||
libraries = []
|
||||
|
||||
cache = name + "_" + hashlib.sha1(c_code.encode('utf-8')).hexdigest()
|
||||
try:
|
||||
os.mkdir(tmpdir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
fd = os.open(tmpdir, 0)
|
||||
fcntl.flock(fd, fcntl.LOCK_EX)
|
||||
try:
|
||||
sys.path.append(tmpdir)
|
||||
try:
|
||||
mod = __import__(cache)
|
||||
except Exception:
|
||||
print(f"cache miss {cache}")
|
||||
compile_code(cache, c_code, c_header, tmpdir, cflags, libraries)
|
||||
mod = __import__(cache)
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
return mod.ffi, mod.lib
|
||||
|
||||
|
||||
def compile_code(name, c_code, c_header, directory, cflags="", libraries=None):
|
||||
if libraries is None:
|
||||
libraries = []
|
||||
|
||||
ffibuilder = FFI()
|
||||
ffibuilder.set_source(name, c_code, source_extension='.cpp', libraries=libraries)
|
||||
ffibuilder.cdef(c_header)
|
||||
os.environ['OPT'] = "-fwrapv -O2 -DNDEBUG -std=c++1z"
|
||||
os.environ['CFLAGS'] = cflags
|
||||
ffibuilder.compile(verbose=True, debug=False, tmpdir=directory)
|
||||
|
||||
|
||||
def wrap_compiled(name, directory):
|
||||
sys.path.append(directory)
|
||||
mod = __import__(name)
|
||||
return mod.ffi, mod.lib
|
||||
|
||||
@@ -1,60 +1,7 @@
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from atomicwrites import AtomicWriter
|
||||
|
||||
|
||||
def mkdirs_exists_ok(path):
|
||||
if path.startswith(('http://', 'https://')):
|
||||
raise ValueError('URL path')
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError:
|
||||
if not os.path.isdir(path):
|
||||
raise
|
||||
|
||||
|
||||
def rm_not_exists_ok(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except OSError:
|
||||
if os.path.exists(path):
|
||||
raise
|
||||
|
||||
|
||||
def rm_tree_or_link(path):
|
||||
if os.path.islink(path):
|
||||
os.unlink(path)
|
||||
elif os.path.isdir(path):
|
||||
shutil.rmtree(path)
|
||||
|
||||
|
||||
def get_tmpdir_on_same_filesystem(path):
|
||||
normpath = os.path.normpath(path)
|
||||
parts = normpath.split("/")
|
||||
if len(parts) > 1 and parts[1] == "scratch":
|
||||
return "/scratch/tmp"
|
||||
elif len(parts) > 2 and parts[2] == "runner":
|
||||
return f"/{parts[1]}/runner/tmp"
|
||||
return "/tmp"
|
||||
|
||||
|
||||
class NamedTemporaryDir():
|
||||
def __init__(self, temp_dir=None):
|
||||
self._path = tempfile.mkdtemp(dir=temp_dir)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._path
|
||||
|
||||
def close(self):
|
||||
shutil.rmtree(self._path)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
import contextlib
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class CallbackReader:
|
||||
@@ -76,24 +23,16 @@ class CallbackReader:
|
||||
return chunk
|
||||
|
||||
|
||||
def _get_fileobject_func(writer, temp_dir):
|
||||
def _get_fileobject():
|
||||
return writer.get_fileobject(dir=temp_dir)
|
||||
return _get_fileobject
|
||||
@contextlib.contextmanager
|
||||
def atomic_write_in_dir(path: str, mode: str = 'w', buffering: int = -1, encoding: Optional[str] = None, newline: Optional[str] = None,
|
||||
overwrite: bool = False):
|
||||
"""Write to a file atomically using a temporary file in the same directory as the destination file."""
|
||||
dir_name = os.path.dirname(path)
|
||||
|
||||
def atomic_write_on_fs_tmp(path, **kwargs):
|
||||
"""Creates an atomic writer using a temporary file in a temporary directory
|
||||
on the same filesystem as path.
|
||||
"""
|
||||
# TODO(mgraczyk): This use of AtomicWriter relies on implementation details to set the temp
|
||||
# directory.
|
||||
writer = AtomicWriter(path, **kwargs)
|
||||
return writer._open(_get_fileobject_func(writer, get_tmpdir_on_same_filesystem(path)))
|
||||
if not overwrite and os.path.exists(path):
|
||||
raise FileExistsError(f"File '{path}' already exists. To overwrite it, set 'overwrite' to True.")
|
||||
|
||||
|
||||
def atomic_write_in_dir(path, **kwargs):
|
||||
"""Creates an atomic writer using a temporary file in the same directory
|
||||
as the destination file.
|
||||
"""
|
||||
writer = AtomicWriter(path, **kwargs)
|
||||
return writer._open(_get_fileobject_func(writer, os.path.dirname(path)))
|
||||
with tempfile.NamedTemporaryFile(mode=mode, buffering=buffering, encoding=encoding, newline=newline, dir=dir_name, delete=False) as tmp_file:
|
||||
yield tmp_file
|
||||
tmp_file_name = tmp_file.name
|
||||
os.replace(tmp_file_name, path)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
simple_kalman_impl.c
|
||||
@@ -1,5 +0,0 @@
|
||||
Import('envCython')
|
||||
|
||||
simple_kalman_python = envCython.Program('simple_kalman_impl.so', 'simple_kalman_impl.pyx')
|
||||
|
||||
Export('simple_kalman_python')
|
||||
@@ -1,12 +0,0 @@
|
||||
from openpilot.common.kalman.simple_kalman_impl import KF1D as KF1D
|
||||
assert KF1D
|
||||
import numpy as np
|
||||
|
||||
def get_kalman_gain(dt, A, C, Q, R, iterations=100):
|
||||
P = np.zeros_like(Q)
|
||||
for _ in range(iterations):
|
||||
P = A.dot(P).dot(A.T) + dt * Q
|
||||
S = C.dot(P).dot(C.T) + R
|
||||
K = P.dot(C.T).dot(np.linalg.inv(S))
|
||||
P = (np.eye(len(P)) - K.dot(C)).dot(P)
|
||||
return K
|
||||
@@ -1,18 +0,0 @@
|
||||
# cython: language_level = 3
|
||||
|
||||
cdef class KF1D:
|
||||
cdef public:
|
||||
double x0_0
|
||||
double x1_0
|
||||
double K0_0
|
||||
double K1_0
|
||||
double A0_0
|
||||
double A0_1
|
||||
double A1_0
|
||||
double A1_1
|
||||
double C0_0
|
||||
double C0_1
|
||||
double A_K_0
|
||||
double A_K_1
|
||||
double A_K_2
|
||||
double A_K_3
|
||||
@@ -1,37 +0,0 @@
|
||||
# distutils: language = c++
|
||||
# cython: language_level=3
|
||||
|
||||
cdef class KF1D:
|
||||
def __init__(self, x0, A, C, K):
|
||||
self.x0_0 = x0[0][0]
|
||||
self.x1_0 = x0[1][0]
|
||||
self.A0_0 = A[0][0]
|
||||
self.A0_1 = A[0][1]
|
||||
self.A1_0 = A[1][0]
|
||||
self.A1_1 = A[1][1]
|
||||
self.C0_0 = C[0]
|
||||
self.C0_1 = C[1]
|
||||
self.K0_0 = K[0][0]
|
||||
self.K1_0 = K[1][0]
|
||||
|
||||
self.A_K_0 = self.A0_0 - self.K0_0 * self.C0_0
|
||||
self.A_K_1 = self.A0_1 - self.K0_0 * self.C0_1
|
||||
self.A_K_2 = self.A1_0 - self.K1_0 * self.C0_0
|
||||
self.A_K_3 = self.A1_1 - self.K1_0 * self.C0_1
|
||||
|
||||
def update(self, meas):
|
||||
cdef double x0_0 = self.A_K_0 * self.x0_0 + self.A_K_1 * self.x1_0 + self.K0_0 * meas
|
||||
cdef double x1_0 = self.A_K_2 * self.x0_0 + self.A_K_3 * self.x1_0 + self.K1_0 * meas
|
||||
self.x0_0 = x0_0
|
||||
self.x1_0 = x1_0
|
||||
|
||||
return [self.x0_0, self.x1_0]
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return [[self.x0_0], [self.x1_0]]
|
||||
|
||||
@x.setter
|
||||
def x(self, x):
|
||||
self.x0_0 = x[0][0]
|
||||
self.x1_0 = x[1][0]
|
||||
@@ -1,23 +0,0 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
class KF1D:
|
||||
# this EKF assumes constant covariance matrix, so calculations are much simpler
|
||||
# the Kalman gain also needs to be precomputed using the control module
|
||||
|
||||
def __init__(self, x0, A, C, K):
|
||||
self.x = x0
|
||||
self.A = A
|
||||
self.C = np.atleast_2d(C)
|
||||
self.K = K
|
||||
|
||||
self.A_K = self.A - np.dot(self.K, self.C)
|
||||
|
||||
# K matrix needs to be pre-computed as follow:
|
||||
# import control
|
||||
# (x, l, K) = control.dare(np.transpose(self.A), np.transpose(self.C), Q, R)
|
||||
# self.K = np.transpose(K)
|
||||
|
||||
def update(self, meas):
|
||||
self.x = np.dot(self.A_K, self.x) + np.dot(self.K, meas)
|
||||
return self.x
|
||||
@@ -1,87 +0,0 @@
|
||||
import unittest
|
||||
import random
|
||||
import timeit
|
||||
import numpy as np
|
||||
|
||||
from openpilot.common.kalman.simple_kalman import KF1D
|
||||
from openpilot.common.kalman.simple_kalman_old import KF1D as KF1D_old
|
||||
|
||||
|
||||
class TestSimpleKalman(unittest.TestCase):
|
||||
def setUp(self):
|
||||
dt = 0.01
|
||||
x0_0 = 0.0
|
||||
x1_0 = 0.0
|
||||
A0_0 = 1.0
|
||||
A0_1 = dt
|
||||
A1_0 = 0.0
|
||||
A1_1 = 1.0
|
||||
C0_0 = 1.0
|
||||
C0_1 = 0.0
|
||||
K0_0 = 0.12287673
|
||||
K1_0 = 0.29666309
|
||||
|
||||
self.kf_old = KF1D_old(x0=np.array([[x0_0], [x1_0]]),
|
||||
A=np.array([[A0_0, A0_1], [A1_0, A1_1]]),
|
||||
C=np.array([C0_0, C0_1]),
|
||||
K=np.array([[K0_0], [K1_0]]))
|
||||
|
||||
self.kf = KF1D(x0=[[x0_0], [x1_0]],
|
||||
A=[[A0_0, A0_1], [A1_0, A1_1]],
|
||||
C=[C0_0, C0_1],
|
||||
K=[[K0_0], [K1_0]])
|
||||
|
||||
def test_getter_setter(self):
|
||||
self.kf.x = [[1.0], [1.0]]
|
||||
self.assertEqual(self.kf.x, [[1.0], [1.0]])
|
||||
|
||||
def update_returns_state(self):
|
||||
x = self.kf.update(100)
|
||||
self.assertEqual(x, self.kf.x)
|
||||
|
||||
def test_old_equal_new(self):
|
||||
for _ in range(1000):
|
||||
v_wheel = random.uniform(0, 200)
|
||||
|
||||
x_old = self.kf_old.update(v_wheel)
|
||||
x = self.kf.update(v_wheel)
|
||||
|
||||
# Compare the output x, verify that the error is less than 1e-4
|
||||
np.testing.assert_almost_equal(x_old[0], x[0])
|
||||
np.testing.assert_almost_equal(x_old[1], x[1])
|
||||
|
||||
def test_new_is_faster(self):
|
||||
setup = """
|
||||
import numpy as np
|
||||
|
||||
from openpilot.common.kalman.simple_kalman import KF1D
|
||||
from openpilot.common.kalman.simple_kalman_old import KF1D as KF1D_old
|
||||
|
||||
dt = 0.01
|
||||
x0_0 = 0.0
|
||||
x1_0 = 0.0
|
||||
A0_0 = 1.0
|
||||
A0_1 = dt
|
||||
A1_0 = 0.0
|
||||
A1_1 = 1.0
|
||||
C0_0 = 1.0
|
||||
C0_1 = 0.0
|
||||
K0_0 = 0.12287673
|
||||
K1_0 = 0.29666309
|
||||
|
||||
kf_old = KF1D_old(x0=np.array([[x0_0], [x1_0]]),
|
||||
A=np.array([[A0_0, A0_1], [A1_0, A1_1]]),
|
||||
C=np.array([C0_0, C0_1]),
|
||||
K=np.array([[K0_0], [K1_0]]))
|
||||
|
||||
kf = KF1D(x0=[[x0_0], [x1_0]],
|
||||
A=[[A0_0, A0_1], [A1_0, A1_1]],
|
||||
C=[C0_0, C0_1],
|
||||
K=[[K0_0], [K1_0]])
|
||||
"""
|
||||
kf_speed = timeit.timeit("kf.update(1234)", setup=setup, number=10000)
|
||||
kf_old_speed = timeit.timeit("kf_old.update(1234)", setup=setup, number=10000)
|
||||
self.assertTrue(kf_speed < kf_old_speed / 4)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,12 +0,0 @@
|
||||
class lazy_property():
|
||||
"""Defines a property whose value will be computed only once and as needed.
|
||||
|
||||
This can only be used on instance methods.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
self._func = func
|
||||
|
||||
def __get__(self, obj_self, cls):
|
||||
value = self._func(obj_self)
|
||||
setattr(obj_self, self._func.__name__, value)
|
||||
return value
|
||||
@@ -65,7 +65,7 @@ class SwagFormatter(logging.Formatter):
|
||||
|
||||
return record_dict
|
||||
|
||||
def format(self, record): # noqa: A003
|
||||
def format(self, record):
|
||||
if self.swaglogger is None:
|
||||
raise Exception("must set swaglogger before calling format()")
|
||||
return json_robust_dumps(self.format_dict(record))
|
||||
@@ -95,7 +95,7 @@ class SwagLogFileFormatter(SwagFormatter):
|
||||
k += "$a"
|
||||
return k, v
|
||||
|
||||
def format(self, record): # noqa: A003
|
||||
def format(self, record):
|
||||
if isinstance(record, str):
|
||||
v = json.loads(record)
|
||||
else:
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/mat.h"
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
const int TRAJECTORY_SIZE = 33;
|
||||
const int LAT_MPC_N = 16;
|
||||
const int LON_MPC_N = 32;
|
||||
const float MIN_DRAW_DISTANCE = 10.0;
|
||||
const float MAX_DRAW_DISTANCE = 100.0;
|
||||
|
||||
const float RYG_GREEN = 0.01165;
|
||||
const float RYG_YELLOW = 0.06157;
|
||||
|
||||
template <typename T, size_t size>
|
||||
constexpr std::array<T, size> build_idxs(float max_val) {
|
||||
std::array<T, size> result{};
|
||||
for (int i = 0; i < size; ++i) {
|
||||
result[i] = max_val * ((i / (double)(size - 1)) * (i / (double)(size - 1)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr auto T_IDXS = build_idxs<double, TRAJECTORY_SIZE>(10.0);
|
||||
constexpr auto T_IDXS_FLOAT = build_idxs<float, TRAJECTORY_SIZE>(10.0);
|
||||
constexpr auto X_IDXS = build_idxs<double, TRAJECTORY_SIZE>(192.0);
|
||||
constexpr auto X_IDXS_FLOAT = build_idxs<float, TRAJECTORY_SIZE>(192.0);
|
||||
|
||||
const mat3 FCAM_INTRINSIC_MATRIX = (mat3){{2648.0, 0.0, 1928.0 / 2,
|
||||
0.0, 2648.0, 1208.0 / 2,
|
||||
0.0, 0.0, 1.0}};
|
||||
|
||||
// tici ecam focal probably wrong? magnification is not consistent across frame
|
||||
// Need to retrain model before this can be changed
|
||||
const mat3 ECAM_INTRINSIC_MATRIX = (mat3){{567.0, 0.0, 1928.0 / 2,
|
||||
0.0, 567.0, 1208.0 / 2,
|
||||
0.0, 0.0, 1.0}};
|
||||
@@ -1,22 +0,0 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
def deep_interp_np(x, xp, fp, axis=None):
|
||||
if axis is not None:
|
||||
fp = fp.swapaxes(0,axis)
|
||||
x = np.atleast_1d(x)
|
||||
xp = np.array(xp)
|
||||
if len(xp) < 2:
|
||||
return np.repeat(fp, len(x), axis=0)
|
||||
if min(np.diff(xp)) < 0:
|
||||
raise RuntimeError('Bad x array for interpolation')
|
||||
j = np.searchsorted(xp, x) - 1
|
||||
j = np.clip(j, 0, len(xp)-2)
|
||||
d = np.divide(x - xp[j], xp[j + 1] - xp[j], out=np.ones_like(x, dtype=np.float64), where=xp[j + 1] - xp[j] != 0)
|
||||
vals_interp = (fp[j].T*(1 - d)).T + (fp[j + 1].T*d).T
|
||||
if axis is not None:
|
||||
vals_interp = vals_interp.swapaxes(0,axis)
|
||||
if len(vals_interp) == 1:
|
||||
return vals_interp[0]
|
||||
else:
|
||||
return vals_interp
|
||||
@@ -4,9 +4,11 @@
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <csignal>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/queue.h"
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
#include "system/hardware/hw.h"
|
||||
@@ -92,6 +94,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"AssistNowToken", PERSISTENT},
|
||||
{"AthenadPid", PERSISTENT},
|
||||
{"AthenadUploadQueue", PERSISTENT},
|
||||
{"AthenadRecentlyViewedRoutes", PERSISTENT},
|
||||
{"CalibrationParams", PERSISTENT},
|
||||
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
|
||||
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
|
||||
@@ -114,7 +117,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"DoReboot", CLEAR_ON_MANAGER_START},
|
||||
{"DoShutdown", CLEAR_ON_MANAGER_START},
|
||||
{"DoUninstall", CLEAR_ON_MANAGER_START},
|
||||
{"ExperimentalLongitudinalEnabled", PERSISTENT},
|
||||
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY},
|
||||
{"ExperimentalMode", PERSISTENT},
|
||||
{"ExperimentalModeConfirmed", PERSISTENT},
|
||||
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
@@ -142,16 +145,13 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"IsReleaseBranch", CLEAR_ON_MANAGER_START},
|
||||
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
|
||||
{"IsUpdateAvailable", CLEAR_ON_MANAGER_START},
|
||||
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"LaikadEphemerisV3", PERSISTENT | DONT_LOG},
|
||||
{"LanguageSetting", PERSISTENT},
|
||||
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
|
||||
{"LastGPSPosition", PERSISTENT},
|
||||
{"LastManagerExitReason", CLEAR_ON_MANAGER_START},
|
||||
{"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
|
||||
{"LastSystemShutdown", CLEAR_ON_MANAGER_START},
|
||||
{"LastUpdateException", CLEAR_ON_MANAGER_START},
|
||||
{"LastUpdateTime", PERSISTENT},
|
||||
{"LiveParameters", PERSISTENT},
|
||||
@@ -162,7 +162,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"NavPastDestinations", PERSISTENT},
|
||||
{"NavSettingLeftSide", PERSISTENT},
|
||||
{"NavSettingTime24h", PERSISTENT},
|
||||
{"NavdRender", PERSISTENT},
|
||||
{"NetworkMetered", PERSISTENT},
|
||||
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
|
||||
@@ -182,22 +182,19 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"PandaSignatures", CLEAR_ON_MANAGER_START},
|
||||
{"Passive", PERSISTENT},
|
||||
{"PrimeType", PERSISTENT},
|
||||
{"RecordFront", PERSISTENT},
|
||||
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
|
||||
{"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"ShouldDoUpdate", CLEAR_ON_MANAGER_START},
|
||||
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"SshEnabled", PERSISTENT},
|
||||
{"SubscriberInfo", PERSISTENT},
|
||||
{"TermsVersion", PERSISTENT},
|
||||
{"Timezone", PERSISTENT},
|
||||
{"TrainingVersion", PERSISTENT},
|
||||
{"UbloxAvailable", PERSISTENT},
|
||||
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterAvailableBranches", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterAvailableBranches", PERSISTENT},
|
||||
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
|
||||
@@ -205,6 +202,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterState", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterLastFetchTime", PERSISTENT},
|
||||
{"Version", PERSISTENT},
|
||||
{"VisionRadarToggle", PERSISTENT},
|
||||
{"WheeledBody", PERSISTENT},
|
||||
@@ -308,8 +306,15 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
|
||||
|
||||
Params::Params(const std::string &path) {
|
||||
prefix = "/" + util::getenv("OPENPILOT_PREFIX", "d");
|
||||
params_path = ensure_params_path(prefix, path);
|
||||
params_prefix = "/" + util::getenv("OPENPILOT_PREFIX", "d");
|
||||
params_path = ensure_params_path(params_prefix, path);
|
||||
}
|
||||
|
||||
Params::~Params() {
|
||||
if (future.valid()) {
|
||||
future.wait();
|
||||
}
|
||||
assert(queue.empty());
|
||||
}
|
||||
|
||||
std::vector<std::string> Params::allKeys() const {
|
||||
@@ -422,3 +427,20 @@ void Params::clearAll(ParamKeyType key_type) {
|
||||
|
||||
fsync_dir(getParamPath());
|
||||
}
|
||||
|
||||
void Params::putNonBlocking(const std::string &key, const std::string &val) {
|
||||
queue.push(std::make_pair(key, val));
|
||||
// start thread on demand
|
||||
if (!future.valid() || future.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) {
|
||||
future = std::async(std::launch::async, &Params::asyncWriteThread, this);
|
||||
}
|
||||
}
|
||||
|
||||
void Params::asyncWriteThread() {
|
||||
// TODO: write the latest one if a key has multiple values in the queue.
|
||||
std::pair<std::string, std::string> p;
|
||||
while (queue.try_pop(p, 0)) {
|
||||
// Params::put is Thread-Safe
|
||||
put(p.first, p.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/queue.h"
|
||||
|
||||
enum ParamKeyType {
|
||||
PERSISTENT = 0x02,
|
||||
CLEAR_ON_MANAGER_START = 0x04,
|
||||
CLEAR_ON_ONROAD_TRANSITION = 0x08,
|
||||
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
|
||||
DONT_LOG = 0x20,
|
||||
DEVELOPMENT_ONLY = 0x40,
|
||||
ALL = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
class Params {
|
||||
public:
|
||||
explicit Params(const std::string &path = {});
|
||||
~Params();
|
||||
// Not copyable.
|
||||
Params(const Params&) = delete;
|
||||
Params& operator=(const Params&) = delete;
|
||||
@@ -24,7 +31,7 @@ public:
|
||||
bool checkKey(const std::string &key);
|
||||
ParamKeyType getKeyType(const std::string &key);
|
||||
inline std::string getParamPath(const std::string &key = {}) {
|
||||
return params_path + prefix + (key.empty() ? "" : "/" + key);
|
||||
return params_path + params_prefix + (key.empty() ? "" : "/" + key);
|
||||
}
|
||||
|
||||
// Delete a value
|
||||
@@ -46,8 +53,18 @@ public:
|
||||
inline int putBool(const std::string &key, bool val) {
|
||||
return put(key.c_str(), val ? "1" : "0", 1);
|
||||
}
|
||||
void putNonBlocking(const std::string &key, const std::string &val);
|
||||
inline void putBoolNonBlocking(const std::string &key, bool val) {
|
||||
putNonBlocking(key, val ? "1" : "0");
|
||||
}
|
||||
|
||||
private:
|
||||
void asyncWriteThread();
|
||||
|
||||
std::string params_path;
|
||||
std::string prefix;
|
||||
std::string params_prefix;
|
||||
|
||||
// for nonblocking write
|
||||
std::future<void> future;
|
||||
SafeQueue<std::pair<std::string, std::string>> queue;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName, put_nonblocking, \
|
||||
put_bool_nonblocking
|
||||
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName
|
||||
assert Params
|
||||
assert ParamKeyType
|
||||
assert UnknownKeyName
|
||||
assert put_nonblocking
|
||||
assert put_bool_nonblocking
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from libcpp cimport bool
|
||||
from libcpp.string cimport string
|
||||
from libcpp.vector cimport vector
|
||||
import threading
|
||||
|
||||
cdef extern from "common/params.h":
|
||||
cpdef enum ParamKeyType:
|
||||
@@ -11,6 +10,7 @@ cdef extern from "common/params.h":
|
||||
CLEAR_ON_MANAGER_START
|
||||
CLEAR_ON_ONROAD_TRANSITION
|
||||
CLEAR_ON_OFFROAD_TRANSITION
|
||||
DEVELOPMENT_ONLY
|
||||
ALL
|
||||
|
||||
cdef cppclass c_Params "Params":
|
||||
@@ -19,6 +19,8 @@ cdef extern from "common/params.h":
|
||||
bool getBool(string, bool) nogil
|
||||
int remove(string) nogil
|
||||
int put(string, string) nogil
|
||||
void putNonBlocking(string, string) nogil
|
||||
void putBoolNonBlocking(string, bool) nogil
|
||||
int putBool(string, bool) nogil
|
||||
bool checkKey(string) nogil
|
||||
string getParamPath(string) nogil
|
||||
@@ -79,7 +81,7 @@ cdef class Params:
|
||||
"""
|
||||
Warning: This function blocks until the param is written to disk!
|
||||
In very rare cases this can take over a second, and your code will hang.
|
||||
Use the put_nonblocking helper function in time sensitive code, but
|
||||
Use the put_nonblocking, put_bool_nonblocking in time sensitive code, but
|
||||
in general try to avoid writing params as much as possible.
|
||||
"""
|
||||
cdef string k = self.check_key(key)
|
||||
@@ -92,6 +94,17 @@ cdef class Params:
|
||||
with nogil:
|
||||
self.p.putBool(k, val)
|
||||
|
||||
def put_nonblocking(self, key, dat):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef string dat_bytes = ensure_bytes(dat)
|
||||
with nogil:
|
||||
self.p.putNonBlocking(k, dat_bytes)
|
||||
|
||||
def put_bool_nonblocking(self, key, bool val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putBoolNonBlocking(k, val)
|
||||
|
||||
def remove(self, key):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
@@ -103,9 +116,3 @@ cdef class Params:
|
||||
|
||||
def all_keys(self):
|
||||
return self.p.allKeys()
|
||||
|
||||
def put_nonblocking(key, val, d=""):
|
||||
threading.Thread(target=lambda: Params(d).put(key, val)).start()
|
||||
|
||||
def put_bool_nonblocking(key, bool val, d=""):
|
||||
threading.Thread(target=lambda: Params(d).put_bool(key, val)).start()
|
||||
|
||||
@@ -6,12 +6,14 @@ from typing import Optional
|
||||
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
|
||||
class OpenpilotPrefix:
|
||||
def __init__(self, prefix: Optional[str] = None, clean_dirs_on_exit: bool = True):
|
||||
def __init__(self, prefix: Optional[str] = None, 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('/dev/shm', self.prefix)
|
||||
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)
|
||||
@@ -22,6 +24,9 @@ class OpenpilotPrefix:
|
||||
pass
|
||||
os.makedirs(Paths.log_root(), exist_ok=True)
|
||||
|
||||
if self.shared_download_cache:
|
||||
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_obj, exc_tb):
|
||||
@@ -42,5 +47,6 @@ class OpenpilotPrefix:
|
||||
os.remove(symlink_path)
|
||||
shutil.rmtree(self.msgq_path, ignore_errors=True)
|
||||
shutil.rmtree(Paths.log_root(), ignore_errors=True)
|
||||
shutil.rmtree(Paths.download_cache_root(), ignore_errors=True)
|
||||
if not os.environ.get("COMMA_CACHE", False):
|
||||
shutil.rmtree(Paths.download_cache_root(), ignore_errors=True)
|
||||
shutil.rmtree(Paths.comma_home(), ignore_errors=True)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import time
|
||||
|
||||
class Profiler():
|
||||
def __init__(self, enabled=False):
|
||||
self.enabled = enabled
|
||||
self.cp = {}
|
||||
self.cp_ignored = []
|
||||
self.iter = 0
|
||||
self.start_time = time.time()
|
||||
self.last_time = self.start_time
|
||||
self.tot = 0.
|
||||
|
||||
def reset(self, enabled=False):
|
||||
self.enabled = enabled
|
||||
self.cp = {}
|
||||
self.cp_ignored = []
|
||||
self.iter = 0
|
||||
self.start_time = time.time()
|
||||
self.last_time = self.start_time
|
||||
|
||||
def checkpoint(self, name, ignore=False):
|
||||
# ignore flag needed when benchmarking threads with ratekeeper
|
||||
if not self.enabled:
|
||||
return
|
||||
tt = time.time()
|
||||
if name not in self.cp:
|
||||
self.cp[name] = 0.
|
||||
if ignore:
|
||||
self.cp_ignored.append(name)
|
||||
self.cp[name] += tt - self.last_time
|
||||
if not ignore:
|
||||
self.tot += tt - self.last_time
|
||||
self.last_time = tt
|
||||
|
||||
def display(self):
|
||||
if not self.enabled:
|
||||
return
|
||||
self.iter += 1
|
||||
print("******* Profiling %d *******" % self.iter)
|
||||
for n, ms in sorted(self.cp.items(), key=lambda x: -x[1]):
|
||||
if n in self.cp_ignored:
|
||||
print("%30s: %9.2f avg: %7.2f percent: %3.0f IGNORED" % (n, ms*1000.0, ms*1000.0/self.iter, ms/self.tot*100))
|
||||
else:
|
||||
print("%30s: %9.2f avg: %7.2f percent: %3.0f" % (n, ms*1000.0, ms*1000.0/self.iter, ms/self.tot*100))
|
||||
print(f"Iter clock: {self.tot / self.iter:2.6f} TOTAL: {self.tot:2.2f}")
|
||||
@@ -78,7 +78,7 @@ class Ratekeeper:
|
||||
time.sleep(self._remaining)
|
||||
return lagged
|
||||
|
||||
# this only monitor the cumulative lag, but does not enforce a rate
|
||||
# Monitors the cumulative lag, but does not enforce a rate
|
||||
def monitor_time(self) -> bool:
|
||||
prev = self._last_monitor_time
|
||||
self._last_monitor_time = time.monotonic()
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import time
|
||||
import functools
|
||||
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
|
||||
def retry(attempts=3, delay=1.0, ignore_failure=False):
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
for _ in range(attempts):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception:
|
||||
cloudlog.exception(f"{func.__name__} failed, trying again")
|
||||
time.sleep(delay)
|
||||
|
||||
if ignore_failure:
|
||||
cloudlog.error(f"{func.__name__} failed after retry")
|
||||
else:
|
||||
raise Exception(f"{func.__name__} failed after retry")
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@retry(attempts=10)
|
||||
def abc():
|
||||
raise ValueError("abc failed :(")
|
||||
abc()
|
||||
@@ -0,0 +1,54 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
def get_kalman_gain(dt, A, C, Q, R, iterations=100):
|
||||
P = np.zeros_like(Q)
|
||||
for _ in range(iterations):
|
||||
P = A.dot(P).dot(A.T) + dt * Q
|
||||
S = C.dot(P).dot(C.T) + R
|
||||
K = P.dot(C.T).dot(np.linalg.inv(S))
|
||||
P = (np.eye(len(P)) - K.dot(C)).dot(P)
|
||||
return K
|
||||
|
||||
|
||||
class KF1D:
|
||||
# this EKF assumes constant covariance matrix, so calculations are much simpler
|
||||
# the Kalman gain also needs to be precomputed using the control module
|
||||
|
||||
def __init__(self, x0, A, C, K):
|
||||
self.x0_0 = x0[0][0]
|
||||
self.x1_0 = x0[1][0]
|
||||
self.A0_0 = A[0][0]
|
||||
self.A0_1 = A[0][1]
|
||||
self.A1_0 = A[1][0]
|
||||
self.A1_1 = A[1][1]
|
||||
self.C0_0 = C[0]
|
||||
self.C0_1 = C[1]
|
||||
self.K0_0 = K[0][0]
|
||||
self.K1_0 = K[1][0]
|
||||
|
||||
self.A_K_0 = self.A0_0 - self.K0_0 * self.C0_0
|
||||
self.A_K_1 = self.A0_1 - self.K0_0 * self.C0_1
|
||||
self.A_K_2 = self.A1_0 - self.K1_0 * self.C0_0
|
||||
self.A_K_3 = self.A1_1 - self.K1_0 * self.C0_1
|
||||
|
||||
# K matrix needs to be pre-computed as follow:
|
||||
# import control
|
||||
# (x, l, K) = control.dare(np.transpose(self.A), np.transpose(self.C), Q, R)
|
||||
# self.K = np.transpose(K)
|
||||
|
||||
def update(self, meas):
|
||||
#self.x = np.dot(self.A_K, self.x) + np.dot(self.K, meas)
|
||||
x0_0 = self.A_K_0 * self.x0_0 + self.A_K_1 * self.x1_0 + self.K0_0 * meas
|
||||
x1_0 = self.A_K_2 * self.x0_0 + self.A_K_3 * self.x1_0 + self.K1_0 * meas
|
||||
self.x0_0 = x0_0
|
||||
self.x1_0 = x1_0
|
||||
return [self.x0_0, self.x1_0]
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return [[self.x0_0], [self.x1_0]]
|
||||
|
||||
def set_x(self, x):
|
||||
self.x0_0 = x[0][0]
|
||||
self.x1_0 = x[1][0]
|
||||
@@ -1,47 +0,0 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "common/statlog.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <stdio.h>
|
||||
#include <mutex>
|
||||
#include <zmq.h>
|
||||
|
||||
class StatlogState : public LogState {
|
||||
public:
|
||||
StatlogState() : LogState("ipc:///tmp/stats") {}
|
||||
};
|
||||
|
||||
static StatlogState s = {};
|
||||
|
||||
static void log(const char* metric_type, const char* metric, const char* fmt, ...) {
|
||||
std::lock_guard lk(s.lock);
|
||||
if (!s.initialized) s.initialize();
|
||||
|
||||
char* value_buf = nullptr;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int ret = vasprintf(&value_buf, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (ret > 0 && value_buf) {
|
||||
char* line_buf = nullptr;
|
||||
ret = asprintf(&line_buf, "%s:%s|%s", metric, value_buf, metric_type);
|
||||
if (ret > 0 && line_buf) {
|
||||
zmq_send(s.sock, line_buf, ret, ZMQ_NOBLOCK);
|
||||
free(line_buf);
|
||||
}
|
||||
free(value_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void statlog_log(const char* metric_type, const char* metric, int value) {
|
||||
log(metric_type, metric, "%d", value);
|
||||
}
|
||||
|
||||
void statlog_log(const char* metric_type, const char* metric, float value) {
|
||||
log(metric_type, metric, "%f", value);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define STATLOG_GAUGE "g"
|
||||
#define STATLOG_SAMPLE "sa"
|
||||
|
||||
void statlog_log(const char* metric_type, const char* metric, int value);
|
||||
void statlog_log(const char* metric_type, const char* metric, float value);
|
||||
|
||||
#define statlog_gauge(metric, value) statlog_log(STATLOG_GAUGE, metric, value)
|
||||
#define statlog_sample(metric, value) statlog_log(STATLOG_SAMPLE, metric, value)
|
||||
@@ -5,30 +5,29 @@
|
||||
#include "common/swaglog.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include <zmq.h>
|
||||
#include <stdarg.h>
|
||||
#include "third_party/json11/json11.hpp"
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/version.h"
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
class SwaglogState : public LogState {
|
||||
public:
|
||||
SwaglogState() : LogState(Path::swaglog_ipc().c_str()) {}
|
||||
class SwaglogState {
|
||||
public:
|
||||
SwaglogState() {
|
||||
zctx = zmq_ctx_new();
|
||||
sock = zmq_socket(zctx, ZMQ_PUSH);
|
||||
|
||||
json11::Json::object ctx_j;
|
||||
// Timeout on shutdown for messages to be received by the logging process
|
||||
int timeout = 100;
|
||||
zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout));
|
||||
zmq_connect(sock, Path::swaglog_ipc().c_str());
|
||||
|
||||
inline void initialize() {
|
||||
ctx_j = json11::Json::object {};
|
||||
print_level = CLOUDLOG_WARNING;
|
||||
const char* print_lvl = getenv("LOGPRINT");
|
||||
if (print_lvl) {
|
||||
if (const char* print_lvl = getenv("LOGPRINT")) {
|
||||
if (strcmp(print_lvl, "debug") == 0) {
|
||||
print_level = CLOUDLOG_DEBUG;
|
||||
} else if (strcmp(print_lvl, "info") == 0) {
|
||||
@@ -38,39 +37,44 @@ class SwaglogState : public LogState {
|
||||
}
|
||||
}
|
||||
|
||||
// openpilot bindings
|
||||
char* dongle_id = getenv("DONGLE_ID");
|
||||
if (dongle_id) {
|
||||
ctx_j = json11::Json::object{};
|
||||
if (char* dongle_id = getenv("DONGLE_ID")) {
|
||||
ctx_j["dongle_id"] = dongle_id;
|
||||
}
|
||||
char* daemon_name = getenv("MANAGER_DAEMON");
|
||||
if (daemon_name) {
|
||||
if (char* daemon_name = getenv("MANAGER_DAEMON")) {
|
||||
ctx_j["daemon"] = daemon_name;
|
||||
}
|
||||
ctx_j["version"] = COMMA_VERSION;
|
||||
ctx_j["dirty"] = !getenv("CLEAN");
|
||||
|
||||
// device type
|
||||
ctx_j["device"] = Hardware::get_name();
|
||||
LogState::initialize();
|
||||
}
|
||||
|
||||
~SwaglogState() {
|
||||
zmq_close(sock);
|
||||
zmq_ctx_destroy(zctx);
|
||||
}
|
||||
|
||||
void log(int levelnum, const char* filename, int lineno, const char* func, const char* msg, const std::string& log_s) {
|
||||
std::lock_guard lk(lock);
|
||||
if (levelnum >= print_level) {
|
||||
printf("%s: %s\n", filename, msg);
|
||||
}
|
||||
zmq_send(sock, log_s.data(), log_s.length(), ZMQ_NOBLOCK);
|
||||
}
|
||||
|
||||
std::mutex lock;
|
||||
void* zctx = nullptr;
|
||||
void* sock = nullptr;
|
||||
int print_level;
|
||||
json11::Json::object ctx_j;
|
||||
};
|
||||
|
||||
static SwaglogState s = {};
|
||||
bool LOG_TIMESTAMPS = getenv("LOG_TIMESTAMPS");
|
||||
uint32_t NO_FRAME_ID = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
static void log(int levelnum, const char* filename, int lineno, const char* func, const char* msg, const std::string& log_s) {
|
||||
if (levelnum >= s.print_level) {
|
||||
printf("%s: %s\n", filename, msg);
|
||||
}
|
||||
zmq_send(s.sock, log_s.data(), log_s.length(), ZMQ_NOBLOCK);
|
||||
}
|
||||
|
||||
static void cloudlog_common(int levelnum, const char* filename, int lineno, const char* func,
|
||||
char* msg_buf, const json11::Json::object &msg_j={}) {
|
||||
std::lock_guard lk(s.lock);
|
||||
if (!s.initialized) s.initialize();
|
||||
static SwaglogState s;
|
||||
|
||||
json11::Json::object log_j = json11::Json::object {
|
||||
{"ctx", s.ctx_j},
|
||||
@@ -89,7 +93,7 @@ static void cloudlog_common(int levelnum, const char* filename, int lineno, cons
|
||||
std::string log_s;
|
||||
log_s += (char)levelnum;
|
||||
((json11::Json)log_j).dump(log_s);
|
||||
log(levelnum, filename, lineno, func, msg_buf, log_s);
|
||||
s.log(levelnum, filename, lineno, func, msg_buf, log_s);
|
||||
|
||||
free(msg_buf);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import os
|
||||
import unittest
|
||||
from uuid import uuid4
|
||||
|
||||
from openpilot.common.file_helpers import atomic_write_on_fs_tmp
|
||||
from openpilot.common.file_helpers import atomic_write_in_dir
|
||||
|
||||
|
||||
@@ -11,14 +10,12 @@ class TestFileHelpers(unittest.TestCase):
|
||||
path = f"/tmp/tmp{uuid4()}"
|
||||
with atomic_write_func(path) as f:
|
||||
f.write("test")
|
||||
assert not os.path.exists(path)
|
||||
|
||||
with open(path) as f:
|
||||
self.assertEqual(f.read(), "test")
|
||||
os.remove(path)
|
||||
|
||||
def test_atomic_write_on_fs_tmp(self):
|
||||
self.run_atomic_write_func(atomic_write_on_fs_tmp)
|
||||
|
||||
def test_atomic_write_in_dir(self):
|
||||
self.run_atomic_write_func(atomic_write_in_dir)
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "catch2/catch.hpp"
|
||||
#define private public
|
||||
#include "common/params.h"
|
||||
#include "common/util.h"
|
||||
|
||||
TEST_CASE("params_nonblocking_put") {
|
||||
char tmp_path[] = "/tmp/asyncWriter_XXXXXX";
|
||||
const std::string param_path = mkdtemp(tmp_path);
|
||||
auto param_names = {"CarParams", "IsMetric"};
|
||||
{
|
||||
Params params(param_path);
|
||||
for (const auto &name : param_names) {
|
||||
params.putNonBlocking(name, "1");
|
||||
// param is empty
|
||||
REQUIRE(params.get(name).empty());
|
||||
}
|
||||
|
||||
// check if thread is running
|
||||
REQUIRE(params.future.valid());
|
||||
REQUIRE(params.future.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout);
|
||||
}
|
||||
// check results
|
||||
Params p(param_path);
|
||||
for (const auto &name : param_names) {
|
||||
REQUIRE(p.get(name) == "1");
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import time
|
||||
import uuid
|
||||
import unittest
|
||||
|
||||
from openpilot.common.params import Params, ParamKeyType, UnknownKeyName, put_nonblocking, put_bool_nonblocking
|
||||
from openpilot.common.params import Params, ParamKeyType, UnknownKeyName
|
||||
|
||||
class TestParams(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@@ -86,7 +86,7 @@ class TestParams(unittest.TestCase):
|
||||
q = Params()
|
||||
def _delayed_writer():
|
||||
time.sleep(0.1)
|
||||
put_nonblocking("CarParams", "test")
|
||||
Params().put_nonblocking("CarParams", "test")
|
||||
threading.Thread(target=_delayed_writer).start()
|
||||
assert q.get("CarParams") is None
|
||||
assert q.get("CarParams", True) == b"test"
|
||||
@@ -95,7 +95,7 @@ class TestParams(unittest.TestCase):
|
||||
q = Params()
|
||||
def _delayed_writer():
|
||||
time.sleep(0.1)
|
||||
put_bool_nonblocking("CarParams", True)
|
||||
Params().put_bool_nonblocking("CarParams", True)
|
||||
threading.Thread(target=_delayed_writer).start()
|
||||
assert q.get("CarParams") is None
|
||||
assert q.get("CarParams", True) == b"1"
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#include "catch2/catch.hpp"
|
||||
#include "common/ratekeeper.h"
|
||||
#include "common/timing.h"
|
||||
#include "common/util.h"
|
||||
|
||||
TEST_CASE("RateKeeper") {
|
||||
float freq = GENERATE(10, 50, 100);
|
||||
RateKeeper rk("Test RateKeeper", freq);
|
||||
|
||||
int lags = 0;
|
||||
int bad_keep_times = 0;
|
||||
for (int i = 0; i < freq; ++i) {
|
||||
double begin = seconds_since_boot();
|
||||
util::sleep_for(util::random_int(0, 1000.0 / freq - 1));
|
||||
bool lagged = rk.keepTime();
|
||||
lags += lagged;
|
||||
bad_keep_times += (seconds_since_boot() - begin - (1 / freq)) > 1e-3;
|
||||
}
|
||||
|
||||
// need a tolerance here due to scheduling
|
||||
REQUIRE(lags < 5);
|
||||
REQUIRE(bad_keep_times < 5);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import unittest
|
||||
|
||||
from openpilot.common.simple_kalman import KF1D
|
||||
|
||||
|
||||
class TestSimpleKalman(unittest.TestCase):
|
||||
def setUp(self):
|
||||
dt = 0.01
|
||||
x0_0 = 0.0
|
||||
x1_0 = 0.0
|
||||
A0_0 = 1.0
|
||||
A0_1 = dt
|
||||
A1_0 = 0.0
|
||||
A1_1 = 1.0
|
||||
C0_0 = 1.0
|
||||
C0_1 = 0.0
|
||||
K0_0 = 0.12287673
|
||||
K1_0 = 0.29666309
|
||||
|
||||
self.kf = KF1D(x0=[[x0_0], [x1_0]],
|
||||
A=[[A0_0, A0_1], [A1_0, A1_1]],
|
||||
C=[C0_0, C0_1],
|
||||
K=[[K0_0], [K1_0]])
|
||||
|
||||
def test_getter_setter(self):
|
||||
self.kf.set_x([[1.0], [1.0]])
|
||||
self.assertEqual(self.kf.x, [[1.0], [1.0]])
|
||||
|
||||
def update_returns_state(self):
|
||||
x = self.kf.update(100)
|
||||
self.assertEqual(x, self.kf.x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -3,4 +3,4 @@ import datetime
|
||||
MIN_DATE = datetime.datetime(year=2023, month=6, day=1)
|
||||
|
||||
def system_time_valid():
|
||||
return datetime.datetime.now() > MIN_DATE
|
||||
return datetime.datetime.now() > MIN_DATE
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <zmq.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
@@ -180,36 +179,3 @@ void update_max_atomic(std::atomic<T>& max, T const& value) {
|
||||
T prev = max;
|
||||
while (prev < value && !max.compare_exchange_weak(prev, value)) {}
|
||||
}
|
||||
|
||||
class LogState {
|
||||
public:
|
||||
bool initialized = false;
|
||||
std::mutex lock;
|
||||
void *zctx = nullptr;
|
||||
void *sock = nullptr;
|
||||
int print_level;
|
||||
std::string endpoint;
|
||||
|
||||
LogState(std::string _endpoint) {
|
||||
endpoint = _endpoint;
|
||||
}
|
||||
|
||||
inline void initialize() {
|
||||
zctx = zmq_ctx_new();
|
||||
sock = zmq_socket(zctx, ZMQ_PUSH);
|
||||
|
||||
// Timeout on shutdown for messages to be received by the logging process
|
||||
int timeout = 100;
|
||||
zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout));
|
||||
|
||||
zmq_connect(sock, endpoint.c_str());
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
~LogState() {
|
||||
if (initialized) {
|
||||
zmq_close(sock);
|
||||
zmq_ctx_destroy(zctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMMA_VERSION "0.9.5.3"
|
||||
#define COMMA_VERSION "0.9.6"
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import sys
|
||||
import pygame
|
||||
import cv2
|
||||
|
||||
class Window:
|
||||
def __init__(self, w, h, caption="window", double=False, halve=False):
|
||||
self.w = w
|
||||
self.h = h
|
||||
pygame.display.init()
|
||||
pygame.display.set_caption(caption)
|
||||
self.double = double
|
||||
self.halve = halve
|
||||
if self.double:
|
||||
self.rw, self.rh = w*2, h*2
|
||||
elif self.halve:
|
||||
self.rw, self.rh = w//2, h//2
|
||||
else:
|
||||
self.rw, self.rh = w, h
|
||||
self.screen = pygame.display.set_mode((self.rw, self.rh))
|
||||
pygame.display.flip()
|
||||
|
||||
# hack for xmonad, it shrinks the window by 6 pixels after the display.flip
|
||||
if self.screen.get_width() != self.rw:
|
||||
self.screen = pygame.display.set_mode((self.rw+(self.rw-self.screen.get_width()), self.rh+(self.rh-self.screen.get_height())))
|
||||
pygame.display.flip()
|
||||
|
||||
def draw(self, out):
|
||||
pygame.event.pump()
|
||||
if self.double:
|
||||
out2 = cv2.resize(out, (self.w*2, self.h*2))
|
||||
pygame.surfarray.blit_array(self.screen, out2.swapaxes(0, 1))
|
||||
elif self.halve:
|
||||
out2 = cv2.resize(out, (self.w//2, self.h//2))
|
||||
pygame.surfarray.blit_array(self.screen, out2.swapaxes(0, 1))
|
||||
else:
|
||||
pygame.surfarray.blit_array(self.screen, out.swapaxes(0, 1))
|
||||
pygame.display.flip()
|
||||
|
||||
def getkey(self):
|
||||
while 1:
|
||||
event = pygame.event.wait()
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
if event.type == pygame.KEYDOWN:
|
||||
return event.key
|
||||
|
||||
def getclick(self):
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||
mx, my = pygame.mouse.get_pos()
|
||||
return mx, my
|
||||
|
||||
if __name__ == "__main__":
|
||||
import numpy as np
|
||||
win = Window(200, 200, double=True)
|
||||
img: np.ndarray = np.zeros((200, 200, 3), np.uint8)
|
||||
while 1:
|
||||
print("draw")
|
||||
img += 1
|
||||
win.draw(img)
|
||||
@@ -1,46 +0,0 @@
|
||||
import os
|
||||
from cffi import FFI
|
||||
from typing import Any, List
|
||||
|
||||
# Workaround for the EON/termux build of Python having os.*xattr removed.
|
||||
ffi = FFI()
|
||||
ffi.cdef("""
|
||||
int setxattr(const char *path, const char *name, const void *value, size_t size, int flags);
|
||||
ssize_t getxattr(const char *path, const char *name, void *value, size_t size);
|
||||
ssize_t listxattr(const char *path, char *list, size_t size);
|
||||
int removexattr(const char *path, const char *name);
|
||||
""")
|
||||
libc = ffi.dlopen(None)
|
||||
|
||||
def setxattr(path, name, value, flags=0) -> None:
|
||||
path = path.encode()
|
||||
name = name.encode()
|
||||
if libc.setxattr(path, name, value, len(value), flags) == -1:
|
||||
raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: setxattr({path}, {name}, {value}, {flags})")
|
||||
|
||||
def getxattr(path, name, size=128):
|
||||
path = path.encode()
|
||||
name = name.encode()
|
||||
value = ffi.new(f"char[{size}]")
|
||||
l = libc.getxattr(path, name, value, size)
|
||||
if l == -1:
|
||||
# errno 61 means attribute hasn't been set
|
||||
if ffi.errno == 61:
|
||||
return None
|
||||
raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: getxattr({path}, {name}, {size})")
|
||||
return ffi.buffer(value)[:l]
|
||||
|
||||
def listxattr(path, size=128) -> List[Any]:
|
||||
path = path.encode()
|
||||
attrs = ffi.new(f"char[{size}]")
|
||||
l = libc.listxattr(path, attrs, size)
|
||||
if l == -1:
|
||||
raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: listxattr({path}, {size})")
|
||||
# attrs is b'\0' delimited values (so chop off trailing empty item)
|
||||
return [a.decode() for a in ffi.buffer(attrs)[:l].split(b"\0")[0:-1]]
|
||||
|
||||
def removexattr(path, name) -> None:
|
||||
path = path.encode()
|
||||
name = name.encode()
|
||||
if libc.removexattr(path, name) == -1:
|
||||
raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: removexattr({path}, {name})")
|
||||
@@ -3,17 +3,35 @@ import pytest
|
||||
import random
|
||||
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.selfdrive.manager import manager
|
||||
from openpilot.system.hardware import TICI
|
||||
|
||||
|
||||
def pytest_sessionstart(session):
|
||||
# TODO: fix tests and enable test order randomization
|
||||
if session.config.pluginmanager.hasplugin('randomly'):
|
||||
session.config.option.randomly_reorganize = False
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True, trylast=True)
|
||||
def pytest_runtest_call(item):
|
||||
# ensure we run as a hook after capturemanager's
|
||||
if item.get_closest_marker("nocapture") is not None:
|
||||
capmanager = item.config.pluginmanager.getplugin("capturemanager")
|
||||
with capmanager.global_and_fixture_disabled():
|
||||
yield
|
||||
else:
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", autouse=True)
|
||||
def openpilot_function_fixture():
|
||||
def openpilot_function_fixture(request):
|
||||
starting_env = dict(os.environ)
|
||||
|
||||
random.seed(0)
|
||||
|
||||
# setup a clean environment for each test
|
||||
with OpenpilotPrefix():
|
||||
with OpenpilotPrefix(shared_download_cache=request.node.get_closest_marker("shared_download_cache") is not None) as prefix:
|
||||
prefix = os.environ["OPENPILOT_PREFIX"]
|
||||
|
||||
yield
|
||||
@@ -24,6 +42,8 @@ def openpilot_function_fixture():
|
||||
os.environ.clear()
|
||||
os.environ.update(starting_env)
|
||||
|
||||
# cleanup any started processes
|
||||
manager.manager_cleanup()
|
||||
|
||||
# If you use setUpClass, the environment variables won't be cleared properly,
|
||||
# so we need to hook both the function and class pytest fixtures
|
||||
@@ -37,8 +57,26 @@ def openpilot_class_fixture():
|
||||
os.environ.update(starting_env)
|
||||
|
||||
|
||||
@pytest.hookimpl(tryfirst=True)
|
||||
def pytest_collection_modifyitems(config, items):
|
||||
skipper = pytest.mark.skip(reason="Skipping tici test on PC")
|
||||
for item in items:
|
||||
if not TICI and "tici" in item.keywords:
|
||||
item.add_marker(skipper)
|
||||
item.add_marker(skipper)
|
||||
|
||||
if "xdist_group_class_property" in item.keywords:
|
||||
class_property_name = item.get_closest_marker('xdist_group_class_property').args[0]
|
||||
class_property_value = getattr(item.cls, class_property_name)
|
||||
item.add_marker(pytest.mark.xdist_group(class_property_value))
|
||||
|
||||
|
||||
@pytest.hookimpl(trylast=True)
|
||||
def pytest_configure(config):
|
||||
config_line = "xdist_group_class_property: group tests by a property of the class that contains them"
|
||||
config.addinivalue_line("markers", config_line)
|
||||
|
||||
config_line = "nocapture: don't capture test output"
|
||||
config.addinivalue_line("markers", config_line)
|
||||
|
||||
config_line = "shared_download_cache: share download cache between tests"
|
||||
config.addinivalue_line("markers", config_line)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# [Bounties](https://github.com/orgs/commaai/projects/26/views/1)
|
||||
|
||||
Get paid to improve openpilot!
|
||||
|
||||
## Rules
|
||||
|
||||
* code must be merged into openpilot master
|
||||
* bounty eligibility is solely at our discretion
|
||||
* once you open a PR, the bounty is locked to you until you stop working on it
|
||||
* open a ticket at [comma.ai/support](https://comma.ai/support/shop-order) with links to your PRs to claim
|
||||
* get an extra 20% if you redeem your bounty in [comma shop](https://comma.ai/shop) credit (including refunds on previous orders)
|
||||
|
||||
New bounties can be proposed in the [**#contributing**](https://discord.com/channels/469524606043160576/1183173332531687454) channel in Discord.
|
||||
|
||||
## Issue bounties
|
||||
|
||||
We've tagged bounty-eligible issues across openpilot and the rest of our repos; check out all the open ones [here](https://github.com/orgs/commaai/projects/26/views/1). These bounties roughly work out like this:
|
||||
* **$100** - a few hours of work for an experienced openpilot developer; a good intro for someone new to openpilot
|
||||
* **$300** - a day of work for an experienced openpilot developer
|
||||
* **$500** - a few days of work for an experienced openpilot developer
|
||||
* **$1k+** - a week or two of work (could be less for the right person)
|
||||
|
||||
## Car bounties
|
||||
|
||||
The car bounties only apply to cars that have a path to ship in openpilot release, which excludes unsupportable cars (e.g. Fords with a steering lockout) or cars that require extra hardware (Honda Accord with serial steering).
|
||||
|
||||
#### Brand or platform port - $2000
|
||||
Example PR: [commaai/openpilot#23331](https://github.com/commaai/openpilot/pull/23331)
|
||||
|
||||
This is for adding support for an entirely new brand or a substantially new ADAS platform within a brand (e.g. the Volkswagen PQ platform).
|
||||
|
||||
#### Model port - $250
|
||||
Example PR: [commaai/openpilot#30245](https://github.com/commaai/openpilot/pull/30245)
|
||||
|
||||
This is for porting a new car model that runs on a platform openpilot already supports.
|
||||
In the average case, this is a few hours of work for an experienced software developer.
|
||||
|
||||
This bounty also covers getting openpilot supported on a previously unsupported trim of an already supported car, e.g. the Chevy Bolt without ACC.
|
||||
|
||||
#### Reverse Engineering a new Actuation Message - $300
|
||||
|
||||
This is for cars that are already supported, and it has three components:
|
||||
* reverse a new steering, adaptive cruise, or AEB message
|
||||
* merge the DBC definitions to [opendbc](http://github.com/commaai/opendbc)
|
||||
* merge the openpilot code to use it and post a demo route
|
||||
|
||||
The control doesn't have to be perfect, but it should generally do what it's supposed to do.
|
||||
|
||||
### Specific Cars
|
||||
|
||||
#### Rivian R1T or R1S - $3000
|
||||
|
||||
Get a Rivian driving with openpilot.
|
||||
Requires a merged port with lateral control and at least a POC of longitudinal control.
|
||||
|
||||
#### Toyota SecOc - $5000
|
||||
|
||||
We're contributing $5k to the [community-organized bounty](https://github.com/commaai/openpilot/discussions/19932).
|
||||
|
||||
#### Chevy Bolt with SuperCruise - $2500
|
||||
|
||||
The Bolt is already supported on the trim with standard ACC. Get openpilot working on the trim with SuperCruise. It must be a normal install: no extra pandas or other hardware, no ECU reflashes, etc. The full bounty is for a port with lateral and longitudinal control. $1500 of the bounty can be claimed with a lateral-only port.
|
||||
@@ -28,13 +28,14 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Chevrolet|Volt 2017-18[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|7 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Chevrolet&model=Volt 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/QeMCN_4TFfQ" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Chrysler&model=Pacifica 2017-18">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Chrysler&model=Pacifica 2019-20">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Chrysler&model=Pacifica 2021">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Chrysler&model=Pacifica Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Chrysler&model=Pacifica 2021-23">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica Hybrid 2017|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Chrysler&model=Pacifica Hybrid 2017">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica Hybrid 2018|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Chrysler&model=Pacifica Hybrid 2018">Buy Here</a></sub></details>||
|
||||
|Chrysler|Pacifica Hybrid 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Chrysler&model=Pacifica Hybrid 2019-23">Buy Here</a></sub></details>||
|
||||
|comma|body|All|openpilot|0 mph|0 mph|[](##)|[](##)|None||
|
||||
|Ford|Bronco Sport 2021-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Bronco Sport 2021-22">Buy Here</a></sub></details>||
|
||||
|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Escape 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Explorer 2020-22|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Explorer 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Explorer 2020-23|Co-Pilot360 Assist+|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Explorer 2020-23">Buy Here</a></sub></details>||
|
||||
|Ford|Focus 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Focus 2018">Buy Here</a></sub></details>||
|
||||
|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Kuga 2020-22">Buy Here</a></sub></details>||
|
||||
|Ford|Maverick 2022|LARIAT Luxury|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 2022">Buy Here</a></sub></details>||
|
||||
@@ -76,6 +77,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Honda&model=Pilot 2016-22">Buy Here</a></sub></details>||
|
||||
|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Honda&model=Ridgeline 2017-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Azera 2022">Buy Here</a></sub></details>||
|
||||
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Azera Hybrid 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Azera Hybrid 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Azera Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|Bayon Non-SCC 2021|No Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Bayon Non-SCC 2021">Buy Here</a></sub></details>||
|
||||
|Hyundai|Custin 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Custin 2023">Buy Here</a></sub></details>||
|
||||
@@ -101,26 +103,27 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=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|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Kona Electric 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=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 Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Kona Hybrid 2020">Buy Here</a></sub></details>|<a href="https://youtu.be/0dwpAHiZgFo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Kona Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Kona Non-SCC 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=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-23[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Cruz 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Santa Fe 2019-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe 2019-20">Buy Here</a></sub></details>||
|
||||
|Hyundai|Santa Cruz 2022-23[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Cruz 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Santa Fe 2019-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe 2019-20">Buy Here</a></sub></details>|<a href="https://youtu.be/bjDR0YjM__s" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Santa Fe 2021-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Sonata 2018-19">Buy Here</a></sub></details>||
|
||||
|Hyundai|Sonata 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Sonata Hybrid 2020-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Sonata Hybrid 2020-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Staria 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Staria 2023">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2021">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson 2022[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2022">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson 2023[<sup>8</sup>](#footnotes)|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2023">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson 2022[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2022">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson 2023[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2023">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson Diesel 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Tucson Hybrid 2022-24[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson Hybrid 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Veloster 2019-20">Buy Here</a></sub></details>||
|
||||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Jeep&model=Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Jeep&model=Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Carnival 2023-24[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Carnival 2023-24">Buy Here</a></sub></details>||
|
||||
|Kia|Carnival 2022-24[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Carnival 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|Carnival (China only) 2023[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Ceed 2019">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (Southeast Asia only) 2022-23[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=EV6 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>||
|
||||
@@ -138,10 +141,12 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Kia|Niro EV 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro EV 2021">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro EV 2022">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=lT7zcG6ZpGo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Niro EV 2023[<sup>8</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro EV 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2021-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Hybrid 2021-22">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Hybrid 2021">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Hybrid 2023[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Hybrid 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2018-19|All|Stock|10 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Plug-in Hybrid 2018-19">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2020|All|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Plug-in Hybrid 2020">Buy Here</a></sub></details>||
|
||||
|Kia|Niro Plug-in Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Plug-in Hybrid 2022">Buy Here</a></sub></details>||
|
||||
|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Optima 2017">Buy Here</a></sub></details>||
|
||||
|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Optima 2019-20">Buy Here</a></sub></details>||
|
||||
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Optima Hybrid 2019">Buy Here</a></sub></details>||
|
||||
@@ -152,16 +157,17 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Kia|Sorento 2021-23[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sorento 2021-23">Buy Here</a></sub></details>||
|
||||
|Kia|Sorento Hybrid 2021-23[<sup>8</sup>](#footnotes)|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sorento Hybrid 2021-23">Buy Here</a></sub></details>||
|
||||
|Kia|Sorento Plug-in Hybrid 2022-23[<sup>8</sup>](#footnotes)|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|
||||
|Kia|Sportage 2023[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sportage 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Sportage 2023[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sportage 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Sportage Hybrid 2023[<sup>8</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=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|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=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|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Stinger 2022">Buy Here</a></sub></details>||
|
||||
|Kia|Stinger 2022-23|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Stinger 2022-23">Buy Here</a></sub></details>||
|
||||
|Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=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|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=CT Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=ES 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES 2019-24|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=ES 2019-24">Buy Here</a></sub></details>||
|
||||
|Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>||
|
||||
|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=ES Hybrid 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Lexus|GS F 2016|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=GS F 2016">Buy Here</a></sub></details>||
|
||||
|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=IS 2017-19">Buy Here</a></sub></details>||
|
||||
|Lexus|IS 2022-23|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=IS 2022-23">Buy Here</a></sub></details>||
|
||||
|Lexus|NX 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=NX 2018-19">Buy Here</a></sub></details>||
|
||||
@@ -250,10 +256,12 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Toyota|RAV4 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 2017-18">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=wJxjDd42gGA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 2022">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 2023-24|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 2023-24">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 Hybrid 2016">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=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-24|All|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 Hybrid 2023-24">Buy Here</a></sub></details>||
|
||||
|Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=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>|
|
||||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=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,14</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=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>|
|
||||
|
||||
@@ -1,26 +1,50 @@
|
||||
# How to contribute
|
||||
|
||||
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/).
|
||||
|
||||
Most open source development activity is coordinated through our [GitHub Discussions](https://github.com/commaai/openpilot/discussions) and [Discord](https://discord.comma.ai). A lot of documentation is available at https://docs.comma.ai and on our [blog](https://blog.comma.ai/).
|
||||
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/). Development activity is coordinated through our GitHub Issues, [GitHub Discussions](https://github.com/commaai/openpilot/discussions), and [Discord](https://discord.comma.ai).
|
||||
|
||||
### Getting Started
|
||||
|
||||
* Setup your [development environment](../tools/)
|
||||
* Join our [Discord](https://discord.comma.ai)
|
||||
* Make sure you have a [GitHub account](https://github.com/signup/free)
|
||||
* Fork [our repositories](https://github.com/commaai) on GitHub
|
||||
* Setup your [development environment](../tools/)
|
||||
* Read about the [development workflow](WORKFLOW.md)
|
||||
* Join our [Discord](https://discord.comma.ai)
|
||||
* Docs are at https://docs.comma.ai and https://blog.comma.ai
|
||||
|
||||
## What contributions are we looking for?
|
||||
|
||||
**openpilot's priorities are [safety](SAFETY.md), stability, quality, and features, in that order.** openpilot is part of comma's mission to *solve self-driving cars while delivering shippable intermediaries*, and **all** development is towards that goal.
|
||||
|
||||
### What gets merged?
|
||||
|
||||
The probability of a pull request being merged is a function of its value to the project and the effort it will take us to get it merged.
|
||||
If a PR offers *some* value but will take lots of time to get merged, it will be closed.
|
||||
Simple, well-tested bug fixes are the easiest to merge, and new features are the hardest to get merged.
|
||||
|
||||
All of these are examples of good PRs:
|
||||
* typo fix: https://github.com/commaai/openpilot/pull/30678
|
||||
* removing unused code: https://github.com/commaai/openpilot/pull/30573
|
||||
* simple car model port: https://github.com/commaai/openpilot/pull/30245
|
||||
* car brand port: https://github.com/commaai/openpilot/pull/23331
|
||||
|
||||
### What doesn't get merged?
|
||||
|
||||
* **arbitrary style changes**: code is art, and it's up to the author to make it beautiful
|
||||
* **500+ line PRs**: clean it up, break it up into smaller PRs, or both
|
||||
* **PRs without a clear goal**: every PR must have a singular and clear goal
|
||||
* **UI design changes**: we do not have a good review process for this yet
|
||||
* **New features**: We believe openpilot is mostly feature-complete, and the rest is a matter of refinement and fixing bugs. As a result of this, most feature PRs will be immediately closed, however the beauty of open source is that forks can and do offer features that upstream openpilot doesn't.
|
||||
|
||||
### First contribution
|
||||
Try out some of these first pull requests ideas to dive into the codebase:
|
||||
|
||||
* Increase our [mypy](http://mypy-lang.org/) coverage
|
||||
* Write some documentation
|
||||
* Tackle an open [good first issue](https://github.com/commaai/openpilot/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
|
||||
Check out any [good first issue](https://github.com/commaai/openpilot/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) to get started.
|
||||
|
||||
### What do I need to contribute?
|
||||
|
||||
A lot of openpilot work requires only a PC, and some requires a comma device.
|
||||
Most car-related contributions require access to that car, plus a comma device installed in the car.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Pull requests should be against the master branch. Welcomed contributions include bug reports, car ports, and any [open issue](https://github.com/commaai/openpilot/issues). If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.
|
||||
Pull requests should be against the master branch. If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.
|
||||
|
||||
A good pull request has all of the following:
|
||||
* a clearly stated purpose
|
||||
@@ -31,18 +55,11 @@ A good pull request has all of the following:
|
||||
* if you've improved your car's tuning, post before and after plots
|
||||
* passes the CI tests
|
||||
|
||||
### Car Ports
|
||||
## Contributing without Code
|
||||
|
||||
We've released a [Model Port guide](https://blog.comma.ai/openpilot-port-guide-for-toyota-models/) for porting to Toyota/Lexus models.
|
||||
|
||||
If you port openpilot to a substantially new car brand, see this more generic [Brand Port guide](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/).
|
||||
|
||||
## Testing
|
||||
|
||||
### Automated Testing
|
||||
|
||||
All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.
|
||||
|
||||
### Code Style and Linting
|
||||
|
||||
Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
|
||||
* Report bugs in GitHub issues.
|
||||
* Report driving issues in the `#driving-feedback` Discord channel.
|
||||
* Consider opting into driver camera uploads to improve the driver monitoring model.
|
||||
* Connect your device to Wi-Fi regularly, so that we can pull data for training better driving models.
|
||||
* Run the `nightly` branch and report issues. This branch is like `master` but it's built just like a release.
|
||||
* Annotate images in the [comma10k dateset](https://github.com/commaai/comma10k).
|
||||
|
||||
@@ -41,13 +41,13 @@ clean:
|
||||
|
||||
@echo "Building rst files..."
|
||||
sphinx-apidoc -o "$(DOCSBUILDDIR)" ../ \
|
||||
../xx ../laika_repo ../rednose_repo ../notebooks ../panda_jungle \
|
||||
../xx ../rednose_repo ../notebooks ../panda_jungle \
|
||||
../third_party \
|
||||
../panda/examples \
|
||||
../scripts \
|
||||
../selfdrive/modeld \
|
||||
../selfdrive/debug \
|
||||
$(shell find .. -type d -name "*test*")
|
||||
$(shell find .. -type d -name "*test* -not -path "**.venv**" \")
|
||||
|
||||
@echo "Building html files..."
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(DOCSBUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# openpilot-docs
|
||||
|
||||
These docs are autogenerated from [this folder](https://github.com/commaai/openpilot/tree/master/docs) in the main openpilot repository.
|
||||
@@ -0,0 +1,42 @@
|
||||
# openpilot development workflow
|
||||
|
||||
Aside from the ML models, most tools used for openpilot development are in this repo.
|
||||
|
||||
Most development happens on normal Ubuntu workstations, and not in cars or directly on comma devices. See the [setup guide](../tools) for getting your PC setup for openpilot development.
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
# get the latest stuff
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
|
||||
# update dependencies
|
||||
tools/ubuntu_setup.sh
|
||||
|
||||
# build everything
|
||||
scons -j$(nproc)
|
||||
|
||||
# build just the ui with either of these
|
||||
scons -j8 selfdrive/ui/
|
||||
cd selfdrive/ui/ && scons -u -j8
|
||||
|
||||
# test everything
|
||||
pytest .
|
||||
|
||||
# test just logging services
|
||||
cd system/loggerd && pytest .
|
||||
|
||||
# run the linter
|
||||
pre-commit run --all
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Automated Testing
|
||||
|
||||
All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.
|
||||
|
||||
### Code Style and Linting
|
||||
|
||||
Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 129 B |
@@ -1,56 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="19.999983"
|
||||
height="19"
|
||||
viewBox="0 0 19.999983 19"
|
||||
version="1.1"
|
||||
id="svg1425"
|
||||
sodipodi:docname="icon-star-empty.svg"
|
||||
style="fill:none"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<metadata
|
||||
id="metadata1431">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs1429" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1198"
|
||||
inkscape:window-height="631"
|
||||
id="namedview1427"
|
||||
showgrid="false"
|
||||
inkscape:zoom="9.8333333"
|
||||
inkscape:cx="-8.3559301"
|
||||
inkscape:cy="8.9999925"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="1267"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg1425" />
|
||||
<path
|
||||
d="m 10.258402,14.841908 -0.2584,-0.1559 -0.2583999,0.1559 -5.16547,3.1177 1.3708,-5.876 0.06856,-0.2939 -0.2281,-0.1976 -4.56431,-3.9540698 6.00919,-0.50982 0.30043,-0.02549 0.11766,-0.27761 2.3496399,-5.54381 2.3496,5.54381 0.1177,0.27761 0.3004,0.02549 6.0092,0.50982 -4.5643,3.9540698 -0.2281,0.1976 0.0686,0.2939 1.3708,5.876 z"
|
||||
id="path1423"
|
||||
inkscape:connector-curvature="0"
|
||||
style="stroke:#b7b7b7" />
|
||||
</svg>
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3142658fa2782d266028dcab491e02ab329a2cadcf9efb1846a5f9631d64cac1
|
||||
size 1947
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 129 B |
@@ -1,56 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="19.999983"
|
||||
height="19"
|
||||
viewBox="0 0 19.999983 19"
|
||||
version="1.1"
|
||||
id="svg817"
|
||||
sodipodi:docname="icon-star-full.svg"
|
||||
style="fill:none"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<metadata
|
||||
id="metadata823">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs821" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1198"
|
||||
inkscape:window-height="1898"
|
||||
id="namedview819"
|
||||
showgrid="false"
|
||||
inkscape:zoom="20.005229"
|
||||
inkscape:cx="8.4325646"
|
||||
inkscape:cy="3.9969093"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg817" />
|
||||
<path
|
||||
d="m 10.258402,14.841908 -0.2584,-0.1559 -0.2583999,0.1559 -5.16547,3.1177 1.3708,-5.876 0.06856,-0.2939 -0.2281,-0.1976 -4.56431,-3.9540698 6.00919,-0.50982 0.30043,-0.02549 0.11766,-0.27761 2.3496399,-5.54381 2.3496,5.54381 0.1177,0.27761 0.3004,0.02549 6.0092,0.50982 -4.5643,3.9540698 -0.2281,0.1976 0.0686,0.2939 1.3708,5.876 z"
|
||||
id="path815"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#f5c543;stroke:#f0a43b" />
|
||||
</svg>
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5fdcc85f3d8c9d0c2fb76b98ddd9f118c0e4a12c859a4281a04a0870d5de12c8
|
||||
size 1950
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 129 B |
@@ -1,66 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="19.999983"
|
||||
height="19.000008"
|
||||
viewBox="0 0 19.999983 19.000008"
|
||||
version="1.1"
|
||||
id="svg831"
|
||||
sodipodi:docname="icon-star-half.svg"
|
||||
style="fill:none"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<metadata
|
||||
id="metadata837">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs835" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1198"
|
||||
inkscape:window-height="948"
|
||||
id="namedview833"
|
||||
showgrid="false"
|
||||
inkscape:zoom="9.8333333"
|
||||
inkscape:cx="-8.3559301"
|
||||
inkscape:cy="9"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="950"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg831" />
|
||||
<path
|
||||
d="M 10.000002,8.1671631e-6 V 15.270008 l -6.1799999,3.73 1.64,-7.03 L 2.0565151e-6,7.2400082 7.1900021,6.6300082 Z"
|
||||
id="path825"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#f5c543" />
|
||||
<path
|
||||
d="m 10.258402,14.841908 -0.2584,-0.1559 -0.2583999,0.1559 -5.16547,3.1177 1.3708,-5.876 0.06856,-0.2939 -0.2281,-0.1976 -4.56431,-3.9540698 6.00919,-0.50982 0.30043,-0.02549 0.11766,-0.27761 2.3496399,-5.54381 2.3496,5.54381 0.1177,0.27761 0.3004,0.02549 6.0092,0.50982 -4.5643,3.9540698 -0.2281,0.1976 0.0686,0.2939 1.3708,5.876 z"
|
||||
id="path827"
|
||||
inkscape:connector-curvature="0"
|
||||
style="stroke:#b7b7b7" />
|
||||
<path
|
||||
d="m 5.3322621,16.919208 3.66774,-2.2137 0.9999999,-0.6055 v 1.17 l -6.1799999,3.73 1.64,-7.03 L 2.0565151e-6,7.2400082 7.1900021,6.6300082 10.000002,8.1671631e-6 V 2.6000082 l -0.9999999,2.32203 -1.1246,2.65341 -5.42923,0.46066 4.12481,3.5732998 z"
|
||||
id="path829"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#f0a43b" />
|
||||
</svg>
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cdf5e7ae57626f4cda35973873a4696252babbbe473913fe0aafdd8ba39d7fc3
|
||||
size 2508
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 129 B |
@@ -1,12 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg viewBox="500.972 178.81 20 14.375" width="20" height="14.375" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
|
||||
<defs>
|
||||
<clipPath id="clip0_1674_1768">
|
||||
<rect width="20" height="20" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g clip-path="url(#clip0_1674_1768)" transform="matrix(1, 0, 0, 1, 500.971771, 175.81041)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.582 5.2447C19.352 4.3611 18.6743 3.66531 17.8138 3.42916C16.2542 3 10 3 10 3C10 3 3.7458 3 2.18614 3.42916C1.32557 3.66531 0.647841 4.3611 0.417841 5.2447C0 6.84612 0 10.1875 0 10.1875C0 10.1875 0 13.5288 0.417841 15.1303C0.647841 16.0139 1.32557 16.7097 2.18614 16.946C3.7458 17.375 10 17.375 10 17.375C10 17.375 16.2542 17.375 17.8138 16.946C18.6743 16.7097 19.352 16.0139 19.582 15.1303C20 13.5288 20 10.1875 20 10.1875C20 10.1875 20 6.84612 19.582 5.2447ZM8.12509 13.6255V7.37549L13.1251 10.5006L8.12509 13.6255Z" fill="#FF0000"/>
|
||||
</g>
|
||||
<path d="M 425.503 122.113 L 428.63 127.117 L 422.376 127.117 L 425.503 122.113 Z" style="stroke: rgb(0, 0, 0); stroke-width: 0px; fill: rgb(255, 255, 255);" transform="matrix(0, 1, -1, 0, 636.212463, -239.192383)" bx:shape="triangle 422.376 122.113 6.254 5.004 0.5 0 1@278e08c4"/>
|
||||
</svg>
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6cb64f9da10b818c56763a7c48347f6043da20a2a77fb14f6d60d9457c575b6b
|
||||
size 1278
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 129 B |
@@ -29,8 +29,6 @@ camerad
|
||||
^^^^^^^
|
||||
.. autodoxygenindex::
|
||||
:project: system_camerad_cameras
|
||||
.. autodoxygenindex::
|
||||
:project: system_camerad_imgproc
|
||||
|
||||
locationd
|
||||
^^^^^^^^^
|
||||
@@ -43,12 +41,6 @@ ui
|
||||
.. autodoxygenindex::
|
||||
:project: selfdrive_ui
|
||||
|
||||
soundd
|
||||
""""""
|
||||
.. autodoxygenindex::
|
||||
:project: selfdrive_ui_soundd
|
||||
|
||||
|
||||
replay
|
||||
""""""
|
||||
.. autodoxygenindex::
|
||||
|
||||
@@ -18,14 +18,6 @@ cereal
|
||||
cereal/README.md
|
||||
cereal/messaging/msgq.md
|
||||
|
||||
laika
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
laika_repo/README.md
|
||||
|
||||
models
|
||||
=========
|
||||
|
||||
|
||||
@@ -9,11 +9,6 @@ source "$BASEDIR/launch_env.sh"
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
|
||||
function agnos_init {
|
||||
# wait longer for weston to come up
|
||||
if [ -f "$BASEDIR/prebuilt" ]; then
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
# TODO: move this to agnos
|
||||
sudo rm -f /data/etc/NetworkManager/system-connections/*.nmmeta
|
||||
|
||||
@@ -35,9 +30,6 @@ function launch {
|
||||
# Remove orphaned git lock if it exists on boot
|
||||
[ -f "$DIR/.git/index.lock" ] && rm -f $DIR/.git/index.lock
|
||||
|
||||
# Pull time from panda
|
||||
$DIR/selfdrive/boardd/set_time.py
|
||||
|
||||
# Check to see if there's a valid overlay-based update available. Conditions
|
||||
# are as follows:
|
||||
#
|
||||
@@ -77,14 +69,19 @@ function launch {
|
||||
export PYTHONPATH="$PWD"
|
||||
|
||||
# hardware specific init
|
||||
agnos_init
|
||||
if [ -f /AGNOS ]; then
|
||||
agnos_init
|
||||
fi
|
||||
|
||||
# write tmux scrollback to a file
|
||||
tmux capture-pane -pq -S-1000 > /tmp/launch_log
|
||||
|
||||
# start manager
|
||||
cd selfdrive/manager
|
||||
./build.py && ./manager.py
|
||||
if [ ! -f $DIR/prebuilt ]; then
|
||||
./build.py
|
||||
fi
|
||||
./manager.py
|
||||
|
||||
# if broken, keep on screen error
|
||||
while true; do sleep 1; done
|
||||
|
||||
@@ -7,11 +7,7 @@ export OPENBLAS_NUM_THREADS=1
|
||||
export VECLIB_MAXIMUM_THREADS=1
|
||||
|
||||
if [ -z "$AGNOS_VERSION" ]; then
|
||||
export AGNOS_VERSION="8.2"
|
||||
fi
|
||||
|
||||
if [ -z "$PASSIVE" ]; then
|
||||
export PASSIVE="1"
|
||||
export AGNOS_VERSION="9.1"
|
||||
fi
|
||||
|
||||
export STAGING_ROOT="/data/safe_staging"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
export PASSIVE="0"
|
||||
exec ./launch_chffrplus.sh
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
[tool.pytest.ini_options]
|
||||
minversion = "6.0"
|
||||
addopts = "--ignore=openpilot/ --ignore=cereal/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=laika_repo/ -Werror --strict-config --strict-markers --durations=10"
|
||||
#cpp_files = "test_*" # uncomment when agnos has pytest-cpp and remove from CI
|
||||
addopts = "--ignore=openpilot/ --ignore=cereal/ --ignore=opendbc/ --ignore=panda/ --ignore=rednose_repo/ --ignore=tinygrad_repo/ --ignore=teleoprtc_repo/ -Werror --strict-config --strict-markers --durations=10 -n auto --dist=loadgroup"
|
||||
cpp_files = "test_*"
|
||||
cpp_harness = "selfdrive/test/cpp_harness.py"
|
||||
python_files = "test_*.py"
|
||||
#timeout = "30" # you get this long by default
|
||||
markers = [
|
||||
@@ -16,13 +17,17 @@ testpaths = [
|
||||
"selfdrive/controls",
|
||||
"selfdrive/locationd",
|
||||
"selfdrive/monitoring",
|
||||
"selfdrive/navd/tests",
|
||||
"selfdrive/thermald",
|
||||
"selfdrive/test/longitudinal_maneuvers",
|
||||
"selfdrive/test/process_replay/test_fuzzy.py",
|
||||
"system/camerad",
|
||||
"system/hardware/tici",
|
||||
"system/loggerd",
|
||||
"system/proclogd",
|
||||
"system/tests",
|
||||
"system/ubloxd",
|
||||
"system/webrtc",
|
||||
"tools/lib/tests",
|
||||
"tools/replay",
|
||||
"tools/cabana"
|
||||
@@ -38,12 +43,12 @@ exclude = [
|
||||
"cereal/",
|
||||
"opendbc/",
|
||||
"panda/",
|
||||
"laika/",
|
||||
"laika_repo/",
|
||||
"rednose/",
|
||||
"rednose_repo/",
|
||||
"tinygrad/",
|
||||
"tinygrad_repo/",
|
||||
"teleoprtc/",
|
||||
"teleoprtc_repo/",
|
||||
"third_party/",
|
||||
]
|
||||
|
||||
@@ -72,49 +77,39 @@ documentation = "https://docs.comma.ai"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "~3.11"
|
||||
atomicwrites = "*"
|
||||
aiohttp = "*"
|
||||
aiortc = "*"
|
||||
casadi = "==3.6.3"
|
||||
cffi = "*"
|
||||
control = "*"
|
||||
crcmod = "*"
|
||||
cryptography = "*"
|
||||
Cython = "*"
|
||||
future-fstrings = "*" # for acados
|
||||
hatanaka = "==2.4"
|
||||
hexdump = "*"
|
||||
Jinja2 = "*"
|
||||
json-rpc = "*"
|
||||
libusb1 = "*"
|
||||
numpy = "*"
|
||||
onnx = ">=1.14.0"
|
||||
onnxruntime = { version = ">=1.15.1", platform = "linux", markers = "platform_machine == 'aarch64'" }
|
||||
onnxruntime-gpu = { version = ">=1.15.1", platform = "linux", markers = "platform_machine == 'x86_64'" }
|
||||
onnxruntime = { version = ">=1.16.3", platform = "linux", markers = "platform_machine == 'aarch64'" }
|
||||
onnxruntime-gpu = { version = ">=1.16.3", platform = "linux", markers = "platform_machine == 'x86_64'" }
|
||||
psutil = "*"
|
||||
pyaudio = "*"
|
||||
pycapnp = "*"
|
||||
pycryptodome = "*"
|
||||
pycurl = "*"
|
||||
pydub = "*"
|
||||
PyJWT = "*"
|
||||
pyopencl = "*"
|
||||
pyserial = "*"
|
||||
PyYAML = "*"
|
||||
pyzmq = "*"
|
||||
requests = "*"
|
||||
scons = "*"
|
||||
sentry-sdk = "==1.28.1" # needs to be updated with AGNOS
|
||||
setproctitle = "*"
|
||||
smbus2 = "*"
|
||||
sounddevice = "*"
|
||||
spidev = { version = "*", platform = "linux" }
|
||||
sympy = "*"
|
||||
timezonefinder = "*"
|
||||
tqdm = "*"
|
||||
websocket_client = "*"
|
||||
polyline = "*"
|
||||
sconscontrib = {git = "https://github.com/SCons/scons-contrib.git"}
|
||||
|
||||
# these should be removed
|
||||
markdown-it-py = "*"
|
||||
timezonefinder = "*"
|
||||
setproctitle = "*"
|
||||
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
@@ -122,26 +117,29 @@ av = "*"
|
||||
azure-identity = "*"
|
||||
azure-storage-blob = "*"
|
||||
breathe = "*"
|
||||
control = "*"
|
||||
coverage = "*"
|
||||
dictdiffer = "*"
|
||||
ft4222 = "*"
|
||||
hypothesis = "~6.47"
|
||||
inputs = "*"
|
||||
Jinja2 = "*"
|
||||
lru-dict = "*"
|
||||
markdown-it-py = "*"
|
||||
matplotlib = "*"
|
||||
metadrive-simulator = { git = "https://github.com/metadriverse/metadrive.git", rev ="72e842cd1d025bf676e4af8797a01e4aa282109f", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies
|
||||
metadrive-simulator = { git = "https://github.com/metadriverse/metadrive.git", rev ="main", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies
|
||||
mpld3 = "*"
|
||||
mypy = "*"
|
||||
myst-parser = "*"
|
||||
natsort = "*"
|
||||
opencv-python-headless = "*"
|
||||
pandas = "*"
|
||||
parameterized = "^0.8"
|
||||
pprofile = "*"
|
||||
polyline = "*"
|
||||
pre-commit = "*"
|
||||
pyautogui = "*"
|
||||
pyopencl = "*"
|
||||
pygame = "*"
|
||||
pympler = "*"
|
||||
pywinctl = "*"
|
||||
pyprof2calltree = "*"
|
||||
pytest = "*"
|
||||
pytest-cov = "*"
|
||||
@@ -149,31 +147,20 @@ pytest-cpp = "*"
|
||||
pytest-subtests = "*"
|
||||
pytest-xdist = "*"
|
||||
pytest-timeout = "*"
|
||||
pytest-timeouts = "*"
|
||||
pytest-random-order = "*"
|
||||
pytest-randomly = "*"
|
||||
ruff = "*"
|
||||
scipy = "*"
|
||||
sphinx = "*"
|
||||
sphinx-rtd-theme = "*"
|
||||
sphinx-sitemap = "*"
|
||||
tabulate = "*"
|
||||
tenacity = "*"
|
||||
types-atomicwrites = "*"
|
||||
types-certifi = "*"
|
||||
types-pycurl = "*"
|
||||
types-PyYAML = "*"
|
||||
types-requests = "*"
|
||||
types-tabulate = "*"
|
||||
tqdm = "*"
|
||||
|
||||
# this is only pinned since 5.15.11 is broken
|
||||
pyqt5 = { version = "==5.15.2", markers = "platform_machine == 'x86_64'" } # no aarch64 wheels for macOS/linux
|
||||
|
||||
[tool.poetry.group.carla]
|
||||
optional = true
|
||||
|
||||
[tool.poetry.group.carla.dependencies]
|
||||
carla = { url = "https://github.com/commaai/carla/releases/download/3.11.4/carla-0.9.14-cp311-cp311-linux_x86_64.whl", platform = "linux", markers = "platform_machine == 'x86_64'" }
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
@@ -181,15 +168,16 @@ build-backend = "poetry.core.masonry.api"
|
||||
# https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml
|
||||
[tool.ruff]
|
||||
select = ["E", "F", "W", "PIE", "C4", "ISC", "RUF008", "RUF100", "A", "B", "TID251"]
|
||||
ignore = ["W292", "E741", "E402", "C408", "ISC003", "B027", "B024"]
|
||||
ignore = ["E741", "E402", "C408", "ISC003", "B027", "B024"]
|
||||
line-length = 160
|
||||
target-version="py311"
|
||||
exclude = [
|
||||
"panda",
|
||||
"opendbc",
|
||||
"laika_repo",
|
||||
"rednose_repo",
|
||||
"tinygrad_repo",
|
||||
"teleoprtc",
|
||||
"teleoprtc_repo",
|
||||
"third_party",
|
||||
]
|
||||
flake8-implicit-str-concat.allow-multiline=false
|
||||
@@ -199,3 +187,6 @@ flake8-implicit-str-concat.allow-multiline=false
|
||||
"system".msg = "Use openpilot.system"
|
||||
"third_party".msg = "Use openpilot.third_party"
|
||||
"tools".msg = "Use openpilot.tools"
|
||||
|
||||
[tool.coverage.run]
|
||||
concurrency = ["multiprocessing", "thread"]
|
||||
|
||||
@@ -22,6 +22,7 @@ pre-commit uninstall || true
|
||||
|
||||
echo "[-] bringing master-ci and devel in sync T=$SECONDS"
|
||||
cd $TARGET_DIR
|
||||
|
||||
git fetch --depth 1 origin master-ci
|
||||
git fetch --depth 1 origin devel
|
||||
|
||||
|
||||
@@ -102,11 +102,4 @@ if [ ! -z "$RELEASE_BRANCH" ]; then
|
||||
git push -f origin $RELEASE_BRANCH:$RELEASE_BRANCH
|
||||
fi
|
||||
|
||||
if [ ! -z "$DASHCAM_BRANCH" ]; then
|
||||
# Create dashcam
|
||||
git rm selfdrive/car/*/carcontroller.py
|
||||
git commit -m "create dashcam release from release"
|
||||
git push -f origin $RELEASE_BRANCH:$DASHCAM_BRANCH
|
||||
fi
|
||||
|
||||
echo "[-] done T=$SECONDS"
|
||||
|
||||
@@ -21,27 +21,8 @@ openpilot/**
|
||||
|
||||
common/.gitignore
|
||||
common/__init__.py
|
||||
common/conversions.py
|
||||
common/gpio.py
|
||||
common/realtime.py
|
||||
common/timeout.py
|
||||
common/ffi_wrapper.py
|
||||
common/file_helpers.py
|
||||
common/logging_extra.py
|
||||
common/numpy_fast.py
|
||||
common/params.py
|
||||
common/params_pyx.pyx
|
||||
common/profiler.py
|
||||
common/basedir.py
|
||||
common/dict_helpers.py
|
||||
common/filter_simple.py
|
||||
common/stat_live.py
|
||||
common/spinner.py
|
||||
common/text_window.py
|
||||
common/time.py
|
||||
|
||||
common/kalman/.gitignore
|
||||
common/kalman/*
|
||||
common/*.py
|
||||
common/*.pyx
|
||||
|
||||
common/transformations/__init__.py
|
||||
common/transformations/camera.py
|
||||
@@ -76,7 +57,6 @@ selfdrive/statsd.py
|
||||
|
||||
system/logmessaged.py
|
||||
system/micd.py
|
||||
system/swaglog.py
|
||||
system/version.py
|
||||
|
||||
selfdrive/athena/__init__.py
|
||||
@@ -115,9 +95,7 @@ selfdrive/car/ecu_addrs.py
|
||||
selfdrive/car/isotp_parallel_query.py
|
||||
selfdrive/car/tests/__init__.py
|
||||
selfdrive/car/tests/test_car_interfaces.py
|
||||
selfdrive/car/torque_data/params.yaml
|
||||
selfdrive/car/torque_data/substitute.yaml
|
||||
selfdrive/car/torque_data/override.yaml
|
||||
selfdrive/car/torque_data/*.toml
|
||||
|
||||
selfdrive/car/body/*.py
|
||||
selfdrive/car/chrysler/*.py
|
||||
@@ -137,6 +115,7 @@ selfdrive/debug/can_printer.py
|
||||
selfdrive/debug/check_freq.py
|
||||
selfdrive/debug/dump.py
|
||||
selfdrive/debug/filter_log_message.py
|
||||
selfdrive/debug/format_fingerprints.py
|
||||
selfdrive/debug/get_fingerprint.py
|
||||
selfdrive/debug/uiview.py
|
||||
|
||||
@@ -149,31 +128,8 @@ selfdrive/gpxd/gpxd.py
|
||||
common/SConscript
|
||||
common/version.h
|
||||
|
||||
common/prefix.h
|
||||
common/swaglog.h
|
||||
common/swaglog.cc
|
||||
common/statlog.h
|
||||
common/statlog.cc
|
||||
common/util.cc
|
||||
common/util.h
|
||||
common/queue.h
|
||||
common/clutil.cc
|
||||
common/clutil.h
|
||||
common/params.h
|
||||
common/params.cc
|
||||
common/ratekeeper.cc
|
||||
common/ratekeeper.h
|
||||
common/watchdog.cc
|
||||
common/watchdog.h
|
||||
|
||||
common/modeldata.h
|
||||
common/mat.h
|
||||
common/timing.h
|
||||
|
||||
common/gpio.cc
|
||||
common/gpio.h
|
||||
common/i2c.cc
|
||||
common/i2c.h
|
||||
common/*.h
|
||||
common/*.cc
|
||||
|
||||
selfdrive/controls/__init__.py
|
||||
selfdrive/controls/controlsd.py
|
||||
@@ -189,7 +145,6 @@ selfdrive/controls/lib/latcontrol_angle.py
|
||||
selfdrive/controls/lib/latcontrol_torque.py
|
||||
selfdrive/controls/lib/latcontrol_pid.py
|
||||
selfdrive/controls/lib/latcontrol.py
|
||||
selfdrive/controls/lib/lateral_planner.py
|
||||
selfdrive/controls/lib/longcontrol.py
|
||||
selfdrive/controls/lib/longitudinal_planner.py
|
||||
selfdrive/controls/lib/pid.py
|
||||
@@ -201,6 +156,7 @@ selfdrive/controls/lib/lateral_mpc_lib/*
|
||||
selfdrive/controls/lib/longitudinal_mpc_lib/*
|
||||
|
||||
system/__init__.py
|
||||
system/*.py
|
||||
|
||||
system/hardware/__init__.py
|
||||
system/hardware/base.h
|
||||
@@ -217,6 +173,7 @@ system/hardware/tici/agnos.json
|
||||
system/hardware/tici/amplifier.py
|
||||
system/hardware/tici/updater
|
||||
system/hardware/tici/iwlist.py
|
||||
system/hardware/tici/esim.nmconnection
|
||||
system/hardware/pc/__init__.py
|
||||
system/hardware/pc/hardware.h
|
||||
system/hardware/pc/hardware.py
|
||||
@@ -236,12 +193,10 @@ selfdrive/locationd/paramsd.py
|
||||
selfdrive/locationd/models/__init__.py
|
||||
selfdrive/locationd/models/.gitignore
|
||||
selfdrive/locationd/models/car_kf.py
|
||||
selfdrive/locationd/models/gnss_kf.py
|
||||
selfdrive/locationd/models/live_kf.py
|
||||
selfdrive/locationd/models/live_kf.h
|
||||
selfdrive/locationd/models/live_kf.cc
|
||||
selfdrive/locationd/models/constants.py
|
||||
selfdrive/locationd/models/gnss_helpers.py
|
||||
|
||||
selfdrive/locationd/torqued.py
|
||||
selfdrive/locationd/calibrationd.py
|
||||
@@ -286,6 +241,12 @@ system/sensord/sensors/*.cc
|
||||
system/sensord/sensors/*.h
|
||||
system/sensord/pigeond.py
|
||||
|
||||
system/webrtc/__init__.py
|
||||
system/webrtc/webrtcd.py
|
||||
system/webrtc/schema.py
|
||||
system/webrtc/device/audio.py
|
||||
system/webrtc/device/video.py
|
||||
|
||||
selfdrive/thermald/thermald.py
|
||||
selfdrive/thermald/power_monitoring.py
|
||||
selfdrive/thermald/fan_controller.py
|
||||
@@ -301,13 +262,9 @@ selfdrive/ui/.gitignore
|
||||
selfdrive/ui/SConscript
|
||||
selfdrive/ui/*.cc
|
||||
selfdrive/ui/*.h
|
||||
selfdrive/ui/ui
|
||||
selfdrive/ui/text
|
||||
selfdrive/ui/spinner
|
||||
selfdrive/ui/soundd/*.cc
|
||||
selfdrive/ui/soundd/*.h
|
||||
selfdrive/ui/soundd/soundd
|
||||
selfdrive/ui/soundd/.gitignore
|
||||
selfdrive/ui/soundd.py
|
||||
selfdrive/ui/translations/*.ts
|
||||
selfdrive/ui/translations/languages.json
|
||||
selfdrive/ui/update_translations.py
|
||||
@@ -337,12 +294,8 @@ system/camerad/main.cc
|
||||
system/camerad/snapshot/*
|
||||
system/camerad/cameras/camera_common.h
|
||||
system/camerad/cameras/camera_common.cc
|
||||
system/camerad/cameras/sensor2_i2c.h
|
||||
|
||||
system/camerad/imgproc/conv.cl
|
||||
system/camerad/imgproc/pool.cl
|
||||
system/camerad/imgproc/utils.cc
|
||||
system/camerad/imgproc/utils.h
|
||||
system/camerad/sensors/*.h
|
||||
system/camerad/sensors/*.cc
|
||||
|
||||
selfdrive/manager/__init__.py
|
||||
selfdrive/manager/build.py
|
||||
@@ -448,9 +401,11 @@ third_party/qt5/larch64/bin/**
|
||||
scripts/update_now.sh
|
||||
scripts/stop_updater.sh
|
||||
|
||||
teleoprtc/**
|
||||
|
||||
rednose_repo/site_scons/site_tools/rednose_filter.py
|
||||
rednose/.gitignore
|
||||
rednose/**
|
||||
laika/**
|
||||
|
||||
body/.gitignore
|
||||
body/board/SConscript
|
||||
|
||||