Compare commits

..

204 Commits

Author SHA1 Message Date
royjr 12f2c30c14 Merge branch 'master' into ccnc-port 2026-09-07 00:44:44 -04:00
royjr 0999b0cbe9 Merge branch 'master' into ccnc-port 2026-09-02 15:16:21 -04:00
royjr ed1121e61c Update opendbc_repo 2026-09-02 15:16:02 -04:00
royjr 50d7f75bfc Merge branch 'master' into ccnc-port 2026-08-30 16:21:17 -04:00
royjr 15c7f52e40 Merge branch 'master' into ccnc-port 2026-08-28 20:28:33 -04:00
royjr 8dfe04a318 Merge branch 'master' into ccnc-port 2026-08-24 14:19:36 -04:00
royjr 9648ac2f04 Merge branch 'master' into ccnc-port 2026-08-23 21:48:17 -04:00
royjr a03a11e333 Merge branch 'master' into ccnc-port 2026-08-23 19:36:45 -04:00
royjr 53b1070b09 Merge branch 'master' into ccnc-port 2026-08-23 11:05:40 -04:00
royjr 68bf6d8162 Merge branch 'master' into ccnc-port 2026-08-22 13:19:05 -04:00
royjr 8b472291d0 Merge branch 'master' into ccnc-port 2026-08-21 17:12:13 -04:00
royjr 797c8d4293 Update opendbc_repo 2026-08-21 17:09:31 -04:00
royjr 7568528507 Merge branch 'master' into ccnc-port 2026-08-19 12:53:59 -04:00
royjr 6665c3acf6 Merge branch 'master' into ccnc-port 2026-08-17 10:14:33 -04:00
royjr 3b13eb4d0d Update opendbc_repo 2026-08-17 10:14:19 -04:00
royjr f7eb4c2561 Update opendbc_repo 2026-08-15 01:39:27 -04:00
royjr be9255358c Update opendbc_repo 2026-08-15 01:35:33 -04:00
royjr f48ccb5d7a Merge branch 'master' into ccnc-port 2026-08-14 20:42:45 -04:00
royjr 99559d6749 Update opendbc_repo 2026-08-14 20:42:36 -04:00
royjr 4b6f0ffb46 Merge branch 'master' into ccnc-port 2026-08-11 11:56:46 -04:00
royjr 55415382ce Update opendbc_repo 2026-08-11 11:56:38 -04:00
royjr 9f30901eb6 Merge branch 'master' into ccnc-port 2026-08-10 16:33:50 -04:00
royjr d2045d24fb Update opendbc_repo 2026-08-10 16:33:37 -04:00
royjr 6488a11e4d Merge branch 'master' into ccnc-port 2026-08-02 14:27:34 -04:00
royjr 7b22b65313 Merge branch 'master' into ccnc-port 2026-07-27 15:29:04 -04:00
royjr b59a50101e Update opendbc_repo 2026-07-27 15:28:51 -04:00
royjr 3e30962bd3 Merge branch 'master' into ccnc-port 2026-07-25 03:04:23 -04:00
royjr 3274043063 Update opendbc_repo 2026-07-25 03:04:12 -04:00
royjr c624550d2e Merge branch 'master' into ccnc-port 2026-07-20 15:52:41 -04:00
royjr 6759038671 Merge branch 'master' into ccnc-port 2026-07-20 09:18:18 -04:00
royjr aa636e75c8 Merge branch 'master' into ccnc-port 2026-07-16 00:23:49 -04:00
royjr 5ff3c3bd8d Update opendbc_repo 2026-07-16 00:23:43 -04:00
royjr 1e11b52290 Update opendbc_repo 2026-07-14 00:40:02 -04:00
royjr 76e0204025 Update opendbc_repo 2026-07-14 00:37:13 -04:00
royjr cc88f2cbd6 Update opendbc_repo 2026-07-10 22:00:25 -04:00
royjr ee0ac199a4 Update opendbc_repo 2026-07-03 08:08:29 -04:00
royjr d5ed828eaa Update opendbc_repo 2026-07-01 19:30:06 -04:00
royjr 9fca585f2a Merge branch 'master' into ccnc-port 2026-06-30 22:14:33 -04:00
royjr bb1259303e Update opendbc_repo 2026-06-30 22:14:23 -04:00
royjr e135051ca8 Merge branch 'master' into ccnc-port 2026-06-13 22:38:22 -04:00
royjr 12bef55d8a Update opendbc_repo 2026-06-13 22:12:00 -04:00
royjr 2f7a45e6c8 Merge branch 'master' into ccnc-port 2026-06-08 22:01:57 -04:00
royjr 936ebfc12b Update opendbc_repo 2026-06-08 22:01:44 -04:00
royjr aa0c9dc0eb Merge branch 'master' into ccnc-port 2026-06-04 09:52:35 -04:00
royjr 7476a866e7 Update opendbc_repo 2026-06-04 09:52:06 -04:00
royjr 610d857e33 Merge branch 'master' into ccnc-port 2026-05-28 08:30:40 -04:00
royjr d2f47407d0 Update opendbc_repo 2026-05-12 21:03:18 -04:00
royjr db75ec76ea Merge branch 'master' into ccnc-port 2026-05-12 20:44:57 -04:00
royjr 24066465d7 Update opendbc_repo 2026-05-12 20:44:48 -04:00
royjr a7abbd6e25 Update opendbc_repo 2026-04-20 18:22:12 -04:00
royjr 878982447c Merge branch 'master' into ccnc-port 2026-04-19 12:06:46 -04:00
royjr 576527a36b Merge branch 'master' into ccnc-port 2026-04-17 05:42:35 -04:00
royjr ef8c35da24 Update opendbc_repo 2026-04-17 05:41:21 -04:00
royjr 85688b1040 Merge branch 'master' into ccnc-port 2026-04-16 19:48:39 -04:00
royjr 0fb2199130 Update opendbc_repo 2026-04-16 19:47:57 -04:00
royjr d48d756c1d Update opendbc_repo 2026-04-08 00:56:54 -04:00
royjr 2ed298a0c9 Merge branch 'master' into ccnc-port 2026-04-08 00:51:13 -04:00
royjr d68f038949 Update opendbc_repo 2026-04-08 00:51:11 -04:00
royjr 7231571e57 Merge branch 'master' into ccnc-port 2026-04-03 23:34:00 -04:00
royjr b37f1419d3 Update opendbc_repo 2026-04-03 23:33:19 -04:00
royjr cd85a66790 Merge branch 'master' into ccnc-port 2026-03-26 00:53:07 -04:00
royjr 305ea87daf Update opendbc_repo 2026-03-26 00:52:44 -04:00
royjr 4bbfc793e0 Merge branch 'master' into ccnc-port 2026-03-15 15:44:59 -04:00
royjr d5d983676e Update opendbc_repo 2026-03-13 16:41:05 -04:00
royjr de8a96a398 Merge branch 'master' into ccnc-port 2026-03-13 16:41:00 -04:00
royjr 0cbf45f699 Merge branch 'master' into ccnc-port 2026-03-11 23:28:59 -04:00
royjr 0d68a3a2ab Merge branch 'master' into ccnc-port 2026-03-09 19:58:32 -04:00
royjr 9e85a85059 Update opendbc_repo 2026-03-09 19:58:18 -04:00
royjr 0373c327c0 Update opendbc_repo 2026-03-02 10:10:38 -05:00
royjr efe9e5c200 Update opendbc_repo 2026-03-02 02:15:05 -05:00
royjr 8a249a45dc Update opendbc_repo 2026-03-02 02:06:16 -05:00
royjr bdbefe67f6 Update opendbc_repo 2026-03-02 01:40:31 -05:00
royjr 675bb166ad Merge branch 'master' into ccnc-port 2026-03-01 17:18:11 -05:00
royjr 1b717a7e88 Merge branch 'master' into ccnc-port 2026-03-01 13:23:30 -05:00
royjr 86f55a8ba9 Update opendbc_repo 2026-03-01 13:23:24 -05:00
royjr 629392d2f7 Update opendbc_repo 2026-02-27 16:31:59 -05:00
royjr bc414bdc8b Update opendbc_repo 2026-02-26 23:53:26 -05:00
royjr 7ca5649f2c Merge branch 'master' into ccnc-port 2026-02-26 23:52:46 -05:00
royjr 641ee8fa87 Update opendbc_repo 2026-02-26 23:52:27 -05:00
royjr 56c276158c Merge branch 'master' into ccnc-port 2026-02-24 14:12:12 -05:00
royjr c65308a8bd Update opendbc_repo 2026-02-24 14:12:01 -05:00
royjr 994e526460 Merge branch 'master' into ccnc-port 2026-02-18 12:06:05 -05:00
royjr 1defae36b7 Update opendbc_repo 2026-02-18 12:05:53 -05:00
royjr 8f029fd0ef Merge branch 'master' into ccnc-port 2026-02-13 23:01:41 -05:00
royjr ddb46284dc Update opendbc_repo 2026-02-13 23:01:16 -05:00
royjr 9effc754d9 Merge branch 'master' into ccnc-port 2026-02-06 01:16:06 -05:00
royjr e49ffc2a2d Update opendbc_repo 2026-02-06 01:15:59 -05:00
royjr 2cacd0b3e5 Merge branch 'master' into ccnc-port 2026-01-24 12:50:18 -05:00
royjr c4b8859dff Update opendbc_repo 2026-01-24 12:50:11 -05:00
royjr 8fb0953205 Merge branch 'master' into ccnc-port 2026-01-11 22:17:38 -05:00
royjr 63d1c8835f Merge branch 'master' into ccnc-port 2026-01-10 13:03:48 -05:00
royjr 17a185606d Merge branch 'master' into ccnc-port 2026-01-09 16:40:32 -05:00
royjr da10131392 Merge branch 'master' into ccnc-port 2025-12-28 17:18:51 -05:00
royjr 7107c2ba14 Merge branch 'master' into ccnc-port 2025-12-23 12:13:48 -05:00
royjr 95b6e877ac Update opendbc_repo 2025-12-23 12:13:29 -05:00
royjr eb02c6570e Update opendbc_repo 2025-12-21 15:43:04 -05:00
royjr 1be8ae31c4 Merge branch 'master' into ccnc-port 2025-12-19 01:04:42 -05:00
royjr 04dcd38856 Update opendbc_repo 2025-12-19 01:04:30 -05:00
royjr 22ccf0d72f Merge branch 'master' into ccnc-port 2025-12-15 17:02:50 -05:00
royjr 3c969bb627 Merge branch 'master' into ccnc-port 2025-12-13 23:22:22 -05:00
royjr 20f8011feb Update opendbc_repo 2025-12-13 23:22:11 -05:00
royjr 9cf17e74a1 Merge branch 'master' into ccnc-port 2025-12-12 23:19:56 -05:00
royjr 2c4efdf557 Merge branch 'master' into ccnc-port 2025-12-07 13:29:48 -05:00
royjr 4cd3d3c16c Merge branch 'master' into ccnc-port 2025-12-02 12:56:21 -05:00
royjr 637f3ae9c8 Merge branch 'master' into ccnc-port 2025-12-01 14:41:03 -05:00
royjr 464ee80f71 Merge branch 'master' into ccnc-port 2025-11-26 00:27:53 -05:00
royjr 2743a04613 Merge branch 'master' into ccnc-port 2025-11-24 18:44:13 -05:00
royjr 7f9978d001 Merge branch 'master' into ccnc-port 2025-11-22 00:21:15 -05:00
royjr 4b83961c67 Merge branch 'master' into ccnc-port 2025-11-21 16:23:22 -05:00
royjr c00eaf428a Update opendbc_repo 2025-11-21 16:23:01 -05:00
royjr 0a9993e8d4 Merge branch 'master' into ccnc-port 2025-11-19 16:49:59 -05:00
royjr 0af214a985 Update opendbc_repo 2025-11-19 16:49:51 -05:00
royjr af43385e3a Merge branch 'master' into ccnc-port 2025-11-11 10:19:51 -05:00
royjr 0ab2b8c590 Update opendbc_repo 2025-11-07 19:59:50 -05:00
royjr 67ab18a0de Merge branch 'master' into ccnc-port 2025-11-07 19:23:51 -05:00
royjr e87dc15b30 Update opendbc_repo 2025-11-07 19:23:37 -05:00
royjr 192d08516c Merge branch 'master' into ccnc-port 2025-11-02 19:23:00 -05:00
royjr 3cf001c59c Update opendbc_repo 2025-11-02 19:22:49 -05:00
royjr f2ccd021da Merge branch 'master' into ccnc-port 2025-11-02 14:07:54 -05:00
royjr c9fc900f64 Update opendbc_repo 2025-11-02 14:07:44 -05:00
royjr 3c37c5ce5d Update opendbc_repo 2025-10-30 11:28:49 -04:00
royjr 7c45889e4e Merge branch 'master' into ccnc-port 2025-10-30 11:27:50 -04:00
royjr 2aabb7aee8 Merge branch 'master' into ccnc-port 2025-10-24 14:16:09 -04:00
royjr 3859e9962f Update opendbc_repo 2025-10-24 14:15:51 -04:00
royjr 810efbab72 Merge branch 'master' into ccnc-port 2025-10-18 07:33:11 -04:00
royjr ec27bec326 Update opendbc_repo 2025-10-18 07:32:33 -04:00
royjr 250d553157 Merge branch 'master' into ccnc-port 2025-10-14 21:57:32 -04:00
royjr cea54a0ca8 Update opendbc_repo 2025-10-14 21:57:26 -04:00
royjr 8e72d783bd Update opendbc_repo 2025-10-13 22:41:21 -04:00
royjr 1b0dc103dc Merge branch 'master' into ccnc-port 2025-10-11 23:51:46 -04:00
royjr 6c364d292b Update opendbc_repo 2025-10-11 23:51:31 -04:00
royjr bcdec2ce84 Merge branch 'master' into ccnc-port 2025-10-10 17:29:05 -04:00
royjr 3deaeb3759 Merge branch 'master' into ccnc-port 2025-10-10 15:02:32 -04:00
royjr c669f0984a Update opendbc_repo 2025-10-10 15:02:17 -04:00
royjr 46dd946740 Merge branch 'master' into ccnc-port 2025-10-07 01:36:06 -04:00
royjr 9da4b3653e Update opendbc_repo 2025-10-07 01:35:58 -04:00
royjr 4e21ae7c50 Update opendbc_repo 2025-10-05 06:21:56 -04:00
royjr bb91e92237 Update opendbc_repo 2025-10-05 06:01:15 -04:00
royjr 14b4c4f85b Update opendbc_repo 2025-10-02 09:20:32 -04:00
royjr 0660b542c3 Merge branch 'master' into ccnc-port 2025-10-01 16:01:32 -04:00
royjr 2b893b90c9 Update opendbc_repo 2025-10-01 16:01:26 -04:00
royjr f5139178ed Merge branch 'master' into ccnc-port 2025-09-30 14:39:57 -04:00
royjr fb43b755f2 Update opendbc_repo 2025-09-30 14:39:50 -04:00
royjr 07f5b967d8 Merge branch 'master' into ccnc-port 2025-09-24 21:30:29 -04:00
royjr ea19c7d3bb Update opendbc_repo 2025-09-24 21:30:17 -04:00
royjr e461842cbb Merge branch 'master' into ccnc-port 2025-09-23 05:55:02 -04:00
royjr a73c9659d5 Update opendbc_repo 2025-09-23 05:54:50 -04:00
royjr cb796fbc76 Merge branch 'master' into ccnc-port 2025-09-18 20:10:43 -04:00
royjr 6bf75fc557 Update opendbc_repo 2025-09-18 20:10:37 -04:00
royjr 9a1fc28819 Merge branch 'master' into ccnc-port 2025-09-18 13:54:36 -04:00
royjr 0741d05e92 Update opendbc_repo 2025-09-18 13:54:23 -04:00
royjr 1ad008107d Merge branch 'master' into ccnc-port 2025-09-15 01:40:27 -04:00
royjr feebd9df93 Reapply "UI: Developer UI (#1233)"
This reverts commit 15e5d2efb9.
2025-09-15 01:40:21 -04:00
royjr c2e5ced3e5 Update opendbc_repo 2025-09-15 01:39:51 -04:00
royjr 15e5d2efb9 Revert "UI: Developer UI (#1233)"
This reverts commit 1bb4ca2547.
2025-09-12 02:10:29 -04:00
royjr a3929d0b54 Merge branch 'master' into ccnc-port 2025-09-12 01:40:29 -04:00
royjr 794f8f9991 Update opendbc_repo 2025-09-08 09:27:31 -04:00
royjr 68fa5e3f21 Merge branch 'master' into ccnc-port 2025-09-07 13:13:37 -04:00
royjr 86c6cc1f48 Merge branch 'master' into ccnc-port 2025-09-03 22:22:12 -04:00
royjr eb7ffbf093 Update opendbc_repo 2025-09-03 10:14:58 -04:00
royjr 3919095752 Update opendbc_repo 2025-09-03 10:05:35 -04:00
royjr 74d63be1c3 Merge branch 'master' into ccnc-port 2025-09-03 09:50:55 -04:00
royjr 8894486a1a Update opendbc_repo 2025-09-03 09:50:49 -04:00
royjr 810599315d Merge branch 'master' into ccnc-port 2025-08-31 16:53:30 -04:00
royjr 6f3ab810c8 Update opendbc_repo 2025-08-31 16:53:24 -04:00
royjr 230f78b8d3 Merge branch 'master' into ccnc-port 2025-08-26 12:14:46 -04:00
royjr f1affec088 Update opendbc_repo 2025-08-26 12:14:22 -04:00
royjr 97d8ef242c Merge branch 'master' into ccnc-port 2025-08-24 15:12:57 -04:00
royjr a63fff9b45 Update opendbc_repo 2025-08-24 15:12:46 -04:00
royjr cb3893daaa Merge branch 'master' into ccnc-port 2025-08-23 10:33:24 -04:00
royjr 29f60df74b Merge branch 'master' into ccnc-port 2025-08-22 11:18:27 -04:00
royjr c6c072e1f4 Update opendbc_repo 2025-08-22 11:18:18 -04:00
royjr d101cbb83e Update opendbc_repo 2025-08-13 16:00:04 -04:00
royjr 1536d59633 Update opendbc_repo 2025-08-13 15:28:37 -04:00
royjr dc99b865ae Merge branch 'master' into ccnc-port 2025-08-13 12:31:14 -04:00
royjr e59bc027ff Merge branch 'master' into ccnc-port 2025-08-13 11:58:05 -04:00
royjr cf7e5efaca Update opendbc_repo 2025-08-13 11:57:57 -04:00
royjr 4b44f2eb31 Merge branch 'master' into ccnc-port 2025-08-10 09:18:24 -04:00
royjr 107d2ab400 Update opendbc_repo 2025-08-10 09:18:15 -04:00
royjr 5432d9062c Merge branch 'master' into ccnc-port 2025-08-04 11:52:29 -04:00
royjr f533f6c843 Merge branch 'master' into ccnc-port 2025-08-02 06:53:54 -04:00
royjr 58e9ac763c Update opendbc_repo 2025-08-02 06:53:43 -04:00
royjr cb50d54169 Merge branch 'master-new' into ccnc-port 2025-07-24 20:23:46 -04:00
royjr bd5de4ed0a Merge branch 'master-new' into ccnc-port 2025-07-20 23:49:36 -04:00
royjr 0d4073fadb Merge branch 'master-new' into ccnc-port 2025-07-19 23:18:26 -04:00
royjr ebc70dcb52 Merge branch 'master-new' into ccnc-port 2025-07-19 14:37:17 -04:00
royjr 4d0426999e Update opendbc_repo 2025-07-19 14:36:59 -04:00
royjr 286da42573 Merge branch 'master-new' into ccnc-port 2025-07-16 23:48:23 -04:00
royjr 8a836710a9 Update opendbc_repo 2025-07-16 23:48:06 -04:00
royjr 5d515bcf33 Merge branch 'master-new' into ccnc-port 2025-07-07 05:35:55 -04:00
royjr 1c7f6d5133 Update opendbc_repo 2025-07-03 21:24:01 -04:00
royjr 05d57c7aeb Update opendbc_repo 2025-07-01 18:30:32 -04:00
royjr e4b0eaf352 Update opendbc_repo 2025-06-28 19:30:28 -04:00
royjr a710276472 Merge branch 'master-new' into ccnc-port 2025-06-28 19:22:59 -04:00
royjr af086db671 Merge branch 'master-new' into ccnc-port 2025-06-28 12:13:26 -04:00
royjr 0d9eb0e25e Update opendbc_repo submodule to latest commit
Advanced the opendbc_repo submodule to commit d309f7ec96e37267c94d12fc4bfe2672ad505b06. This pulls in the latest changes from the opendbc repository.
2025-06-26 14:03:56 -04:00
royjr 0616caed6d Merge branch 'master-new' into ccnc-port 2025-06-25 19:33:53 -04:00
royjr 095337b3c1 Update opendbc_repo 2025-06-25 19:33:38 -04:00
royjr 1edec2d22c Update opendbc_repo 2025-06-14 16:14:02 -04:00
royjr affabb9ee0 Update opendbc_repo 2025-06-14 15:55:07 -04:00
royjr dc27e8711c Update opendbc_repo 2025-06-14 14:54:32 -04:00
royjr cf7329a264 Merge branch 'master-new' into ccnc-port 2025-06-11 21:36:06 -04:00
royjr 5ee5ecd820 Merge branch 'master-new' into ccnc-port 2025-06-08 23:25:13 -04:00
royjr b064f730dd Update opendbc_repo 2025-06-08 17:54:43 -04:00
18 changed files with 215 additions and 401 deletions
+43
View File
@@ -0,0 +1,43 @@
exclude-labels:
- 'no-changelog'
categories:
- title: '🚀 Features'
labels:
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes'
collapse-after: 5
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 Maintenance'
collapse-after: 5
label: 'chore'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&'
replacers:
- search: '/[Ss][Uu][Nn][Nn][Yy][Pp][Ii][Ll][Oo][Tt]/g'
replace: 'sunnypilot'
- search: '/\b[Ss][Pp]\b/g'
replace: 'SP'
version-resolver:
major:
labels:
- 'major'
minor:
labels:
- 'minor'
patch:
labels:
- 'patch'
default: patch
name-template: 'v$RESOLVED_VERSION 🚀'
tag-template: 'v$RESOLVED_VERSION'
version-template: "0.$MAJOR.$MINOR.$PATCH" # The day OP becomes v1, we need to bump this
tag-prefix: "v0." # The day OP becomes v1, we need to bump this
prerelease-identifier: "staging"
template: |
## Changes
$CHANGES
@@ -20,11 +20,6 @@ on:
required: false
type: string
default: 'sunnypilot/sunnypilot_models_v1'
docs_repo:
description: 'GitHub repo holding the driving_models JSON on its gh-pages branch'
required: false
type: string
default: 'sunnypilot/sunnypilot-models'
jobs:
setup:
@@ -39,6 +34,7 @@ jobs:
- name: Checkout sunnypilot repo
uses: actions/checkout@v4
with:
repository: sunnypilot/sunnypilot
path: sunnypilot
submodules: recursive
@@ -51,10 +47,10 @@ jobs:
echo "tinygrad_ref=$ref" >> $GITHUB_OUTPUT
echo "tinygrad_ref is $ref"
- name: Checkout docs repo (gh-pages)
- name: Checkout docs repo (sunnypilot-models, gh-pages)
uses: actions/checkout@v4
with:
repository: ${{ inputs.docs_repo }}
repository: sunnypilot/sunnypilot-models
ref: gh-pages
path: docs
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
@@ -122,7 +118,6 @@ jobs:
json_version: ${{ needs.setup.outputs.json_version }}
target_hardware: ${{ github.event.inputs.target_hardware }}
hf_repo: ${{ github.event.inputs.hf_repo }}
docs_repo: ${{ inputs.docs_repo }}
set_min_version: ${{ github.event.inputs.set_min_version }}
tinygrad_ref: ${{ needs.setup.outputs.tinygrad_ref }}
secrets: inherit
@@ -167,7 +162,6 @@ jobs:
target_hardware: ${{ github.event.inputs.target_hardware }}
artifact_suffix: -retry
hf_repo: ${{ github.event.inputs.hf_repo }}
docs_repo: ${{ inputs.docs_repo }}
set_min_version: ${{ github.event.inputs.set_min_version }}
tinygrad_ref: ${{ needs.setup.outputs.tinygrad_ref }}
secrets: inherit
@@ -39,11 +39,6 @@ on:
required: false
type: string
default: 'sunnypilot/sunnypilot_models_v1'
docs_repo:
description: 'GitHub repo holding the driving_models JSON on its gh-pages branch'
required: false
type: string
default: 'sunnypilot/sunnypilot-models'
set_min_version:
description: 'Minimum selector version'
required: false
@@ -112,11 +107,6 @@ on:
required: false
type: string
default: 'sunnypilot/sunnypilot_models_v1'
docs_repo:
description: 'GitHub repo holding the driving_models JSON on its gh-pages branch'
required: false
type: string
default: 'sunnypilot/sunnypilot-models'
env:
RECOMPILED_DIR: recompiled${{ inputs.recompiled_dir }}
JSON_FILE: docs/docs/driving_models_${{ inputs.target_hardware == 'chestnut' && 'chestnut_v' || 'v' }}${{ inputs.json_version }}.json
@@ -146,7 +136,7 @@ jobs:
- name: Checkout docs repo
uses: actions/checkout@v4
with:
repository: ${{ inputs.docs_repo }}
repository: sunnypilot/sunnypilot-models
ref: gh-pages
path: docs
ssh-key: ${{ secrets.CI_SUNNYPILOT_DOCS_PRIVATE_KEY }}
+28
View File
@@ -0,0 +1,28 @@
name: Release Drafter
on:
push:
branches:
- master
tags:
- 'v*'
pull_request_target:
types: [opened, reopened, synchronize]
workflow_dispatch:
permissions:
contents: read
jobs:
update_release_draft:
permissions:
contents: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v6
with:
config-name: release-drafter.yml
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+78
View File
@@ -0,0 +1,78 @@
name: Debug Discourse Posting
on:
push:
jobs:
test-discourse-post:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Post test message to Discourse
uses: ./.github/workflows/post-to-discourse
with:
discourse-url: ${{ vars.DISCOURSE_URL }}
api-key: ${{ secrets.DISCOURSE_API_KEY }}
api-username: ${{ secrets.DISCOURSE_API_USERNAME }}
topic-id: ${{ vars.DISCOURSE_UPDATES_TOPIC_ID }}
message: |
## 🧪 Test Post from GitHub Actions
**This is a test post to verify Discourse integration**
- **Workflow**: ${{ github.workflow }}
- **Run Number**: #${{ github.run_number }}
- **Branch**: `${{ github.ref_name }}`
- **Commit**: ${{ github.sha }}
- **Actor**: @${{ github.actor }}
- **Timestamp**: ${{ github.event.head_commit.timestamp }}
---
### Fake Build Info (for testing)
- **Version**: 0.9.8-test
- **Build**: #42
- **Branch**: release-test
[View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
*This is an automated test message. Drive safe! 🚗💨*
- name: Create topic on Discourse
uses: ./.github/workflows/post-to-discourse
with:
discourse-url: ${{ vars.DISCOURSE_URL }}
api-key: ${{ secrets.DISCOURSE_API_KEY }}
api-username: ${{ secrets.DISCOURSE_API_USERNAME }}
#topic-id: ${{ vars.DISCOURSE_UPDATES_TOPIC_ID }}
category-id: 4
title: "This is a test of a new topic instead of a reply"
message: |
## 🧪 Test Post from GitHub Actions
**This is a test post to verify Discourse integration**
- **Workflow**: ${{ github.workflow }}
- **Run Number**: #${{ github.run_number }}
- **Branch**: `${{ github.ref_name }}`
- **Commit**: ${{ github.sha }}
- **Actor**: @${{ github.actor }}
- **Timestamp**: ${{ github.event.head_commit.timestamp }}
---
### Fake Build Info (for testing)
- **Version**: 0.9.8-test
- **Build**: #42
- **Branch**: release-test
[View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
*This is an automated test message. Drive safe! 🚗💨*
- name: Display results
if: always()
run: |
echo "::notice::Discourse post test completed"
echo "Check your Discourse topic to verify the post appeared correctly"
-79
View File
@@ -1,79 +0,0 @@
name: Test Models Compatibility With Tinygrad Changes
on:
pull_request:
paths:
- 'tinygrad_repo'
workflow_dispatch:
jobs:
generate-matrix:
runs-on: ubuntu-latest
outputs:
models: ${{ steps.set-matrix.outputs.models }}
steps:
- uses: actions/checkout@v4
- name: Fetch and Parse json
id: set-matrix
run: |
python3 -c '
import json, urllib.request, os, re
with open("openpilot/sunnypilot/models/fetcher.py", "r") as f:
urls = re.findall(r"MODEL_URL(?:_CHESTNUT)?\s*=\s*[\"'"'"']([^\"'"'"']+)[\"'"'"']", f.read())
artifacts = []
for url in urls:
data = json.loads(urllib.request.urlopen(url).read())
for bundle in data.get("bundles", []):
for model in bundle.get("models", []):
if "artifact" in model:
artifacts.append(model["artifact"])
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
f.write(f"models={json.dumps(artifacts)}\n")
'
test-model:
name: Test ${{ matrix.artifact.file_name }}
needs: generate-matrix
runs-on: ubuntu-latest
container: ghcr.io/commaai/openpilot-base:latest
strategy:
fail-fast: false
matrix:
artifact: ${{ fromJson(needs.generate-matrix.outputs.models) }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Download Model Chunks in Parallel
run: |
mkdir -p /tmp/model_chunks
echo '${{ toJson(matrix.artifact.chunks) }}' > chunks.json
BASE_URL="${{ matrix.artifact.download_uri.url }}"
export BASE_DIR=$(dirname "$BASE_URL")
python3 -c '
import json, os
with open("chunks.json") as f:
chunks = json.load(f)
manifest_path = f"/tmp/model_chunks/${{ matrix.artifact.file_name }}.chunkmanifest"
with open(manifest_path, "w") as f:
f.write(str(len(chunks)))
base_dir = os.environ["BASE_DIR"]
with open("/tmp/curl_config.txt", "w") as f:
for c in chunks:
fn = c["file_name"]
f.write(f"url = \"{base_dir}/{fn}\"\noutput = \"/tmp/model_chunks/{fn}\"\n")
'
curl -Z --parallel-immediate --parallel-max 16 -s -S -f -L -K /tmp/curl_config.txt
- name: Run Model Compatibility Test
env:
MODEL_BASE_NAME: ${{ matrix.artifact.file_name }}
MODEL_CHUNK_DIR: "/tmp/model_chunks"
PYTHONPATH: ".:./tinygrad_repo"
run: |
python3 -m pytest openpilot/sunnypilot/modeld_v2/tests/test_models.py
-1
View File
@@ -474,7 +474,6 @@ def main(demo=False):
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob, left_edge, right_edge)
modelv2_send.modelV2.meta.laneChangeState = DH.lane_change_state
modelv2_send.modelV2.meta.laneChangeDirection = DH.lane_change_direction
mdv2sp_send.valid = modelv2_send.valid
mdv2sp_send.modelDataV2SP.laneTurnDirection = DH.lane_turn_direction
fill_driving_model_data(drivingdata_send, modelv2_send)
@@ -4,6 +4,7 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
import os
import re
import time
import pyray as rl
@@ -12,8 +13,7 @@ from openpilot.cereal import custom
from openpilot.sunnypilot.models.helpers import ACTIVE_BUNDLE_KEYS, get_selected_bundle, resolve_bundle_by_ref
from openpilot.common.constants import CV
from openpilot.selfdrive.ui.ui_state import device, ui_state
from openpilot.selfdrive.ui.sunnypilot.model_info import (big_model_state, bundles_for_source, carrying_model, default_model_name,
model_cache_size_mb, queued_name, refresh_in_progress, refresh_model_list)
from openpilot.selfdrive.ui.sunnypilot.model_info import big_model_state, bundles_for_source, carrying_model, default_model_name, queued_name
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.widgets import DialogResult, Widget
@@ -21,6 +21,7 @@ from openpilot.system.ui.widgets.confirm_dialog import alert_dialog, ConfirmDial
from openpilot.system.ui.widgets.scroller_tici import Scroller
from openpilot.system.ui.widgets.toggle import ON_COLOR
from openpilot.sunnypilot.models.runners.constants import CUSTOM_MODEL_PATH
from openpilot.system.ui.sunnypilot.lib.styles import style
from openpilot.system.ui.sunnypilot.lib.utils import NoElideButtonAction, ScrollingButtonAction
from openpilot.system.ui.sunnypilot.widgets.list_view import ListItemSP, toggle_item_sp, option_item_sp
@@ -39,9 +40,6 @@ class ModelsLayout(Widget):
self._selection_source = None
self._downloading = False
self._verifying = False
self._clearing = False
self._refreshing = False
self._refresh_start: float | None = None
self._last_note = None
self.last_cache_calc_time = 0
@@ -69,14 +67,15 @@ class ModelsLayout(Widget):
self.download_item = download_status_item(lambda: tr("Download") if self._downloading else tr("Model Status"))
self.refresh_item = button_item(tr("Refresh Model List"),
lambda: tr("FETCHING...") if self._refreshing else tr("REFRESH"), "",
self._refresh_models)
self.refresh_item = button_item(tr("Refresh Model List"), tr("REFRESH"), "",
lambda: (ui_state.params.put("ModelManager_LastSyncTime", 0),
ui_state.params.put("ModelManager_LastSyncTime_Chestnut", 0),
gui_app.push_widget(alert_dialog(tr("Fetching Latest Models")))))
self.clear_cache_item = ListItemSP(
title=tr("Clear Model Cache"),
description="",
action_item=NoElideButtonAction(lambda: tr("CLEARING...") if self._clearing else tr("CLEAR")),
action_item=NoElideButtonAction(tr("CLEAR")),
callback=self._clear_cache
)
@@ -116,38 +115,39 @@ class ModelsLayout(Widget):
if lagd_toggle:
desc += f"<br>{tr('Live Steer Delay:')} {ui_state.sm['lateralDelay'].lateralDelay:.3f} s"
elif ui_state.CP is not None:
sw = float(ui_state.params.get("LagdToggleDelay", return_default=True))
sw = float(ui_state.params.get("LagdToggleDelay", "0.2"))
cp = ui_state.CP.steerActuatorDelay
desc += f"<br>{tr('Actuator Delay:')} {cp:.2f} s + {tr('Software Delay:')} {sw:.2f} s = {tr('Total Delay:')} {cp + sw:.2f} s"
self.lagd_toggle.set_description(desc)
@staticmethod
def calculate_cache_size():
return model_cache_size_mb()
cache_size = 0.0
if os.path.exists(CUSTOM_MODEL_PATH):
for file in os.listdir(CUSTOM_MODEL_PATH):
try:
cache_size += os.path.getsize(os.path.join(CUSTOM_MODEL_PATH, file))
except OSError:
continue
return cache_size / (1024**2)
def _clear_cache(self):
def _callback(response):
if response == DialogResult.CONFIRM:
ui_state.params.put_bool("ModelManager_ClearCache", True)
self.clear_cache_item.action_item.set_value(f"{self.calculate_cache_size():.2f} MB")
dialog = ConfirmDialog(tr("This will delete ALL downloaded models from the cache except the currently active model. Are you sure?"),
tr("Clear Cache"), callback=_callback)
gui_app.push_widget(dialog)
def _refresh_models(self):
refresh_model_list()
self._refresh_start = time.monotonic()
def _handle_bundle_download_progress(self):
self.cancel_download_item.set_visible(False)
self._downloading = False
self._verifying = False
self.download_item.set_visible(True)
self._clearing = ui_state.params.get_bool("ModelManager_ClearCache")
if self._clearing:
self.last_cache_calc_time = 0.0 # refresh the size as soon as clearing finishes
elif (current_time := time.monotonic()) - self.last_cache_calc_time > 0.5:
if (current_time := time.monotonic()) - self.last_cache_calc_time > 0.5:
self.last_cache_calc_time = current_time
self.clear_cache_item.action_item.set_value(f"{self.calculate_cache_size():.2f} MB")
@@ -345,13 +345,6 @@ class ModelsLayout(Widget):
self.big_model_item.action_item.set_enabled(offroad)
self.small_model_item.set_description("" if offroad else tr("Only available when vehicle is off, or always offroad mode is on"))
# manager is offroad-only, so an onroad clear would never be serviced
self.clear_cache_item.action_item.set_enabled(offroad and not self._downloading and not self._clearing)
# manager is offroad-only, so a refresh queued onroad would never be serviced
self._refreshing = refresh_in_progress(self._refresh_start)
self.refresh_item.action_item.set_enabled(offroad and not self._downloading and not self._refreshing)
def _render(self, rect):
self._scroller.render(rect)
@@ -4,18 +4,15 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
import time
import pyray as rl
from openpilot.cereal import custom
from openpilot.selfdrive.ui.mici.widgets.dialog import BigConfirmationDialog, BigDialog
from openpilot.selfdrive.ui.mici.widgets.dialog import BigDialog
from openpilot.sunnypilot.models.helpers import ACTIVE_BUNDLE_KEYS, get_selected_bundle
from openpilot.selfdrive.ui.mici.widgets.button import BigButton
from openpilot.selfdrive.ui.ui_state import ui_state, device
from openpilot.selfdrive.ui.sunnypilot.model_info import (active_source, big_model_state, bundles_for_source, carrying_model,
default_model_name, model_cache_size_mb, model_info, queued_name,
refresh_in_progress, refresh_model_list)
default_model_name, model_info, queued_name)
from openpilot.system.ui.lib.application import FontWeight, gui_app
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets import Widget
@@ -84,18 +81,10 @@ class ModelsLayoutMici(NavScroller):
self.select_model_btn = BigButton(tr("select model"))
self.select_model_btn.set_click_callback(self._show_folders)
self.refresh_btn = BigButton(tr("refresh models"))
self.refresh_btn.set_click_callback(self._refresh_models)
self._refresh_start: float | None = None
self.cancel_download_btn = BigButton(tr("cancel download"))
self.cancel_download_btn.set_click_callback(lambda: ui_state.params.remove("ModelManager_DownloadRef"))
self.clear_cache_btn = BigButton(tr("clear cache"), value=f"{model_cache_size_mb():.1f} MB")
self.clear_cache_btn.set_click_callback(self._confirm_clear_cache)
self._cache_size_time = 0.0
self.main_items = [self.current_model_info, self.select_model_btn, self.cancel_download_btn, self.refresh_btn, self.clear_cache_btn]
self.main_items = [self.current_model_info, self.select_model_btn, self.cancel_download_btn]
self._scroller.add_widgets(self.main_items)
@property
@@ -173,15 +162,6 @@ class ModelsLayoutMici(NavScroller):
ui_state.params.remove(ACTIVE_BUNDLE_KEYS[source])
self._pop_to_main()
def _confirm_clear_cache(self):
icon = gui_app.texture("icons_mici/settings/network/new/trash.png", 54, 64)
gui_app.push_widget(BigConfirmationDialog(f"{tr('slide to')}\n{tr('clear cache')}", icon,
lambda: ui_state.params.put_bool("ModelManager_ClearCache", True), red=True))
def _refresh_models(self):
refresh_model_list()
self._refresh_start = time.monotonic()
def _select_folder(self, folder_name):
source = self._selection_source
if source is None: # folders are only reachable after picking a hardware
@@ -225,21 +205,6 @@ class ModelsLayoutMici(NavScroller):
device.set_override_interactive_timeout(None)
self._was_downloading = is_downloading
# manager is offroad-only, so an onroad clear would never be serviced
clearing = ui_state.params.get_bool("ModelManager_ClearCache")
self.clear_cache_btn.set_enabled(ui_state.is_offroad() and not is_downloading and not clearing)
if clearing:
self.clear_cache_btn.set_value(tr("clearing..."))
self._cache_size_time = 0.0 # refresh the size as soon as clearing finishes
elif (now := time.monotonic()) - self._cache_size_time > 0.5:
self._cache_size_time = now
self.clear_cache_btn.set_value(f"{model_cache_size_mb():.1f} MB")
# manager is offroad-only, so a refresh queued onroad would never be serviced
refreshing = refresh_in_progress(self._refresh_start)
self.refresh_btn.set_enabled(ui_state.is_offroad() and not is_downloading and not refreshing)
self.refresh_btn.set_value(tr("fetching...") if refreshing else "")
self.current_model_info.current_model_header.set_text(tr("active model"))
active_text, info_header, info_text = _model_info()
self.current_model_info.current_model_text.set_text(active_text)
@@ -4,28 +4,12 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
import contextlib
import os
import time
from openpilot.common.hardware.hw import Paths
from openpilot.selfdrive.ui.ui_state import ui_state, ChestnutState
from openpilot.sunnypilot.models.fetcher import get_cached_bundles
from openpilot.sunnypilot.models.helpers import get_active_source, get_selected_bundle, resolve_bundle_by_ref
from openpilot.sunnypilot.models.model_name import DEFAULT_BIG_MODEL, DEFAULT_MODEL
def model_cache_size_mb() -> float:
"""Bytes on disk under the model cache directory, in MB."""
model_root = Paths.model_root()
total = 0
if os.path.isdir(model_root):
for name in os.listdir(model_root):
with contextlib.suppress(OSError):
total += os.path.getsize(os.path.join(model_root, name))
return total / (1024 ** 2)
def active_source() -> str:
return get_active_source(chestnut=ui_state.chestnut_present,
chestnut_active=ui_state.chestnut_active, chestnut_loading=ui_state.chestnut_loading,
@@ -99,22 +83,3 @@ def model_info() -> tuple[str, str, str]:
active_name = active_bundle.displayName if active_bundle else default_model_name(source)
other_name = other_bundle.displayName if other_bundle else default_model_name(other)
return source, active_name, other_name
# mirrors the manager's ModelCache keys; the manager restamps them on a successful fetch
MODEL_SYNC_KEYS = ("ModelManager_LastSyncTime", "ModelManager_LastSyncTime_Chestnut")
MODEL_SYNC_TIMEOUT = 20.0
def refresh_model_list() -> None:
# zeroing the sync keys makes the manager refetch each manifest on its next tick
for key in MODEL_SYNC_KEYS:
ui_state.params.put(key, 0)
def refresh_in_progress(started_at: float | None) -> bool:
"""Whether a user refresh is still outstanding. A failed fetch never restamps the
sync keys, so the spinner is bounded by MODEL_SYNC_TIMEOUT rather than sticking."""
if started_at is None or time.monotonic() - started_at > MODEL_SYNC_TIMEOUT:
return False
return not all(ui_state.params.get(key) for key in MODEL_SYNC_KEYS)
@@ -15,19 +15,11 @@ class CameraOffsetHelper:
self.actual_camera_offset = 0.0
@staticmethod
def get_v_horizon(intrinsics, rpy_calib):
def apply_camera_offset(model_transform, intrinsics, height, offset_param):
cy = intrinsics[1, 2]
if len(rpy_calib) == 3 and np.isfinite(rpy_calib).all():
fy = intrinsics[1, 1]
pitch = rpy_calib[1]
return float(cy - fy * np.tan(pitch))
return float(cy)
@staticmethod
def apply_camera_offset(model_transform, height, offset_param, v_horizon):
shear = np.eye(3, dtype=np.float32)
shear[0, 1] = offset_param / height
shear[0, 2] = -offset_param / height * v_horizon
shear[0, 2] = -offset_param / height * cy
model_transform = (shear @ model_transform).astype(np.float32)
return model_transform
@@ -38,13 +30,10 @@ class CameraOffsetHelper:
self.actual_camera_offset = (0.9 * self.actual_camera_offset) + (0.1 * self.camera_offset)
dc = DEVICE_CAMERAS[(str(sm['deviceState'].deviceType), str(sm['narrowRoadCameraState'].sensor))]
height = sm["extrinsicsCalibration"].height[0] if sm['extrinsicsCalibration'].height else 1.22
rpy_calib = sm['extrinsicsCalibration'].rpyCalib
intrinsics_main = dc.wide_road.intrinsics if main_wide_camera else dc.narrow_road.intrinsics
v_horizon_main = self.get_v_horizon(intrinsics_main, rpy_calib)
model_transform_main = self.apply_camera_offset(model_transform_main, height, self.actual_camera_offset, v_horizon_main)
model_transform_main = self.apply_camera_offset(model_transform_main, intrinsics_main, height, self.actual_camera_offset)
intrinsics_extra = dc.wide_road.intrinsics
v_horizon_extra = self.get_v_horizon(intrinsics_extra, rpy_calib)
model_transform_extra = self.apply_camera_offset(model_transform_extra, height, self.actual_camera_offset, v_horizon_extra)
model_transform_extra = self.apply_camera_offset(model_transform_extra, intrinsics_extra, height, self.actual_camera_offset)
return model_transform_main, model_transform_extra
-100
View File
@@ -1,100 +0,0 @@
"""
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
import io
import struct
import pickle
import inspect
import importlib
import enum
def _pad_args(func, args, kwargs):
try:
sig = inspect.signature(func)
except Exception:
return args, kwargs
params = list(sig.parameters.values())
if inspect.isfunction(func) and params and params[0].name in ('cls', 'self'):
params = params[1:]
new_args = list(args)
has_varargs = any(p.kind == inspect.Parameter.VAR_POSITIONAL for p in params)
if len(new_args) > len(params) and not has_varargs:
new_args = new_args[:len(params)]
for i in range(len(new_args), len(params)):
param = params[i]
if param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD):
continue
val = param.default if param.default is not inspect.Parameter.empty else None
new_args.append(val)
return new_args, kwargs
def _enum_factory(enum_class):
def factory(*args, **kwargs):
try:
return enum_class(*args, **kwargs)
# OptOps and UOp objects in the .pkl are left over from the compilation phase,
# reassignment does nothing because they aren't tied to the execution graph
# It never executes or evaluates the UOp nodes again.
except ValueError:
return list(enum_class)[0]
factory.__name__ = enum_class.__name__
factory.__module__ = enum_class.__module__
return factory
def _dynamic_factory(real_class):
if isinstance(real_class, type) and issubclass(real_class, enum.Enum):
return _enum_factory(real_class)
def factory(*args, **kwargs):
try:
return real_class(*args, **kwargs)
except TypeError:
new_args, new_kwargs = _pad_args(real_class, args, kwargs)
return real_class(*new_args, **new_kwargs)
class DynamicMeta(type(real_class)):
def __call__(cls, *args, **kwargs):
return factory(*args, **kwargs)
class DynamicProxy(real_class, metaclass=DynamicMeta):
__slots__ = ()
def __new__(cls, *args, **kwargs):
return factory(*args, **kwargs)
DynamicProxy.__name__ = real_class.__name__
DynamicProxy.__module__ = real_class.__module__
return DynamicProxy
class DynamicTinygradUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module == "tinygrad.ops":
try:
importlib.import_module("tinygrad.uops")
module = "tinygrad.uops"
except ImportError:
pass
real_class = getattr(importlib.import_module(module), name)
if module.startswith("tinygrad"):
return _dynamic_factory(real_class)
return real_class
def load_oob(f):
opcodes = f.read(struct.unpack('<q', f.read(8))[0])
def buffers():
while (h := f.read(8)):
pb = pickle.PickleBuffer(bytearray(struct.unpack('<q', h)[0]))
f.readinto(pb)
yield pb
return DynamicTinygradUnpickler(io.BytesIO(opcodes), buffers=buffers()).load()
+1 -3
View File
@@ -17,7 +17,7 @@ from tinygrad.tensor import Tensor
import openpilot.cereal.messaging as messaging
from openpilot.common.hardware import COMMA_HARDWARE
from openpilot.selfdrive.modeld.helpers import chestnut_present
from openpilot.selfdrive.modeld.helpers import chestnut_present, load_oob
from openpilot.cereal import log
from opendbc.car.structs import car
from openpilot.cereal.services import SERVICE_LIST
@@ -52,7 +52,6 @@ from openpilot.sunnypilot.modeld_v2.compile_modeld import (derive_frame_skip, ma
WARP_INPUTS, POLICY_INPUTS)
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
from openpilot.sunnypilot.modeld_v2.modeld_base import ModelStateBase
from openpilot.sunnypilot.modeld_v2.helpers import load_oob
from openpilot.sunnypilot.models.helpers import get_active_bundle
from openpilot.sunnypilot.selfdrive.controls.lib.relc import RoadEdgeLaneChangeController
@@ -552,7 +551,6 @@ def main(demo=False):
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob, left_edge, right_edge)
modelv2_send.modelV2.meta.laneChangeState = DH.lane_change_state
modelv2_send.modelV2.meta.laneChangeDirection = DH.lane_change_direction
mdv2sp_send.valid = modelv2_send.valid
mdv2sp_send.modelDataV2SP.laneTurnDirection = DH.lane_turn_direction
drivingdata_send.drivingModelData.meta.laneChangeState = DH.lane_change_state
drivingdata_send.drivingModelData.meta.laneChangeDirection = DH.lane_change_direction
@@ -6,9 +6,8 @@ See the LICENSE.md file in the root directory for more details.
"""
import numpy as np
from openpilot.common.transformations.camera import DEVICE_CAMERAS, view_frame_from_device_frame
from openpilot.common.transformations.camera import DEVICE_CAMERAS
from openpilot.common.transformations.model import get_warp_matrix
from openpilot.common.transformations.orientation import rot_from_euler
from openpilot.sunnypilot.modeld_v2.camera_offset_helper import CameraOffsetHelper
from openpilot.common.test import OpenpilotTestCase
@@ -47,50 +46,29 @@ class TestCameraOffset(OpenpilotTestCase):
self.camera_offset.update(main_transform, extra_transform, sm, False)
np.testing.assert_almost_equal(self.camera_offset.actual_camera_offset, 0.038)
def test_apply_camera_offset(self):
def test_camera_offset_(self):
intrinsics = self.dc.narrow_road.intrinsics
v_horizon = CameraOffsetHelper.get_v_horizon(intrinsics, []) # pitch = 0 fallback: v_horizon == cy
transform = np.eye(3, dtype=np.float32)
height = 1.22
offset = 0.1
cy = intrinsics[1, 2]
expected_shear = np.eye(3, dtype=np.float32)
expected_shear[0, 1] = offset / height
expected_shear[0, 2] = -offset / height * v_horizon
expected_shear[0, 2] = -offset / height * cy
result = CameraOffsetHelper.apply_camera_offset(transform, height, offset, v_horizon)
result = CameraOffsetHelper.apply_camera_offset(transform, intrinsics, height, offset)
np.testing.assert_array_almost_equal(result, expected_shear)
def test_v_horizon_empty_rpy(self):
intrinsics = self.dc.narrow_road.intrinsics
v_horizon = CameraOffsetHelper.get_v_horizon(intrinsics, [])
np.testing.assert_almost_equal(v_horizon, intrinsics[1, 2])
def test_v_horizon_projection(self):
intrinsics = self.dc.narrow_road.intrinsics
f, cy = intrinsics[1, 1], intrinsics[1, 2]
for pitch_deg in [6.0, -6.0, 0.0]:
rpy = [0.0, np.radians(pitch_deg), 0.0]
d_dev = rot_from_euler(rpy) @ np.array([1.0, 0.0, 0.0])
view = view_frame_from_device_frame @ d_dev
expected = cy + f * view[1] / view[2]
v_horizon = CameraOffsetHelper.get_v_horizon(intrinsics, rpy)
np.testing.assert_almost_equal(v_horizon, expected, decimal=4)
def test_update(self):
height = 1.2
pitch = np.radians(-8.0)
sm = MockStruct(
deviceState=MockStruct(deviceType='mici'),
narrowRoadCameraState=MockStruct(sensor='os04c10'),
extrinsicsCalibration=MockStruct(rpyCalib=[0.0, pitch, 0.0], height=[height])
extrinsicsCalibration=MockStruct(rpyCalib=[0.0, 0.0, 0.0], height=[1.22])
)
intrinsics_main = self.dc.narrow_road.intrinsics
intrinsics_extra = self.dc.wide_road.intrinsics
device_from_calib_euler = np.array(sm['extrinsicsCalibration'].rpyCalib, dtype=np.float32)
device_from_calib_euler = np.array([0.0, 0.0, 0.0], dtype=np.float32)
main_transform = get_warp_matrix(device_from_calib_euler, intrinsics_main, False).astype(np.float32)
extra_transform = get_warp_matrix(device_from_calib_euler, intrinsics_extra, True).astype(np.float32)
@@ -103,13 +81,5 @@ class TestCameraOffset(OpenpilotTestCase):
main_out, extra_out = self.camera_offset.update(main_transform, extra_transform, sm, False)
assert not np.array_equal(main_out, main_transform)
assert not np.array_equal(extra_out, extra_transform)
# settle the low-pass filter
for _ in range(100):
main_out, extra_out = self.camera_offset.update(main_transform, extra_transform, sm, False)
# undo main_transform dot product to get shear matrix
shear = main_out @ np.linalg.inv(main_transform)
expected_v_horizon = intrinsics_main[1, 2] - intrinsics_main[1, 1] * np.tan(pitch)
np.testing.assert_almost_equal(shear[0, 1], self.camera_offset.actual_camera_offset / height, decimal=4)
np.testing.assert_almost_equal(shear[0, 2], -self.camera_offset.actual_camera_offset / height * expected_v_horizon, decimal=4)
assert main_out[0, 1] != 0.0
assert main_out[0, 2] != 0.0
@@ -1,43 +0,0 @@
"""
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
import os
import unittest
from unittest.mock import patch
from openpilot.common.file_chunker import open_file_chunked
from openpilot.sunnypilot.modeld_v2.helpers import load_oob
from tinygrad.device import Device
class TestLegacyModels(unittest.TestCase):
def test_legacy_model_load(self):
base_name = os.environ.get("MODEL_BASE_NAME")
if not base_name:
raise unittest.SkipTest("MODEL_BASE_NAME env var not set, skipping integration test.")
chunk_dir = os.environ.get("MODEL_CHUNK_DIR", "/tmp/model_chunks")
base_path = os.path.join(chunk_dir, base_name)
try:
f = open_file_chunked(base_path)
except Exception as error:
self.fail(f"Failed to open chunked file {base_path}: {error}")
self.addCleanup(f.close)
real_getitem = Device.__class__.__getitem__
def safe_getitem(device_self, ix):
if ix == "QCOM" and not os.path.exists("/dev/kgsl-3d0"):
return real_getitem(device_self, "CPU")
if ix == "AMD" and not os.path.exists("/dev/kfd"):
return real_getitem(device_self, "CPU")
return real_getitem(device_self, ix)
with patch.object(Device.__class__, "__getitem__", safe_getitem):
obj = load_oob(f)
assert isinstance(obj, dict), "Parsed object is not a dictionary"
assert "metadata" in obj, "Metadata key is missing"
@@ -0,0 +1,24 @@
import requests
from openpilot.sunnypilot.models.tinygrad_ref import get_tinygrad_ref
from openpilot.sunnypilot.models.fetcher import ModelFetcher
from openpilot.common.test import OpenpilotTestCase
def fetch_tinygrad_ref():
response = requests.get(ModelFetcher.MODEL_URL, timeout=10)
response.raise_for_status()
json_data = response.json()
return json_data.get("tinygrad_ref")
class TestTinygradRef(OpenpilotTestCase):
def test_tinygrad_ref(self):
current_ref = get_tinygrad_ref()
remote_ref = fetch_tinygrad_ref()
assert remote_ref == current_ref, (
f"""tinygrad_repo ref does not match remote tinygrad_ref of current compiled driving models json.
Current: {current_ref}
Remote: {remote_ref}
Please run build-all workflow to update models."""
)
print("tinygrad_repo ref matches current compiled driving models json ref.")