Compare commits

..

61 Commits

Author SHA1 Message Date
dragonpilot c4955787a3 version: dragonpilot development version for EON/C2
date: 2024-04-10T19:21:57
commit: 8f2124beef4031cf1ad7a123b5fe1eb4985aab4f
2024-04-10 19:22:16 +08:00
dragonpilot c8f7fdc276 version: dragonpilot development version for EON/C2
date: 2024-03-19T09:33:13
commit: c2e5af0b4896bd72cb2e8063f8481a55bb83c583
2024-03-19 09:33:33 +00:00
dragonpilot 994dfb7fd2 version: dragonpilot development version for EON/C2
date: 2024-03-01T19:32:36
commit: dcca316946674ab874ecff36f9e93184f8b876ce
2024-03-01 19:32:49 +08:00
dragonpilot 94d8d7458d version: dragonpilot development version for EON/C2
date: 2024-03-01T18:48:48
commit: f1bee6b8e2fc94eee0ab1b1db78e42a9c8e2f4aa
2024-03-01 18:49:06 +08:00
eFini 22af1becc7 Update eon_installer.sh 2024-02-29 16:42:12 +08:00
eFini a7808e2ee4 Update eon_installer.sh 2024-02-29 16:33:17 +08:00
eFini 61af96ecaa Update eon_installer.sh 2024-02-29 16:30:16 +08:00
eFini e3c646fd0e Create eon_installer.sh 2024-02-29 16:26:53 +08:00
dragonpilot 3c195b3af7 version: dragonpilot development version for EON/C2
date: 2024-02-28T16:32:56
commit: af29cad3e29308622bbbcec7445c15e5433961ec
2024-02-28 16:33:09 +08:00
dragonpilot be05ffa5bf version: dragonpilot development version for EON/C2
date: 2024-02-26T20:43:48
commit: 61592bc9e895361b44b62dd805c59bf41d486183
2024-02-26 20:43:59 +08:00
Vehicle Researcher 578d38b5f9 lp-dp 2023-12-14T02:06:09 for EON/C2
version: lp-dp v0.9.5 for EON/C2
date: 2023-12-14T02:06:09
commit: be7270819b5cdeda4010d5276cc186c94189c43c
2023-12-14 02:06:23 +00:00
eFini de4254deb3 Update long_mpc.py 2023-11-26 12:23:24 +08:00
Vehicle Researcher e7df1b8218 lp-dp 2023-11-23T06:28:40 for EON/C2
version: lp-dp v0.9.5 for EON/C2
date: 2023-11-23T06:28:40
commit: b6d75bf11c56c575a151c3cf0fa79f55e0eb4368
2023-11-23 06:28:43 +00:00
Vehicle Researcher f7c8e38426 lp-dp 2023-09-19T10:02:18 for EON/C2
version: lp-dp v0.9.5 for EON/C2
date: 2023-09-19T10:02:18
commit: ec01d2fd7b3d812c067da83ea53fef0bbf34be25
2023-09-19 10:02:28 +00:00
Vehicle Researcher 2c9fa154d6 lp-dp 2023-09-18T04:13:07 for EON/C2
version: lp-dp v0.9.5 for EON/C2
date: 2023-09-18T04:13:07
commit: 5d47b8da43a2550bbebcfbb6636f1296b5433e07
2023-09-18 04:13:27 +00:00
Vehicle Researcher 634aa84919 lp-dp 2023-09-13T13:36:48 for EON/C2
version: lp-dp v0.9.5 for EON/C2
date: 2023-09-13T13:36:48
commit: 1d59b81c40b93f37d4a341c5d35b1c3cd293543d
2023-09-13 13:36:57 +08:00
Vehicle Researcher 9ca1ac0042 lp-dp 2023-08-02T01:57:46 for EON/C2
version: lp-dp v0.9.4 for EON/C2
date: 2023-08-02T01:57:46
commit: 63c51d4b134e443b1ffa59dfe0fc2d50d5e0f446
2023-08-02 01:57:49 +00:00
eFini 0ffb1567bc Merge pull request #193 from jcwlim/lp-dp-beta2
fix indentation error
2023-07-19 13:23:59 +08:00
jcwlim 33419d0516 fix indentation error 2023-07-19 11:14:00 +08:00
eFini 16f5852102 Update controlsd.py 2023-07-19 10:42:28 +08:00
eFini 6527c3656f Update controlsd.py 2023-07-18 13:45:01 +08:00
Vehicle Researcher 0fe74b2af6 lp-dp 2023-07-17T07:18:07 for EON/C2
version: lp-dp v0.9.3 for EON/C2
date: 2023-07-17T07:18:07
commit: 96f87e78722291005720e72d605b459e928f8812
2023-07-17 07:18:10 +00:00
Vehicle Researcher 939c27ad10 lp-dp 2023-07-17T07:06:11 for EON/C2
version: lp-dp v0.9.3 for EON/C2
date: 2023-07-17T07:06:11
commit: d048235d4181b72ff6a2187398580f5d75e2de1e
2023-07-17 07:06:14 +00:00
eFini 768c989952 Fixed NO_IR_CTRL issue 2023-06-13 00:14:52 +08:00
Comma Device 5cc9001bcc model clean up 2023-06-12 06:58:17 +00:00
Vehicle Researcher d3cc1e84a3 lp-dp 2023-06-12T05:58:26 for EON/C2
version: lp-dp v0.9.3 for EON/C2
date: 2023-06-12T05:58:26
commit: a6e632fddf5e5e22867c0fd549b4e701cbc35d63
2023-06-12 05:58:29 +00:00
Vehicle Researcher 3ed6e4b836 lp-dp 2023-05-25T03:24:13 for EON/C2
version: lp-dp v0.9.3 for EON/C2
date: 2023-05-25T03:24:13
commit: d2df8c66259421b8e6d660720312be443043fc14
2023-05-25 03:24:15 +00:00
Vehicle Researcher 8f67934f80 lp-dp 2023-05-25T03:10:00 for EON/C2
version: lp-dp v0.9.3 for EON/C2
date: 2023-05-25T03:10:00
commit: 409000e6091be63a423d23e7940d569fed28497e
2023-05-25 03:10:14 +00:00
Vehicle Researcher 6def7af391 lp-dp 2023-05-19T17:12:55 for EON/C2
version: lp-dp v0.9.2 for EON/C2
date: 2023-05-19T17:12:55
commit: f51617030bfd04cb754fbb720be5ec4d6a8e80fd
2023-05-19 17:12:57 +08:00
Vehicle Researcher 687f549628 lp-dp 2023-05-15T02:15:54 for EON/C2
version: lp-dp v0.9.2 for EON/C2
date: 2023-05-15T02:15:54
commit: 39446776e3af41df83540eaf68e84f8b0e2b5c9f
2023-05-15 02:16:01 +00:00
Vehicle Researcher c8440ab691 lp-dp 2023-05-09T02:32:30 for EON/C2
version: lp-dp v0.9.2 for EON/C2
date: 2023-05-09T02:32:30
commit: cb8adff9d368de2e442e1e7f4309b70a4a2013ad
2023-05-09 02:32:38 +00:00
eFini c6efa8341a Merge pull request #190 from dragonpilot-community/beta2_override
Update drive_helpers.py
2023-04-15 11:58:40 +08:00
eFini 0bb2cfda06 Update drive_helpers.py 2023-04-14 22:01:07 +08:00
eFini 4c8fe7af7e Merge pull request #189 from dragonpilot-community/eFiniLan-patch-5
Update drive_helpers.py
2023-04-14 10:46:56 +08:00
eFini a9f879e64d Update drive_helpers.py 2023-04-14 10:46:07 +08:00
Dragonpilot Team cf18a8fb09 dragonpilot 2023-04-13T02:41:11 for EON/C2
version: dragonpilot v0.9.2 beta for EON/C2
date: 2023-04-13T02:41:11
dp-dev(priv2) master commit: 4526e2dbd703c5d3e958825e64d5912ae452ab30
2023-04-13 02:41:27 +00:00
Dragonpilot Team ca1186a7bf dragonpilot 2023-04-01T09:36:15 for EON/C2
version: dragonpilot v0.9.2 beta for EON/C2
date: 2023-04-01T09:36:15
dp-dev(priv2) master commit: 29bbbec9ef69d7527f4715114749c18d4e22768c
2023-04-01 09:36:19 +00:00
eFini d244592a40 Update events.py 2023-03-31 10:58:48 +08:00
Dragonpilot Team b0e747ea3b dragonpilot 2023-03-30T08:35:14 for EON/C2
version: dragonpilot v0.9.2 beta for EON/C2
date: 2023-03-30T08:35:14
dp-dev(priv2) master commit: 42cfd61d1e0f0a69237e69d75c5b5f69e417a8c9
2023-03-30 08:35:23 +00:00
eFini c0ac87c36c Update power_monitoring.py 2023-03-30 09:01:53 +08:00
Dragonpilot Team eeb43a5107 dragonpilot 2023-03-29T09:55:29 for EON/C2
version: dragonpilot v0.9.2 beta for EON/C2
date: 2023-03-29T09:55:29
dp-dev(priv2) master commit: 7a10a5f475f257bfcaf0f300d0441aef80be52d8
2023-03-29 09:55:32 +00:00
Dragonpilot Team ea800c8f74 dragonpilot 2023-03-27T06:11:06 for EON/C2
version: dragonpilot v0.9.2 beta for EON/C2
date: 2023-03-27T06:11:06
dp-dev(priv2) master commit: 0a08aa2b73a505e11e4c98ac6c5989464b7d339f
2023-03-27 06:27:07 +00:00
Dragonpilot Team f770882b7f dragonpilot 2023-02-08T03:42:25 for EON/C2
version: dragonpilot v0.9.1 beta for EON/C2
date: 2023-02-08T03:42:25
dp-dev(priv2) master commit: 806adddf718b97255ba36d4a9dbd5f6bad383787
2023-02-08 03:42:33 +00:00
eFini 34925962d5 Update controlsd.py 2023-02-07 21:23:37 +08:00
eFini 3977b6d1ff Merge pull request #181 from dragonpilot-community/eFiniLan-patch-2
Update interface.py
2023-02-07 13:19:49 +08:00
eFini 77edcc0058 Update interface.py 2023-02-07 13:19:28 +08:00
Dragonpilot Team 8555e48fc9 dragonpilot 2023-02-07T02:56:39 for EON/C2
version: dragonpilot v0.9.1 beta for EON/C2
date: 2023-02-07T02:56:39
dp-dev(priv2) master commit: 459790d03b790e5f3a8cff18710ac4d44841a16a
2023-02-07 03:00:39 +00:00
Dragonpilot Team 1f2e3aa8b6 dragonpilot 2022-12-30T07:51:42 for EON/C2
version: dragonpilot v0.9.1 beta for EON/C2
date: 2022-12-30T07:51:42
dp-dev(priv2) master commit: 4e8e00606410c2bbe03b93fc89a91caec37d1f3a
2022-12-30 07:51:55 +00:00
Dragonpilot Team 398aeb927b dragonpilot 2022-12-23T08:15:11 for EON/C2
version: dragonpilot v0.9.1 beta for EON/C2
date: 2022-12-23T08:15:11
dp-dev(priv2) master commit: 3cc44ae87d697a5e07bfa58c4e799730bea0b63a
2022-12-23 08:26:46 +00:00
Dragonpilot Team de34fa87ee dragonpilot 2022-11-30T09:37:39 for EON/C2
version: dragonpilot v0.9.1 beta for EON/C2
date: 2022-11-30T09:37:39
dp-dev(priv2) master commit: e2204c868277f20a263c2f93e88c42999d0b0c15
2022-12-01 03:54:37 +00:00
Dragonpilot Team 1fdc1202d1 dragonpilot 2022-11-02T08:11:06 for EON/C2
version: dragonpilot v0.8.17 beta for EON/C2
date: 2022-11-02T08:11:06
dp-dev(priv2) master commit: fa5dbfe5c771a59cf8b82a9cfc26b28989824d31
2022-11-02 08:11:20 +00:00
Dragonpilot Team 4c3c884245 dragonpilot 2022-10-07T10:01:36 for EON/C2
version: dragonpilot v0.8.17 beta for EON/C2
date: 2022-10-07T10:01:36
dp-dev(priv2) master commit: 3aecc0939a714f5f572b3cbe85669ed389161870
2022-10-07 10:05:16 +00:00
Dragonpilot Team fe6459224b dragonpilot 2022-09-15T06:50:26 for EON/C2
version: dragonpilot v0.8.17 beta for EON/C2
date: 2022-09-15T06:50:26
dp-dev(priv2) master commit: 4d0dc8f4278758e1c000fbbef41ad124187335e2
2022-09-15 06:50:40 +00:00
Dragonpilot Team 30a852791f dragonpilot 2022-09-07T01:33:02 for EON/C2
version: dragonpilot v0.8.17 beta for EON/C2
date: 2022-09-07T01:33:02
dp-dev(priv2) master commit: 705261266a609f9ab22a8704a4cf2a380df5a79f
2022-09-07 01:33:08 +00:00
Dragonpilot Team 9546ca4273 dragonpilot 2022-09-06T04:35:28 for EON/C2
version: dragonpilot v0.8.17 beta for EON/C2
date: 2022-09-06T04:35:28
dp-dev(priv2) master commit: 705261266a609f9ab22a8704a4cf2a380df5a79f
2022-09-06 04:35:35 +00:00
Dragonpilot Team e55a27c37e dragonpilot 2022-09-01T09:01:29 for EON/C2
version: dragonpilot v0.8.17 beta for EON/C2
date: 2022-09-01T09:01:29
dp-dev(priv2) master commit: 1aee3e0728e47b4789623262fd595a3bccb7fe6e
2022-09-01 09:01:42 +00:00
Dragonpilot Team 99f7f6023e dragonpilot 2022-08-30T07:26:22 for EON/C2
version: dragonpilot v0.8.17 beta for EON/C2
date: 2022-08-30T07:26:22
dp-dev(priv2) master commit: 0b0eacf73b22b4ff5341143a3beb2d2d681d989b
2022-08-30 07:26:35 +00:00
Dragonpilot Team 58e0b3246f dragonpilot 2022-08-26T01:39:55 for EON/C2
version: dragonpilot v0.8.17 beta for EON/C2
date: 2022-08-26T01:39:55
dp-dev(priv2) master commit: 2cc578fbfc144eaecebf1803c8b59db45c2e9715
2022-08-26 01:40:08 +00:00
Dragonpilot Team 66006fe0e9 dragonpilot 2022-08-19T01:11:48 for EON/C2
version: dragonpilot v0.8.16 beta for EON/C2
date: 2022-08-19T01:11:48
dp-dev(priv2) master commit: 4aee191bc9d1c5099913455ff9e5fa1c3a7a7903
2022-08-19 01:19:48 +00:00
Dragonpilot Team b437663252 dragonpilot 2022-08-17T05:06:08 for EON/C2
version: dragonpilot v0.8.16 beta for EON/C2
date: 2022-08-18T23:02:08
dp-dev(priv2) master commit: 96dd81dde40b92d0686ec5761cfaaab24300b027
2022-08-19 01:01:52 +00:00
Dragonpilot Team 4d7a40310f dragonpilot 2022-08-11T09:38:43 for EON/C2
version: dragonpilot v0.8.16 beta for EON/C2
date: 2022-08-11T09:38:43
dp-dev(priv2) master commit: c6cd233f23f60e7a6055d42850bc593c0e69082e
2022-08-11 09:48:37 +00:00
4768 changed files with 191003 additions and 1291362 deletions
-18
View File
@@ -1,18 +0,0 @@
**/.git
.DS_Store
*.dylib
*.DSYM
*.d
*.pyc
*.pyo
.*.swp
.*.swo
.*.un~
*.tmp
*.o
*.o-*
*.os
*.os-*
venv/
.venv/
-11
View File
@@ -1,11 +0,0 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{py,pyx,pxd}]
charset = utf-8
indent_style = space
indent_size = 2
-47
View File
@@ -1,47 +0,0 @@
name: Bug report
description: For issues with running openpilot on your comma device
labels: ["bug"]
body:
- type: markdown
attributes:
value: >
Before creating a **bug report**, please check the following:
* If the issue likely only affects your car model or make, go back and open a **car bug report** instead.
* If the issue is related to the driving or driver monitoring models, you should open a [discussion](https://github.com/commaai/openpilot/discussions/categories/model-feedback) instead.
* Ensure you're running the latest openpilot release.
* Ensure you're using officially supported hardware. Issues running on PCs have a different issue template.
* Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue.
* Ensure you're running stock openpilot. We cannot look into bug reports from forks.
If you're unsure whether you've hit a bug, check out the #installation-help channel in the [community Discord server](https://discord.comma.ai).
- type: textarea
attributes:
label: Describe the bug
description: Also include a description of how to reproduce the bug
validations:
required: true
- type: input
id: route
attributes:
label: Provide a route where the issue occurs
description: Ensure the route is fully uploaded at https://useradmin.comma.ai. We cannot look into issues without routes, or at least a Dongle ID.
placeholder: 77611a1fac303767|2020-05-11--16-37-07
validations:
required: true
- type: input
id: version
attributes:
label: openpilot version
description: If you're not on release, provide the commit hash
placeholder: 0.8.10
validations:
required: true
- type: textarea
attributes:
label: Additional info
-14
View File
@@ -1,14 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Car bug report
url: https://github.com/commaai/opendbc/issues/new
about: For issues with a particular car make or model
- name: Join the Discord
url: https://discord.comma.ai
about: The community Discord is for both openpilot development and experience discussion
- name: Report driving behavior feedback
url: https://discord.com/channels/469524606043160576/1254834193066623017
about: Feedback for the driving and driver monitoring models goes in the #driving-feedback in Discord
- name: Community Wiki
url: https://github.com/commaai/openpilot/wiki
about: Check out our community wiki
-8
View File
@@ -1,8 +0,0 @@
---
name: Enhancement
about: For openpilot enhancement suggestions
title: ''
labels: 'enhancement'
assignees: ''
---
-42
View File
@@ -1,42 +0,0 @@
name: PC bug report
description: For issues with running openpilot on PC
labels: ["PC"]
body:
- type: markdown
attributes:
value: >
Before creating a **bug report**, please check the following:
* Ensure you're running the latest openpilot release.
* Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue.
* Ensure you're running stock openpilot. We cannot look into bug reports from forks.
If you're unsure whether you've hit a bug, check out the #installation-help channel in the [community Discord server](https://discord.comma.ai).
- type: textarea
attributes:
label: Describe the bug
description: Also include a description of how to reproduce the bug
validations:
required: true
- type: input
id: os-version
attributes:
label: OS Version
placeholder: Ubuntu 24.04
validations:
required: true
- type: input
id: version
attributes:
label: openpilot version or commit
placeholder: bd36f2ec8d3559909678eff2690c10a520938367
validations:
required: false
- type: textarea
attributes:
label: Additional info
-27
View File
@@ -1,27 +0,0 @@
CI / testing:
- changed-files:
- any-glob-to-all-files: "{.github/**,**/test_*,**/test/**,Jenkinsfile}"
car:
- changed-files:
- any-glob-to-all-files: '{selfdrive/car/**,opendbc_repo}'
simulation:
- changed-files:
- any-glob-to-all-files: 'tools/sim/**'
ui:
- changed-files:
- any-glob-to-all-files: '{selfdrive/assets/**,selfdrive/ui/**,system/ui/**}'
tools:
- changed-files:
- any-glob-to-all-files: 'tools/**'
multilanguage:
- changed-files:
- any-glob-to-all-files: 'selfdrive/ui/translations/**'
autonomy:
- changed-files:
- any-glob-to-all-files: "{selfdrive/modeld/models/**,selfdrive/test/process_replay/model_replay_ref_commit}"
-68
View File
@@ -1,68 +0,0 @@
<!-- Please copy and paste the relevant template -->
<!--- ***** Template: Fingerprint *****
**Car**
Which car (make, model, year) this fingerprint is for
**Route**
A route with the fingerprint
-->
<!--- ***** Template: Car 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.
**Route**
Route: [a route with the bug fix]
-->
<!--- ***** 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 CAR 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.
**Verification**
Explain how you tested the refactor for regressions.
-->
+44 -36
View File
@@ -1,6 +1,5 @@
venv/
.venv/
.ci_cache
.env
.clang-format
.DS_Store
@@ -10,13 +9,11 @@ venv/
.overlay_init
.overlay_consistent
.sconsign.dblite
.vscode*
model2.png
a.out
.hypothesis
.cache/
/docs_site/
*.mp4
*.dylib
*.DSYM
*.d
@@ -36,22 +33,36 @@ a.out
*.class
*.pyxbldc
*.vcd
*.mo
*_pyx.cpp
*.stats
*.qm
config.json
clcache
compile_commands.json
compare_runtime*.html
selfdrive/pandad/pandad
cereal/services.h
cereal/gen
cereal/messaging/bridge
selfdrive/ui/translations/tmp
persist
board/obj/
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/test/longitudinal_maneuvers/out
selfdrive/car/tests/cars_dump
system/camerad/camerad
system/camerad/test/ae_gray_test
selfdrive/modeld/_modeld
selfdrive/modeld/_navmodeld
selfdrive/modeld/_dmonitoringmodeld
/src/
one
notebooks
xx
yy
hyperthneed
panda_jungle
provisioning
.coverage*
coverage.xml
@@ -64,11 +75,10 @@ flycheck_*
cppcheck_report.txt
comma*.sh
selfdrive/modeld/models/*.pkl
selfdrive/modeld/thneed/compile
selfdrive/modeld/models/*.thneed
# openpilot log files
*.bz2
*.zst
build/
@@ -77,24 +87,22 @@ build/
poetry.toml
Pipfile
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# rick - these are generated during compilation.
selfdrive/camerad/camerad
selfdrive/golden/
selfdrive/hybrid_modeld/_dmonitoringmodeld
selfdrive/hybrid_modeld/_modeld
selfdrive/hybrid_modeld/models/supercombo.thneed
selfdrive/hybrid_modeld/models/supercombo_badweights.thneed
selfdrive/hybrid_modeld/thneed/compile
selfdrive/loggerd/bootlog
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# rick - keep panda_tici standalone
panda_tici/
# 0813 models
selfdrive/legacy_modeld/_modeld
selfdrive/legacy_modeld/models/supercombo.thneed
selfdrive/legacy_modeld/_dmonitoringmodeld
selfdrive/legacy_modeld/models/supercombo_badweights.thneed
selfdrive/legacy_modeld/thneed/compile
third_party/acados/lib
# lang files
*.po~
-11
View File
@@ -1,11 +0,0 @@
{
"recommendations": [
"ms-python.python",
"ms-vscode.cpptools",
"elagil.pre-commit-helper",
"charliermarsh.ruff",
"JamiTech.simply-blame",
"k--kato.intellij-idea-keybindings",
"trinm1709.dracula-theme-from-intellij"
]
}
-85
View File
@@ -1,85 +0,0 @@
{
"version": "0.2.0",
"inputs": [
{
"id": "python_process",
"type": "pickString",
"description": "Select the process to debug",
"options": [
"selfdrive/controls/controlsd.py",
"system/timed/timed.py",
"tools/sim/run_bridge.py"
]
},
{
"id": "cpp_process",
"type": "pickString",
"description": "Select the process to debug",
"options": [
"selfdrive/ui/ui"
]
},
{
"id": "args",
"description": "Arguments to pass to the process",
"type": "promptString"
},
{
"id": "replayArg",
"type": "promptString",
"description": "Enter route or segment to replay."
}
],
"configurations": [
{
"name": "Python: openpilot Process",
"type": "debugpy",
"request": "launch",
"program": "${input:python_process}",
"console": "integratedTerminal",
"justMyCode": true,
"args": "${input:args}"
},
{
"name": "C++: openpilot Process",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/${input:cpp_process}",
"cwd": "${workspaceFolder}"
},
{
"name": "Attach LLDB to Replay drive",
"type": "lldb",
"request": "attach",
"pid": "${command:pickMyProcess}",
"initCommands": [
"script import time; time.sleep(3)"
]
},
{
"name": "Replay drive",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/opendbc/safety/tests/safety_replay/replay_drive.py",
"args": [
"${input:replayArg}"
],
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"subProcess": true,
"stopOnEntry": false
}
],
"compounds": [
{
"name": "Replay drive + Safety LLDB",
"configurations": [
"Replay drive",
"Attach LLDB to Replay drive"
]
}
]
}
-41
View File
@@ -1,41 +0,0 @@
{
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.renderWhitespace": "trailing",
"files.trimTrailingWhitespace": true,
"terminal.integrated.defaultProfile.linux": "dragonpilot",
"terminal.integrated.profiles.linux": {
"dragonpilot": {
"path": "bash",
"args": ["-c", "distrobox enter dp"]
}
},
"search.exclude": {
"**/.git": true,
"**/.venv": true,
"**/__pycache__": true,
"msgq_repo/": true,
"rednose/": true,
"rednose_repo/": true,
"openpilot/": true,
"teleoprtc_repo/": true,
"tinygrad/": true,
"tinygrad_repo/": true
},
"files.exclude": {
"**/.git": true,
"**/.venv": true,
"**/__pycache__": true
},
"python.analysis.exclude": [
"**/.git",
"**/.venv",
"**/__pycache__",
// exclude directories that should be using the symlinked version
"common/**",
"selfdrive/**",
"system/**",
"third_party/**",
"tools/**",
]
}
-140
View File
@@ -1,140 +0,0 @@
# ALKA (Always-on Lane Keeping Assist) Design v3
## Overview
ALKA enables lateral control (steering) when ACC Main is ON, without requiring cruise to be engaged. This allows lane keeping assist to function independently of longitudinal control.
**Simplified Behavior (v3):**
- All brands use direct tracking: `lkas_on = acc_main_on`
- No button/toggle tracking (removed TJA, LKAS button, LKAS HUD)
- ACC Main ON = ALKA enabled, ACC Main OFF = ALKA disabled
---
## Per-Brand Summary
| Brand | Status | ACC Main Source | Notes |
|-------|--------|-----------------|-------|
| Body | Disabled | - | No steering capability |
| Chrysler | Disabled | - | Needs special handling |
| Ford | Enabled | EngBrakeData (0x165) CcStat | |
| GM | Disabled | - | No ACC Main signal |
| Honda Nidec | Enabled | SCM_FEEDBACK (0x326) MAIN_ON | |
| Honda Bosch | Enabled | SCM_FEEDBACK (0x326) MAIN_ON | |
| Hyundai | Enabled | SCC11 (0x420) bit 0 | |
| Hyundai CAN-FD | Enabled | SCC_CONTROL (0x1A0) bit 66 | |
| Hyundai Legacy | Enabled | SCC11 (0x420) bit 0 | |
| Mazda | Enabled | CRZ_CTRL (0x21C) bit 17 | |
| Nissan | Enabled | CRUISE_THROTTLE (0x239) bit 17 | |
| PSA | Disabled | - | Not implemented |
| Rivian | Disabled | - | Different architecture |
| Subaru | Enabled | CruiseControl (0x240) bit 40 | |
| Subaru Preglobal | Enabled | CruiseControl (0x144) bit 48 | |
| Tesla | Disabled | - | Different architecture |
| Toyota | Enabled | PCM_CRUISE_2 (0x1D3) bit 15 | |
| Toyota (UNSUPPORTED_DSU) | Enabled | DSU_CRUISE (0x365) bit 0 | |
| VW MQB | Enabled | TSK_06 TSK_Status (>=2) | |
| VW PQ | Enabled | Motor_5 (0x480) bit 50 (long) | |
---
## Permission Model
Lateral control requires checks at both layers. Normal path uses `controls_allowed`, ALKA path uses additional checks.
| Check | Panda | openpilot | Notes |
|-------|:-----:|:---------:|-------|
| **Normal Path** |
| `controls_allowed` (cruise engaged) | ✓ | ✓ | Either this OR ALKA path |
| **ALKA Path** |
| `alka_allowed` (brand supports) | ✓ | ✓ | Set per brand in safety init |
| `ALT_EXP_ALKA` (user enabled) | ✓ | ✓ | alternativeExperience flag |
| `lkas_on` (ACC Main ON) | ✓ | ✓ | Tracked via CAN messages |
| `vehicle_moving` / `!standstill` | ✓ | ✓ | |
| **openpilot Additional** |
| `gear_ok` (not P/N/R) | ✗ | ✓ | Python layer only |
| `calibrated` | ✗ | ✓ | Python layer only |
| `seatbelt latched` | ✗ | ✓ | Python layer only |
| `doors closed` | ✗ | ✓ | Python layer only |
| `!steerFaultTemporary` | ✗ | ✓ | Python layer only |
| `!steerFaultPermanent` | ✗ | ✓ | Python layer only |
---
## Data Flow
```
┌─────────────────────────────────────────────────────────────────────┐
│ CAN Bus │
└─────────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ Safety Layer (panda C code) │ │ Python Layer │
│ │ │ │
│ rx_hook: │ │ carstate.py: │
│ - Parse ACC Main signal │ │ - Parse cruiseState.available │
│ - Set lkas_on = acc_main_on │ │ - Set self.lkas_on │
│ │ │ │
│ lat_control_allowed(): │ └─────────────┬───────────────────┘
│ - Check lkas_on + other flags │ │
│ - Gate steering commands │ ▼
└─────────────────────────────────┘ ┌─────────────────────────────────┐
│ card.py: │
│ - Publish carStateExt.lkasOn │
└─────────────┬───────────────────┘
┌─────────────────────────────────┐
│ controlsd.py: │
│ - Read carStateExt.lkasOn │
│ - Check ALKA conditions │
│ - Set CC.latActive │
└─────────────────────────────────┘
```
### Key Files
| File | Purpose |
|------|---------|
| `custom.capnp` | Defines `CarStateExt` struct with `lkasOn` field |
| `log.capnp` | Includes `carStateExt` in event union |
| `interfaces.py` | Defines `self.lkas_on = False` default in `CarStateBase` |
| `carstate.py` (per brand) | Tracks `lkas_on` based on ACC Main |
| `card.py` | Publishes `carStateExt.lkasOn` from `CI.CS.lkas_on` |
| `controlsd.py` | Reads `carStateExt.lkasOn` to determine `alka_active` |
---
## ACC Main Tracking
All brands use simple direct tracking:
```c
// Panda (C code)
if (alka_allowed && (alternative_experience & ALT_EXP_ALKA)) {
lkas_on = acc_main_on; // or GET_BIT(msg, bit_position)
}
```
```python
# Python carstate.py
self.lkas_on = ret.cruiseState.available
```
This guard ensures:
1. Brand supports ALKA (`alka_allowed`)
2. User enabled ALKA (`ALT_EXP_ALKA`)
Without both conditions, no ACC Main tracking occurs, and ALKA remains disabled.
---
## Testing
Safety tests verify:
- `alka_allowed` flag set correctly per brand
- ACC Main tracking updates `lkas_on` directly
- `lat_control_allowed()` returns true only when all conditions met
- Steering TX blocked when ALKA conditions not met
- Bus routing variants (camera_scc, unsupported_dsu)
-91
View File
@@ -1,91 +0,0 @@
```mermaid
flowchart TD
B000["devel-staging"] ---> CORE["core"]
CORE ---> CORE_001["core-feat/params"]
CORE_001 ---> CORE_002["core-feat/panel"]
CORE_002 ---> CORE_003["core-feat/safety-ext"]
CORE_003 ---> MIN["min"]
MIN ---> MIN_001["min-feat/ui/display-mode"]
MIN ---> MIN_002["min-feat/dev/model-selector"]
MIN ---> MIN_003["min-feat/lat/lca"]
MIN ---> MIN_004["min-feat/dev/on-off-road"]
MIN ---> MIN_005["min-feat/ui/hide-hud"]
MIN ---> MIN_006["min-feat/lon/ext-radar"]
MIN ---> MIN_007["min-feat/lat/road-edge-detection"]
MIN ---> MIN_008["min-feat/ui/rainbow-path"]
MIN ---> MIN_009["min-feat/lon/acm"]
MIN ---> MIN_010["min-feat/lon/aem"]
MIN ---> MIN_011["min-feat/lon/dtsc"]
MIN ---> MIN_012["min-feat/lon/apm"]
MIN ---> MIN_013["min-feat/lon/dasr"]
MIN ---> MIN_014["min-feat/dev/alert-mode"]
MIN ---> MIN_015["min-feat/dev/auto-shutdown"]
MIN ---> MIN_016["min-feat/ui/lead-stats"]
MIN ---> MIN_017["min-feat/ui/border-indicator"]
MIN ---> MIN_018["min-feat/dev/delay-loggerd"]
MIN ---> MIN_019["min-feat/dev/disable-connect"]
MIN ---> MIN_020["min-feat/dev/tether-on-boot"]
MIN ---> MIN_021["min-feat/ui/torque-bar"]
MIN ---> MIN_022["min-feat/ui/mici-ui-mode"]
MIN ---> MIN_023["min-feat/lat/lat-offset"]
MIN_001 ---> FULL["full"]
MIN_002 ---> FULL
MIN_003 ---> FULL
MIN_004 ---> FULL
MIN_005 ---> FULL
MIN_006 ---> FULL
MIN_007 ---> FULL
MIN_008 ---> FULL
MIN_009 ---> FULL
MIN_010 ---> FULL
MIN_011 ---> FULL
MIN_012 ---> FULL
MIN_013 ---> FULL
MIN_014 ---> FULL
MIN_015 ---> FULL
MIN_016 ---> FULL
MIN_017 ---> FULL
MIN_018 ---> FULL
MIN_019 ---> FULL
MIN_020 ---> FULL
MIN_021 ---> FULL
FULL ---> TOYOTA_001[brand/toyota/safety-common]
FULL ---> TOYOTA_002[brand/toyota/door-auto-lock-unlock]
FULL ---> TOYOTA_003[brand/toyota/tss1-sng]
FULL ---> TOYOTA_004[brand/toyota/radar-filter]
FULL ---> TOYOTA_005[brand/toyota/sdsu]
FULL ---> TOYOTA_006[brand/toyota/dsu-bypass]
FULL ---> TOYOTA_007[brand/toyota/zss]
FULL ---> TOYOTA_008[brand/toyota/stock-lon]
FULL ---> VAG_001[brand/vag/a0-sng]
FULL ---> VAG_002[brand/vag/pq-steering-patch]
FULL ---> VAG_003[brand/vag/pq-no-dashcam]
FULL ---> VAG_004[brand/vag/avoid-eps-lockout]
FULL ---> HKG_001[brand/hkg/smdps]
FULL ---> HONDA_001[brand/honda/eps-mod]
FULL ---> HONDA_002[brand/honda/nidec-stock-long]
FULL ---> SUBARU_001[brand/subaru/torque-3071]
TOYOTA_001 ---> TOYOTA[pre-toyota]
TOYOTA_002 ---> TOYOTA
TOYOTA_003 ---> TOYOTA
TOYOTA_004 ---> TOYOTA
TOYOTA_005 ---> TOYOTA
TOYOTA_006 ---> TOYOTA
TOYOTA_007 ---> TOYOTA
TOYOTA_008 ---> TOYOTA
VAG_001 ---> VAG[pre-vag]
VAG_002 ---> VAG
VAG_003 ---> VAG
VAG_004 ---> VAG
HKG_001 ---> HKG[pre-hkg]
HONDA_001 ---> HONDA[pre-honda]
SUBARU_001 ---> SUBARU[pre-subaru]
TOYOTA ---> PRE[pre]
VAG ---> PRE
HKG ---> PRE
HONDA ---> PRE
SUBARU ---> PRE
PRE ---> PRE_PATCH[pre-patch]
PRE_PATCH ---> PREBUILD[pre-build]
PREBUILD ---> VERSION[x.x.x]
```
+40
View File
@@ -0,0 +1,40 @@
2024-04-10
========================
* Attempt to fix honda op long issue (take 2).
2024-03-20
========================
* Bug fixes
2024-03-19
========================
* Attempt to fix 70 mins LKAS/Harness error on Toyotas.
2024-03-01
========================
* Display correct changelogs.
2024-02-29
========================
* Added Lead Vehicle Warning
* Added Disable Auto Updates toggle
* Reverted panda back to last working version for honda with minimal changes from op master. (breaks red panda support for now)
* Added EON Installer (https://raw.githubusercontent.com/dragonpilot-community/dragonpilot/d2/scripts/eon_installer.sh)
* Conditionally include red panda firmware.
* Enabled branch selector.
* Reverted transform patch.
2024-02-27
========================
* Fixed door lock/unlock for Toyotas.
* otisserv and fileserv only for offroad.
* Enabling otisserv for offroad status and snapshot.
* Toyota: improve longitudinal control (https://github.com/commaai/openpilot/pull/30697)
* Updated manager/ modules
2024-02-26
========================
* applied transform patch. (https://github.com/commaai/openpilot/pull/31495)
* adjust de2e param accordingly for transform patch.
* increase lead sensitivity.
+11
View File
@@ -0,0 +1,11 @@
2024-02-06
========================
* NEW:
* Rainbow colored Path
* BUGFIXES:
* Toggle for Flight Panel
* NEW VEHICLES:
* Hyundai Staria 2023
* Kia Niro Plug-in Hybrid 2022
* Toyota RAV4 2023-24
* Toyota RAV4 Hybrid 2023-24
-1877
View File
File diff suppressed because it is too large Load Diff
-14
View File
@@ -1,14 +0,0 @@
FROM ghcr.io/commaai/openpilot-base:latest
ENV PYTHONUNBUFFERED=1
ENV OPENPILOT_PATH=/home/batman/openpilot
RUN mkdir -p ${OPENPILOT_PATH}
WORKDIR ${OPENPILOT_PATH}
COPY . ${OPENPILOT_PATH}/
ENV UV_BIN="/home/batman/.local/bin/"
ENV PATH="$UV_BIN:$PATH"
RUN UV_PROJECT_ENVIRONMENT=$VIRTUAL_ENV uv run scons --cache-readonly -j$(nproc)
-81
View File
@@ -1,81 +0,0 @@
FROM ubuntu:24.04
ENV PYTHONUNBUFFERED=1
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y --no-install-recommends sudo tzdata locales ssh pulseaudio xvfb x11-xserver-utils gnome-screenshot python3-tk python3-dev && \
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
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8
COPY tools/install_ubuntu_dependencies.sh /tmp/tools/
RUN /tmp/tools/install_ubuntu_dependencies.sh && \
rm -rf /var/lib/apt/lists/* /tmp/* && \
cd /usr/lib/gcc/arm-none-eabi/* && \
rm -rf arm/ thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp
# Add OpenCL
RUN apt-get update && apt-get install -y --no-install-recommends \
apt-utils \
alien \
unzip \
tar \
curl \
xz-utils \
dbus \
gcc-arm-none-eabi \
tmux \
vim \
libx11-6 \
wget \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /tmp/opencl-driver-intel && \
cd /tmp/opencl-driver-intel && \
wget https://github.com/intel/llvm/releases/download/2024-WW14/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \
wget https://github.com/oneapi-src/oneTBB/releases/download/v2021.12.0/oneapi-tbb-2021.12.0-lin.tgz && \
mkdir -p /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \
cd /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \
tar -zxvf /tmp/opencl-driver-intel/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \
mkdir -p /etc/OpenCL/vendors && \
echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64/libintelocl.so > /etc/OpenCL/vendors/intel_expcpu.icd && \
cd /opt/intel && \
tar -zxvf /tmp/opencl-driver-intel/oneapi-tbb-2021.12.0-lin.tgz && \
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so.12 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so.2 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
mkdir -p /etc/ld.so.conf.d && \
echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 > /etc/ld.so.conf.d/libintelopenclexp.conf && \
ldconfig -f /etc/ld.so.conf.d/libintelopenclexp.conf && \
cd / && \
rm -rf /tmp/opencl-driver-intel
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute
ENV QTWEBENGINE_DISABLE_SANDBOX=1
RUN dbus-uuidgen > /etc/machine-id
ARG USER=batman
ARG USER_UID=1001
RUN useradd -m -s /bin/bash -u $USER_UID $USER
RUN usermod -aG sudo $USER
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
USER $USER
COPY --chown=$USER pyproject.toml uv.lock /home/$USER
COPY --chown=$USER tools/install_python_dependencies.sh /home/$USER/tools/
ENV VIRTUAL_ENV=/home/$USER/.venv
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
RUN cd /home/$USER && \
tools/install_python_dependencies.sh && \
rm -rf tools/ pyproject.toml uv.lock .cache
USER root
RUN sudo git config --global --add safe.directory /tmp/openpilot
+14
View File
@@ -1,3 +1,17 @@
MIT License
Copyright (c) 2023-, Rick Lan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software.
You are not authorized to modify this README file in any way. If you need to make changes or additions to the documentation for your own use, please create a separate file and reference it in this README.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
MIT License
Copyright (c) 2018, Comma.ai, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-30
View File
@@ -1,30 +0,0 @@
Copyright (c) 2019, Rick Lan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, and/or sublicense,
for non-commercial purposes only, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
- Commercial use (e.g. use in a product, service, or activity intended to
generate revenue) is prohibited without explicit written permission from
the copyright holder.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
Copyright (c) 2018, Comma.ai, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Regular → Executable
+177 -39
View File
@@ -1,74 +1,212 @@
![](dragonpilot/selfdrive/assets/dragonpilot.png)
# Legacypilot
[Read this in English](README_EN.md)
This software includes contributions from [dragonpilot](https://github.com/dragonpilot-community/dragonpilot/tree/beta2) and [openpilot](https://github.com/commaai/openpilot).
# **🐲 dragonpilot - 賦予您的愛車「龍」之魂**
NOTICE: legacypilot is not affiliated with comma.ai and is not an official comma.ai product. legacypilot is released under the terms of the MIT License. See the LICENSE file for more details.
**我們與您一同翱翔於更智慧、更貼心的駕駛旅程。**
## **👋 嘿, 朋友,歡迎您的到來!**
## About
`dragonpilot` 誕生於 2019 年,由三位早期的 openpilot 華人玩家共同創立。初衷很簡單:為廣大的華人用戶、玩家們提供一個友善的交流環境、更簡便的設定協助,並加入更多適合在地使用的貼心功能。
legacypilot is a side project that enables comma.ai EON and Comma Two devices to use the dragonpilot. This project was started after comma.ai deprecated support for the EON in version 0.7.9 and for Comma Two in version 0.8.13.1, in order to provide continued access to these devices.
我們深知在地化的重要性,特別是語言的親切感。因此,我們率先導入了完整的中文介面,讓 `dragonpilot` 迅速在華語地區累積了口碑,也讓華人的使用者數量在全球名列前茅。這份來自在地的支持,是我們持續前進的最大動力。
legacypilot combines the Nuclear Grade Model with the latest openpilot (almost) codebase to create a hybrid solution. With the legacypilot project, we have stripped out nearly 99% of the dragonpilot code.
我們以功能強大的 [openpilot](https://github.com/commaai/openpilot) 為基礎——這套據美國消費者報告評測優於市售車方案的開源輔助駕駛系統——融入了更多在地化的巧思與客製化的溫度,希望能打造出最符合您需求的駕駛夥伴。(您也可以參考我們 repo 中保留的 [openpilot 原始說明檔案](README_OPENPILOT.md))
In summary, legacypilot is based on Openpilot 0.8.16 with the latest vehicle model support from the Openpilot master branch.
取名 `dragonpilot`,是因為我們希望它能像神話中的「龍」一樣,既強大又充滿智慧,為您的行車安全保駕護航。龍,在我們華人文化中,更是吉祥與力量的象徵,也代表著我們的根源與驕傲。
Please note that this build is and will always be in the experimental phase and may not be suitable for use as a daily driver.
## **✨ dragonpilot 的里程碑**
I recommend using the openpilot [commatwo_master](https://github.com/commaai/openpilot/tree/commatwo_master) branch for your daily driving needs.
我們不僅保留了 openpilot 的核心優勢,更達成了許多從社群回饋中誕生的里程碑,這些是我們引以為傲的足跡:
* **🚘 全時置中車道維持 (ALKA)**
## Why use legacypilot
這不只是一個功能,更是 `dragonpilot` 的哲學。我們最早於 [0.6.2 版本](https://github.com/dragonpilot-community/dragonpilot/blob/2861467183d62151024320447ba04d18fc3fe1e6/selfdrive/car/toyota/carstate.py#L199) 時便實現了這個功能,其開發歷程始於 2017 Lexus IS300h,接著擴展至 Toyota 全車系,並逐步延伸到其他支援的品牌。它能溫柔地輔助您,讓車輛始終穩定地保持在車道中央,提供一份額外的安心與從容。
I have decided to make this side project open source for users who wish to:
* **🌐 率先導入多國語言介面**
* Port unsupported vehicles using cheaper devices.
* Evaluate end-to-end lateral and longitudinal control on previously unsupported vehicles.
* Understand the limitations of legacy devices.
* Experience pure openpilot (without the modifications of dragonpilot)
* Make their own EON/C2 fork without spending hundreds of hours reverting and testing code.
在官方 openpilot 還未支援前,我們便已將多國語言介面實現。`dragonpilot` 完整支援繁體中文、簡體中文與英文,讓操作毫無隔閡。
By making this project open source, I hope to alleviate some of the frustration and complaints about not being able to access the dragonpilot source code.
* **💻 唯一同時支援多硬體平台**
I encourage users to consider purchasing a [comma 3x](https://shop.comma.ai) for the best and up-to-date openpilot experience.
我們是唯一曾致力於讓專案同時兼容 EON、comma two、comma 3 與 Jetson 平台的社群分支,這份努力是為了服務最廣大的玩家社群。
此外,在 comma.ai 團隊於 0.10.0 版本宣布停止支持 comma 3 後,我們仍是唯一一個完整同時支援 comma 3、comma 3X 以及 O3、O3L、O3XL(O3 系列為副廠硬體)的社群分支。
* **📜 曾榮獲官方認證第一大分支**
## Limitations
基於活躍的社群與功能創新,`dragonpilot` 曾一度成長為 comma ai 官方認證的第一大 openpilot 分支,這份榮耀屬於每一位參與者。
* On-road tests are conducted exclusively in a 2021 Toyota C-HR; other models may not perform properly.
* ~~CAN-FD and BODY features are not supported due to outdated libraries in EON/C2 firmware.~~
* The driving AI model remains in version 0.8.16, as porting TinyGrad/PyOpenCL requires significant effort.
* The driver monitoring AI model remains in version 0.8.13.
* Navigation On Openpilot (NOO) is not supported, as it requires a newer driving model that is not currently available in legacypilot.
* Services are not optimized for resource usage, and using all services may result in overheating issues.
* Language files can only be generated in a PC due to missing Qt5 tools.
* webjoystick is disabled as it requires additional python modules. (aiohttp and others)
* Starting from August 7th, 2023, comma has removed ESP/GPS support from Panda. You can find more details about this change in this [link](https://github.com/commaai/panda/commit/c66b98b2a67441faa4cfcd36c3c9d9f90474cd08).
* Going forward, I will focus solely on maintaining the safety aspects of the code, ensuring that vehicle support and safety declarations remain up to date.
* For safety concern, End-to-End / vision only longitudinal control only available in 0.8.16 driving model.
## **🧑‍💻 設計理念 - 少即是多 (Less is More)**
隨著 openpilot 的 AI 模型日益強大,許多過去需要手動微調的功能,現在都已能透過更先進的模型來實現。因此,我們現在的開發重心回歸到 **「最小化修改」(minimal changes)** 的核心原則上。
## Configuration
我們的目標是為您提供最純粹、最接近官方的 openpilot 駕駛感受,同時保留 `dragonpilot` 那些經過時間考驗、最受社群喜愛的經典功能。我們相信,在強大的 AI 基礎上,簡潔即是力量。
* For research purposes, the INDI and LQR lateral controllers have been restored. Please use the `dp_lat_controller` parameter to override the default controller (0 = DEFAULT, 1 = INDI, 2 = LQR).
* If you are not a Comma Two device, you can use the `dp_no_fan_ctrl` parameter to disable fan-related detection and control.
* The BODY has been tested and is working; however, I personally haven't tried it, so I'm not sure what steps are needed to get it to work.
## **🛠️ 硬件的足跡 - 一路走來的夥伴們**
從最早的 **EON**,到官方的 **comma two / three (C2/C3/C3X)**,再到社群中各式各樣充滿智慧的**副廠機 (如 C1.5, O2, O3, O3L, O3XL 等)**,甚至我們也曾探索過在 [**Jetson Xavier NX**](https://github.com/eFiniLan/xnxpilot) 上的可能性。
## Red Panda (a.k.a. CAN-FD support)
The EON + Red Panda configuration has been tested and worked on [my Toyota](https://youtu.be/KgrI2Ley_Nk) (CAN), so technically it should work on CAN-FD vehicles. However, there are a couple of considerations:
* C2 will not function without hardware modification. You cannot connect the Red Panda directly to the C2 USB port.
* If any changes are made to the Red Panda firmware, the firmware needs to be pre-compiled on a PC and then uploaded to `/data/openpilot/panda/board/obj/`.
* Please be aware that you may encounter **CANBUS disconnection errors**. If this occurs, simply **power cycle BOTH your device and Red Panda**.
目前最新版本主要支援: comma3 / 3X 以及 O3 / O3L / O3XL 等社群硬體。
針對 EON / C1.5 / C2 等舊款硬體,最後支援的版本位於 [d2 分支](https://github.com/dragonpilot-community/dragonpilot/tree/d2)。
無論您手上是哪一款設備,都代表著您對開源駕駛輔助的一份熱情。
## **🫂 加入我們,成為「尋龍者」的一份子**
=======================
`dragonpilot` 的成長,離不開每一位使用者的貢獻與回饋。我們是一個以**公開、透明**為原則的溫暖社群,希望在這裡能與所有對 openpilot / dragonpilot 有興趣的用戶分享、交流開發與使用上的經驗。
![openpilot on the comma 3X](https://github.com/commaai/openpilot/assets/4038174/f1081737-8718-4241-a22a-3ceba526361a)
[**歡迎加入我們的 Facebook 社團進行交流!**](https://www.facebook.com/groups/930190251238639)
Table of Contents
=======================
## **❤️ 特別感謝**
* [What is openpilot?](#what-is-openpilot)
* [Running in a car](#running-on-a-dedicated-device-in-a-car)
* [Running on PC](#running-on-pc)
* [Community and Contributing](#community-and-contributing)
* [User Data and comma Account](#user-data-and-comma-account)
* [Safety and Testing](#safety-and-testing)
* [Directory Structure](#directory-structure)
* [Licensing](#licensing)
`dragonpilot` 從創立至今,從未打算透過 Patreon 等平台進行任何形式的募資。我們的初衷是建立一個讓大家能一起學習、一起成長的社群。It's all about fun, not money.
---
然而,我們仍要對那些自發性支持本專案的朋友們,致上最誠摯的感謝。正是因為有您們的鼓勵,我們才有更大的動力持續前進。
What is openpilot?
------
[**我們的贊助者名單**](SPONSORS.md)
[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW), and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models, and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera-based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md).
### **安全聲明**
<table>
<tr>
<td><a href="https://youtu.be/NmBfgOanCyk" title="Video By Greer Viau"><img src="https://i.imgur.com/1w8c6d2.jpg"></a></td>
<td><a href="https://youtu.be/VHKyqZ7t8Gw" title="Video By Logan LeGrand"><img src="https://i.imgur.com/LnBucik.jpg"></a></td>
<td><a href="https://youtu.be/VxiR4iyBruo" title="Video By Charlie Kim"><img src="https://i.imgur.com/4Qoy48c.jpg"></a></td>
<td><a href="https://youtu.be/-IkImTe1NYE" title="Video By Aragon"><img src="https://i.imgur.com/04VNzPf.jpg"></a></td>
</tr>
<tr>
<td><a href="https://youtu.be/iIUICQkdwFQ" title="Video By Logan LeGrand"><img src="https://i.imgur.com/b1LHQTy.jpg"></a></td>
<td><a href="https://youtu.be/XOsa0FsVIsg" title="Video By PinoyDrives"><img src="https://i.imgur.com/6FG0Bd8.jpg"></a></td>
<td><a href="https://youtu.be/bCwcJ98R_Xw" title="Video By JS"><img src="https://i.imgur.com/zO18CbW.jpg"></a></td>
<td><a href="https://youtu.be/BQ0tF3MTyyc" title="Video By Tsai-Fi"><img src="https://i.imgur.com/eZzelq3.jpg"></a></td>
</tr>
</table>
`dragonpilot` 是一種駕駛**輔助**系統,並非全自動駕駛。它旨在減輕您的駕駛疲勞,提升行車安全,但駕駛人仍需時刻保持專注,並隨時準備接管車輛。請務必遵守您所在地區的交通法規。
**最後,再次感謝您的到來。**
Running on a dedicated device in a car
------
**期待與您一同在智慧駕駛的道路上,乘「龍」而行!**
To use openpilot in a car, you need four things
* A supported device to run this software: a [comma 3X](https://comma.ai/shop/comma-3x) or comma three.
* This software. The setup procedure of the comma 3/3X allows the user to enter a URL for custom software.
The URL, openpilot.comma.ai will install the release version of openpilot. To install openpilot master, you can use installer.comma.ai/commaai/master, and replacing commaai with another GitHub username can install a fork.
* One of [the 250+ supported cars](docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run openpilot.
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car.
We have detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
Running on PC
------
All openpilot services can run as usual on a PC without requiring special hardware or a car. You can also run openpilot on recorded or simulated data to develop or experiment with openpilot.
With openpilot's tools, you can plot logs, replay drives, and watch the full-res camera streams. See [the tools README](tools/README.md) for more information.
You can also run openpilot in simulation [with the CARLA simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine. The whole setup should only take a few minutes but does require a decent GPU.
A PC running openpilot can also control your vehicle if it is connected to a [webcam](https://github.com/commaai/openpilot/tree/master/tools/webcam), a [black panda](https://comma.ai/shop/products/panda), and a [harness](https://comma.ai/shop/products/car-harness).
Community and Contributing
------
openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot). Bug fixes and new car ports are encouraged. Check out [the contributing docs](docs/CONTRIBUTING.md).
Documentation related to openpilot development can be found on [docs.comma.ai](https://docs.comma.ai). Information about running openpilot (e.g. FAQ, fingerprinting, troubleshooting, custom forks, community hardware) should go on the [wiki](https://github.com/commaai/openpilot/wiki).
You can add support for your car by following guides we have written for [Brand](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/) and [Model](https://blog.comma.ai/openpilot-port-guide-for-toyota-models/) ports. Generally, a car with adaptive cruise control and lane keep assist is a good candidate. [Join our Discord](https://discord.comma.ai) to discuss car ports: most car makes have a dedicated channel.
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs#open-positions).
And [follow us on Twitter](https://twitter.com/comma_ai).
User Data and comma Account
------
By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone.
openpilot is open source software: the user is free to disable data collection if they wish to do so.
openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
Safety and Testing
----
* openpilot observes ISO26262 guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
* openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
* panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
* Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
Directory Structure
------
.
├── cereal # The messaging spec and libs used for all logs
├── common # Library like functionality we've developed here
├── docs # Documentation
├── opendbc # Files showing how to interpret data from cars
├── panda # Code used to communicate on CAN
├── third_party # External libraries
└── system # Generic services
├── camerad # Driver to capture images from the camera sensors
├── clocksd # Broadcasts current time
├── hardware # Hardware abstraction classes
├── logcatd # systemd journal as a service
├── loggerd # Logger and uploader of car data
├── proclogd # Logs information from /proc
├── sensord # IMU interface code
└── ubloxd # u-blox GNSS module interface code
└── selfdrive # Code needed to drive the car
├── assets # Fonts, images, and sounds for UI
├── athena # Allows communication with the app
├── boardd # Daemon to talk to the board
├── car # Car specific code to read states and control actuators
├── controls # Planning and controls
├── debug # Tools to help you debug and do car ports
├── locationd # Precise localization and vehicle parameter estimation
├── manager # Daemon that starts/stops all other daemons as needed
├── modeld # Driving and monitoring model runners
├── monitoring # Daemon to determine driver attention
├── navd # Turn-by-turn navigation
├── test # Unit tests, system tests, and a car simulator
└── ui # The UI
Licensing
------
openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys fees and costs) which arise out of, relate to or result from any use of this software by user.
**THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
NO WARRANTY EXPRESSED OR IMPLIED.**
---
<img src="https://d1qb2nb5cznatu.cloudfront.net/startups/i/1061157-bc7e9bf3b246ece7322e6ffe653f6af8-medium_jpg.jpg?buster=1458363130" width="75"></img> <img src="https://cdn-images-1.medium.com/max/1600/1*C87EjxGeMPrkTuVRVWVg4w.png" width="225"></img>
[![openpilot tests](https://github.com/commaai/openpilot/workflows/openpilot%20tests/badge.svg?event=push)](https://github.com/commaai/openpilot/actions)
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)
-74
View File
@@ -1,74 +0,0 @@
![](dragonpilot/selfdrive/assets/dragonpilot.png)
[Read this in Chinese](README.md)
# **🐲 dragonpilot - Bringing the Spirit of the Dragon to Your Car**
**Join us on a smarter, more thoughtful driving journey.**
## **👋 Welcome, friend!**
`dragonpilot` was launched in 2019 by three early openpilot enthusiasts from the Chinese community. Our mission was simple: create a friendly space for users to share experiences, provide easier setup help, and add features tailored for local needs.
Localization has always been at the heart of what we do—starting with a fully Chinese interface. This made `dragonpilot` quickly popular in Chinese-speaking regions and helped our user base grow into one of the largest worldwide. That community support is what keeps us moving forward.
Built on top of the powerful [openpilot](https://github.com/commaai/openpilot)—an open-source driver assistance system rated by Consumer Reports as outperforming commercial offerings—we add localized refinements and user-focused features to create a driving companion that truly fits your needs. (You can also see the [original openpilot README](README_OPENPILOT.md) preserved in our repo.)
The name `dragonpilot` reflects our vision: like the dragon of mythology, it is strong and wise, guarding your safety on the road. In Chinese culture, the dragon is also a symbol of luck and strength, representing our roots and pride.
## **✨ Milestones**
Beyond carrying forward openpilot's core strengths, we've reached several milestones inspired by community feedback:
* **🚘 Always Lane Keep Assist (ALKA)**
More than a feature—it's part of the `dragonpilot` philosophy. Introduced as early as [version 0.6.2](https://github.com/dragonpilot-community/dragonpilot/blob/2861467183d62151024320447ba04d18fc3fe1e6/selfdrive/car/toyota/carstate.py#L199), first tested on a 2017 Lexus IS300h, then expanded to Toyota's lineup and beyond. ALKA helps keep your vehicle steadily centered, giving you extra confidence on the road.
* **🌐 First to add multilingual support**
Before openpilot officially supported it, we had already introduced multiple languages. `dragonpilot` fully supports Traditional Chinese, Simplified Chinese, and English.
* **💻 Only community fork to support multiple hardware platforms at once**
We uniquely worked to make the project run on EON, comma two, comma 3, and Jetson—serving the widest range of users possible.
Additionally, after the comma.ai team deprecated the comma 3 in version 0.10.0, we remain the only community fork to offer full, simultaneous support for the comma 3, comma 3X, and the O3, O3L, and O3XL (the O3 series being third-party hardware).
* **📜 Once recognized as the #1 openpilot fork**
Thanks to an active community and continuous innovation, `dragonpilot` was once the largest openpilot fork officially recognized by comma ai. This honor belongs to everyone who contributed.
## **🧑‍💻 Design Philosophy - Less is More**
As openpilot's AI grows stronger, many features that once required manual tuning are now handled by advanced models. That's why our focus has returned to **“minimal changes.”**
We aim to give you the purest, most official-like openpilot driving experience—while preserving `dragonpilot`'s classic, community-loved features. With a solid AI foundation, simplicity is strength.
## **🛠️ Hardware Journey**
From the early **EON**, to official devices like **comma two / three (C2/C3/C3X)**, to creative community builds (**C1.5, O2, O3, O3L, O3XL, etc.**), and even experiments with [**Jetson Xavier NX**](https://github.com/eFiniLan/xnxpilot).
Currently, the latest versions support: **comma3 / 3X** and community hardware like **O3 / O3L / O3XL**.
Older devices such as **EON / C1.5 / C2** are supported in the [d2 branch](https://github.com/dragonpilot-community/dragonpilot/tree/d2).
Whatever device you're on, it represents your passion for open-source driver assistance.
## **🫂 Join Us Become a “Dragon Seeker”**
`dragonpilot` thrives thanks to every user's contributions and feedback. We're an open, transparent, and welcoming community where enthusiasts can share experiences with openpilot and `dragonpilot`.
[**Join our Facebook group here!**](https://www.facebook.com/groups/930190251238639)
## **❤️ Special Thanks**
Since day one, `dragonpilot` has never asked for funding through Patreon or similar platforms. Our vision is a community where everyone learns and grows together. It's about fun, not money.
That said, we're deeply grateful to those who voluntarily supported the project. Your encouragement keeps us motivated to keep building.
[**See our sponsors**](SPONSORS.md)
### **Safety Notice**
`dragonpilot` is a driver **assistance** system, not full self-driving. It reduces fatigue and improves safety, but you must remain alert and ready to take control at all times. Always follow your local traffic laws.
**Thanks again for being here.**
**We look forward to riding the “dragon” with you on the road to smarter driving!**
-111
View File
@@ -1,111 +0,0 @@
<div align="center" style="text-align: center;">
<h1>openpilot</h1>
<p>
<b>openpilot is an operating system for robotics.</b>
<br>
Currently, it upgrades the driver assistance system in 300+ supported cars.
</p>
<h3>
<a href="https://docs.comma.ai">Docs</a>
<span> · </span>
<a href="https://docs.comma.ai/contributing/roadmap/">Roadmap</a>
<span> · </span>
<a href="https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md">Contribute</a>
<span> · </span>
<a href="https://discord.comma.ai">Community</a>
<span> · </span>
<a href="https://comma.ai/shop">Try it on a comma 3X</a>
</h3>
Quick start: `bash <(curl -fsSL openpilot.comma.ai)`
[![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/tests.yaml/badge.svg)](https://github.com/commaai/openpilot/actions/workflows/tests.yaml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![X Follow](https://img.shields.io/twitter/follow/comma_ai)](https://x.com/comma_ai)
[![Discord](https://img.shields.io/discord/469524606043160576)](https://discord.comma.ai)
</div>
<table>
<tr>
<td><a href="https://youtu.be/NmBfgOanCyk" title="Video By Greer Viau"><img src="https://github.com/commaai/openpilot/assets/8762862/2f7112ae-f748-4f39-b617-fabd689c3772"></a></td>
<td><a href="https://youtu.be/VHKyqZ7t8Gw" title="Video By Logan LeGrand"><img src="https://github.com/commaai/openpilot/assets/8762862/92351544-2833-40d7-9e0b-7ef7ae37ec4c"></a></td>
<td><a href="https://youtu.be/SUIZYzxtMQs" title="A drive to Taco Bell"><img src="https://github.com/commaai/openpilot/assets/8762862/05ceefc5-2628-439c-a9b2-89ce77dc6f63"></a></td>
</tr>
</table>
Using openpilot in a car
------
To use openpilot in a car, you need four things:
1. **Supported Device:** a comma 3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x).
2. **Software:** The setup procedure for the comma 3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version.
3. **Supported Car:** Ensure that you have one of [the 275+ supported cars](docs/CARS.md).
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3X to your car.
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play.
### Branches
Running `master` and other branches directly is supported, but it's recommended to run one of the following prebuilt branches:
| comma four branch | comma 3X branch | URL | description |
|------------------------|------------------------|----------------------------------------|-------------------------------------------------------------------------------------|
| `release-mici` | `release-tizi` | openpilot.comma.ai | This is openpilot's release branch. |
| `release-mici-staging` | `release-tizi-staging` | openpilot-test.comma.ai | This is the staging branch for releases. Use it to get new releases slightly early. |
| `nightly` | `nightly` | openpilot-nightly.comma.ai | This is the bleeding edge development branch. Do not expect this to be stable. |
| `nightly-dev` | `nightly-dev` | installer.comma.ai/commaai/nightly-dev | Same as nightly, but includes experimental development features for some cars. |
To start developing openpilot
------
openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot).
* Join the [community Discord](https://discord.comma.ai)
* Check out [the contributing docs](docs/CONTRIBUTING.md)
* Check out the [openpilot tools](tools/)
* Code documentation lives at https://docs.comma.ai
* Information about running openpilot lives on the [community wiki](https://github.com/commaai/openpilot/wiki)
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs#open-positions) and offers lots of [bounties](https://comma.ai/bounties) for external contributors.
Safety and Testing
----
* openpilot observes [ISO26262](https://en.wikipedia.org/wiki/ISO_26262) guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
* openpilot has software-in-the-loop [tests](.github/workflows/tests.yaml) that run on every commit.
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
* panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
* Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
<details>
<summary>MIT Licensed</summary>
openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys fees and costs) which arise out of, relate to or result from any use of this software by user.
**THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
NO WARRANTY EXPRESSED OR IMPLIED.**
</details>
<details>
<summary>User Data and comma Account</summary>
By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone.
openpilot is open source software: the user is free to disable data collection if they wish to do so.
openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
The driver-facing camera and microphone are only logged if you explicitly opt-in in settings.
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
</details>
+6 -106
View File
@@ -1,109 +1,9 @@
Version 0.10.3 (2025-12-17)
Version 0.9.6 (2023-12-14)
========================
* New driving model #36249
* New temporal policy architecture
* New on-policy training physics noise model
* New driver monitoring model #36409
* Trained on a new dataset, including comma four data
* Improved inter-process communication memory efficiency
Version 0.10.2 (2025-11-19)
========================
* comma four support
Version 0.10.1 (2025-09-08)
========================
* New driving model #36276
* World Model: removed global localization inputs
* World Model: 2x the number of parameters
* World Model: trained on 4x the number of segments
* VAE Compression Model: new architecture and training objective
* Driving Vision Model: trained on 4x the number of segments
* New Driver Monitoring model #36198
* Acura TLX 2021 support thanks to MVL!
* Honda City 2023 support thanks to vanillagorillaa and drFritz!
* Honda N-Box 2018 support thanks to miettal!
* Honda Odyssey 2021-25 support thanks to csouers and MVL!
* Honda Passport 2026 support thanks to vanillagorillaa and MVL!
Version 0.10.0 (2025-08-05)
========================
* New driving model
* New training architecture
* Described in our CVPR paper: "Learning to Drive from a World Model"
* Longitudinal MPC replaced by E2E planning from World Model in Experimental Mode
* Action from lateral MPC as training objective replaced by E2E planning from World Model
* Low-speed lead car ground-truth fixes
* Enable live-learned steering actuation delay
* Opt-in audio recording for dashcam video
* Acura MDX 2025 support thanks to vanillagorillaa and MVL!
* Honda Accord 2023-25 support thanks to vanillagorillaa and MVL!
* Honda CR-V 2023-25 support thanks to vanillagorillaa and MVL!
* Honda Pilot 2023-25 support thanks to vanillagorillaa and MVL!
Version 0.9.9 (2025-05-23)
========================
* New driving model
* New training architecture using parts from MLSIM
* Steering actuation delay is now learned online
* Ford Escape 2023-24 support thanks to incognitojam!
* Ford Kuga 2024 support thanks to incognitojam!
* Hyundai Nexo 2021 support thanks to sunnyhaibin!
* Tesla Model 3 and Y support thanks to lukasloetkolben!
* Lexus RC 2023 support thanks to nelsonjchen!
Version 0.9.8 (2025-02-28)
========================
* New driving model
* Model now gates applying positive acceleration in Chill mode
* New driver monitoring model
* Reduced false positives related to passengers
* Image processing pipeline moved to the ISP
* More GPU time for bigger driving models
* Power draw reduced 0.5W, which means your device runs cooler
* Added toggle to enable driver monitoring even when openpilot is not engaged
* Localizer rewritten to remove GPS dependency at runtime
* Firehose Mode for maximizing your training data uploads
* Enable openpilot longitudinal control for Ford Q3 vehicles
* New Toyota TSS2 longitudinal tune
* Rivian R1S and R1T support thanks to lukasloetkolben!
* Ford F-150, F-150 Hybrid, Mach-E, and Ranger support
Version 0.9.7 (2024-06-13)
========================
* New driving model
* Inputs the past curvature for smoother and more accurate lateral control
* Simplified neural network architecture in the model's last layers
* Minor fixes to desire augmentation and weight decay
* New driver monitoring model
* Improved end-to-end bit for phone detection
* Adjust driving personality with the follow distance button
* Support for hybrid variants of supported Ford models
* Fingerprinting without the OBD-II port on all cars
* Improved fuzzy fingerprinting for Ford and Volkswagen
Version 0.9.6 (2024-02-27)
========================
* New driving model
* Vision model trained on more data
* Improved driving performance
* Directly outputs curvature for lateral control
* New driver monitoring model
* Trained on larger dataset
* Model path UI
* Shows where driving model wants to be
* Shows what model is seeing more clearly, but more jittery
* AGNOS 9
* comma body streaming and controls over WebRTC
* Improved fuzzy fingerprinting for many makes and models
* Alpha longitudinal support for new Toyota models
* Chevrolet Equinox 2019-22 support thanks to JasonJShuler and nworb-cire!
* Dodge Durango 2020-21 support
* Hyundai Staria 2023 support thanks to sunnyhaibin!
* Kia Niro Plug-in Hybrid 2022 support thanks to sunnyhaibin!
* Lexus LC 2024 support thanks to nelsonjchen!
* Toyota RAV4 2023-24 support
* Toyota RAV4 Hybrid 2023-24 support
* Toyota RAV4 2023 support
* Toyota RAV4 Hybrid 2023 support
Version 0.9.5 (2023-11-17)
========================
@@ -710,7 +610,7 @@ Version 0.5.13 (2019-05-31)
* Reduce CPU utilization by 20% and improve stability
* Temporarily remove mapd functionalities to improve stability
* Add openpilot record-only mode for unsupported cars
* Synchronize controlsd to pandad to reduce latency
* Synchronize controlsd to boardd to reduce latency
* Remove panda support for Subaru giraffe
Version 0.5.12 (2019-05-16)
@@ -1046,7 +946,7 @@ Version 0.2.8 (2017-02-27)
Version 0.2.7 (2017-02-08)
===========================
* Better performance and pictures at night
* Fix ptr alignment issue in pandad
* Fix ptr alignment issue in boardd
* Fix brake error light, fix crash if too cold
Version 0.2.6 (2017-01-31)
@@ -1078,7 +978,7 @@ Version 0.2.2 (2017-01-10)
Version 0.2.1 (2016-12-14)
===========================
* Performance improvements, removal of more numpy
* Fix pandad process priority
* Fix boardd process priority
* Make counter timer reset on use of steering wheel
Version 0.2 (2016-12-12)
-224
View File
@@ -1,224 +0,0 @@
import os
import subprocess
import sys
import sysconfig
import platform
import shlex
import numpy as np
import SCons.Errors
SCons.Warnings.warningAsException(True)
Decider('MD5-timestamp')
SetOption('num_jobs', max(1, int(os.cpu_count()/2)))
AddOption('--kaitai', action='store_true', help='Regenerate kaitai struct parsers')
AddOption('--asan', action='store_true', help='turn on ASAN')
AddOption('--ubsan', action='store_true', help='turn on UBSan')
AddOption('--mutation', action='store_true', help='generate mutation-ready code')
AddOption('--ccflags', action='store', type='string', default='', help='pass arbitrary flags over the command line')
AddOption('--minimal',
action='store_false',
dest='extras',
default=os.path.exists(File('#.gitattributes').abspath), # minimal by default on release branch (where there's no LFS)
help='the minimum build to run openpilot. no tests, tools, etc.')
# Detect platform
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
if platform.system() == "Darwin":
arch = "Darwin"
brew_prefix = subprocess.check_output(['brew', '--prefix'], encoding='utf8').strip()
elif arch == "aarch64" and os.path.isfile('/TICI'):
arch = "larch64"
assert arch in [
"larch64", # linux tici arm64
"aarch64", # linux pc arm64
"x86_64", # linux pc x64
"Darwin", # macOS arm64 (x86 not supported)
]
env = Environment(
ENV={
"PATH": os.environ['PATH'],
"PYTHONPATH": Dir("#").abspath + ':' + Dir(f"#third_party/acados").abspath,
"ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath,
"ACADOS_PYTHON_INTERFACE_PATH": Dir("#third_party/acados/acados_template").abspath,
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer"
},
CC='clang',
CXX='clang++',
CCFLAGS=[
"-g",
"-fPIC",
"-O2",
"-Wunused",
"-Werror",
"-Wshadow",
"-Wno-unknown-warning-option",
"-Wno-inconsistent-missing-override",
"-Wno-c99-designator",
"-Wno-reorder-init-list",
"-Wno-vla-cxx-extension",
],
CFLAGS=["-std=gnu11"],
CXXFLAGS=["-std=c++1z"],
CPPPATH=[
"#",
"#msgq",
"#third_party",
"#third_party/json11",
"#third_party/linux/include",
"#third_party/acados/include",
"#third_party/acados/include/blasfeo/include",
"#third_party/acados/include/hpipm/include",
"#third_party/catch2/include",
"#third_party/libyuv/include",
],
LIBPATH=[
"#common",
"#msgq_repo",
"#third_party",
"#selfdrive/pandad",
"#rednose/helpers",
f"#third_party/libyuv/{arch}/lib",
f"#third_party/acados/{arch}/lib",
],
RPATH=[],
CYTHONCFILESUFFIX=".cpp",
COMPILATIONDB_USE_ABSPATH=True,
REDNOSE_ROOT="#",
tools=["default", "cython", "compilation_db", "rednose_filter"],
toolpath=["#site_scons/site_tools", "#rednose_repo/site_scons/site_tools"],
)
# Arch-specific flags and paths
if arch == "larch64":
env.Append(CPPPATH=["#third_party/opencl/include"])
env.Append(LIBPATH=[
"/usr/local/lib",
"/system/vendor/lib64",
"/usr/lib/aarch64-linux-gnu",
])
arch_flags = ["-D__TICI__", "-mcpu=cortex-a57"]
env.Append(CCFLAGS=arch_flags)
env.Append(CXXFLAGS=arch_flags)
elif arch == "Darwin":
env.Append(LIBPATH=[
f"{brew_prefix}/lib",
f"{brew_prefix}/opt/openssl@3.0/lib",
f"{brew_prefix}/opt/llvm/lib/c++",
"/System/Library/Frameworks/OpenGL.framework/Libraries",
])
env.Append(CCFLAGS=["-DGL_SILENCE_DEPRECATION"])
env.Append(CXXFLAGS=["-DGL_SILENCE_DEPRECATION"])
env.Append(CPPPATH=[
f"{brew_prefix}/include",
f"{brew_prefix}/opt/openssl@3.0/include",
])
else:
env.Append(LIBPATH=[
"/usr/lib",
"/usr/local/lib",
])
# Sanitizers and extra CCFLAGS from CLI
if GetOption('asan'):
env.Append(CCFLAGS=["-fsanitize=address", "-fno-omit-frame-pointer"])
env.Append(LINKFLAGS=["-fsanitize=address"])
elif GetOption('ubsan'):
env.Append(CCFLAGS=["-fsanitize=undefined"])
env.Append(LINKFLAGS=["-fsanitize=undefined"])
_extra_cc = shlex.split(GetOption('ccflags') or '')
if _extra_cc:
env.Append(CCFLAGS=_extra_cc)
# no --as-needed on mac linker
if arch != "Darwin":
env.Append(LINKFLAGS=["-Wl,--as-needed", "-Wl,--no-undefined"])
# progress output
node_interval = 5
node_count = 0
def progress_function(node):
global node_count
node_count += node_interval
sys.stderr.write("progress: %d\n" % node_count)
if os.environ.get('SCONS_PROGRESS'):
Progress(progress_function, interval=node_interval)
# ********** Cython build environment **********
py_include = sysconfig.get_paths()['include']
envCython = env.Clone()
envCython["CPPPATH"] += [py_include, np.get_include()]
envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-shadow", "-Wno-deprecated-declarations"]
envCython["CCFLAGS"].remove("-Werror")
envCython["LIBS"] = []
if arch == "Darwin":
envCython["LINKFLAGS"] = env["LINKFLAGS"] + ["-bundle", "-undefined", "dynamic_lookup"]
else:
envCython["LINKFLAGS"] = ["-pthread", "-shared"]
np_version = SCons.Script.Value(np.__version__)
Export('envCython', 'np_version')
Export('env', 'arch')
# Setup cache dir
cache_dir = '/data/scons_cache' if arch == "larch64" else '/tmp/scons_cache'
CacheDir(cache_dir)
Clean(["."], cache_dir)
# ********** start building stuff **********
# Build common module
SConscript(['common/SConscript'])
Import('_common')
common = [_common, 'json11', 'zmq']
Export('common')
# Build messaging (cereal + msgq + socketmaster + their dependencies)
# Enable swaglog include in submodules
env_swaglog = env.Clone()
env_swaglog['CXXFLAGS'].append('-DSWAGLOG="\\"common/swaglog.h\\""')
SConscript(['msgq_repo/SConscript'], exports={'env': env_swaglog})
SConscript(['opendbc_repo/SConscript'], exports={'env': env_swaglog})
SConscript(['cereal/SConscript'])
Import('socketmaster', 'msgq')
messaging = [socketmaster, msgq, 'capnp', 'kj',]
Export('messaging')
# Build other submodules
SConscript(['panda/SConscript'])
SConscript(['panda_tici/SConscript'])
# Build rednose library
SConscript(['rednose/SConscript'])
# Build system services
SConscript([
'system/ubloxd/SConscript',
'system/loggerd/SConscript',
])
if arch == "larch64":
SConscript(['system/camerad/SConscript'])
# Build openpilot
SConscript(['third_party/SConscript'])
SConscript(['selfdrive/SConscript'])
if Dir('#tools/cabana/').exists() and GetOption('extras'):
SConscript(['tools/replay/SConscript'])
if arch != "larch64":
SConscript(['tools/cabana/SConscript'])
env.CompilationDatabase('compile_commands.json')
-5
View File
@@ -1,5 +0,0 @@
# Security Policy
## Reporting a Vulnerability
Suspected vulnerabilities can be reported to both `adeeb@comma.ai` and `security@comma.ai`.
-26
View File
@@ -1,26 +0,0 @@
# Sponsors 贊助者
我們誠摯感謝以下贊助者提供的硬體資源,讓專案能夠在多種平台上進行測試與驗證。
We sincerely thank the following sponsors for providing hardware resources, which enable the project to be tested and validated across multiple platforms.
---
## 贊助者列表 Sponsors
| 贊助者 Sponsor | 設備 Deices | 備註 Notes |
| -------------- | ----------- | ---------- |
| BlueGood | <ul><li>Radar Filter x 2</li><li>sDSU x1</li></ul> | - |
| Chia Chun Lee | <ul><li>C3 Quick Mount x1</li></ul> | - |
| CloudJ | <ul><li>C3X x1</li></ul> | - |
| FareWay | <ul><li>EON Quick Mount x1</li><li>C2/C3 Quick Mount x1</li></ul> | Special thanks for fixing my good old EON |
| Fred Wang | <ul><li>Oneplus 3t x1</li></ul> | - |
| Saber Huang | <ul><li>O3L x1</li></ul> | - |
| [馬威 Mr. One](https://shop61532546.taobao.com/) | <ul><li>O3 x 1</li><li>O3 (Dev) x1</li><li>O3XL x1</li><li>Red Panda x1</li><li>Panda Jungle v1 x1</li></ul> | - |
| 門文梁 | <ul><li>C1.5 x1</li></ul> | - |
---
🙏 沒有你們的支持,我們無法讓專案在這麼多硬體平台上持續成長與驗證。
Without your support, this project could not continue to grow and be validated across so many hardware platforms.
+18
View File
@@ -0,0 +1,18 @@
/gen/
*.tmp
*.pyc
__pycache__
.*.swp
.*.swo
*.os
*.o
*.a
test_runner
libmessaging.*
libmessaging_shared.*
services.h
.sconsign.dblite
libcereal_shared.*
.mypy_cache/
+58
View File
@@ -0,0 +1,58 @@
FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
autoconf \
build-essential \
ca-certificates \
capnproto \
clang \
cppcheck \
curl \
git \
libbz2-dev \
libcapnp-dev \
libffi-dev \
liblzma-dev \
libncurses5-dev \
libncursesw5-dev \
libreadline-dev \
libsqlite3-dev \
libssl-dev \
libtool \
libzmq3-dev \
llvm \
make \
cmake \
ocl-icd-opencl-dev \
opencl-headers \
python-openssl \
tk-dev \
wget \
xz-utils \
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}"
RUN pyenv install 3.11.4 && \
pyenv global 3.11.4 && \
pyenv rehash && \
pip3 install --no-cache-dir pyyaml Cython scons pycapnp pre-commit ruff parameterized coverage numpy
WORKDIR /project/
RUN cd /tmp/ && \
git clone https://github.com/catchorg/Catch2.git && \
cd Catch2 && \
git checkout 229cc4823c8cbe67366da8179efc6089dd3893e9 && \
mv single_include/catch2/ /project/ && \
cd .. \
rm -rf Catch2
WORKDIR /project/cereal
ENV PYTHONPATH=/project
COPY . .
RUN rm -rf .git && \
scons -c && scons -j$(nproc)
+11 -46
View File
@@ -1,6 +1,11 @@
# What is cereal?
# What is cereal? [![cereal tests](https://github.com/commaai/cereal/workflows/tests/badge.svg?event=push)](https://github.com/commaai/cereal/actions) [![codecov](https://codecov.io/gh/commaai/cereal/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/cereal)
cereal is the messaging system for openpilot. It uses [msgq](https://github.com/commaai/msgq) as a pub/sub backend, and [Cap'n proto](https://capnproto.org/capnp-tool.html) for serialization of the structs.
cereal is both a messaging spec for robotics systems as well as generic high performance IPC pub sub messaging with a single publisher and multiple subscribers.
Imagine this use case:
* A sensor process reads gyro measurements directly from an IMU and publishes a `sensorEvents` packet
* A calibration process subscribes to the `sensorEvents` packet to use the IMU
* A localization process subscribes to the `sensorEvents` packet to use the IMU also
## Messaging Spec
@@ -17,7 +22,7 @@ All `Events` have a `logMonoTime` and a `valid`. Then a big union defines the pa
### Maintaining backwards-compatibility
When making changes to the messaging spec you want to maintain backwards-compatibility, such that old logs can
When making changes to the messaging spec you want to maintain backwards-compatability, such that old logs can
be parsed with a new version of cereal. Adding structs and adding members to structs is generally safe, most other
things are not. Read more details [here](https://capnproto.org/language.html).
@@ -27,51 +32,11 @@ Forks of [openpilot](https://github.com/commaai/openpilot) might want to add thi
spec, however this could conflict with future changes made in mainline cereal/openpilot. Rebasing against mainline openpilot
then means breaking backwards-compatibility with all old logs of your fork. So we added reserved events in
[custom.capnp](custom.capnp) that we will leave empty in mainline cereal/openpilot. **If you only modify those, you can ensure your
fork will remain backwards-compatible with all versions of mainline openpilot and your fork.**
fork will remain backwards-compatible with all versions of mainline cereal/openpilot and your fork.**
An example of compatible changes:
```diff
diff --git a/cereal/custom.capnp b/cereal/custom.capnp
index 3348e859e..3365c7b98 100644
--- a/cereal/custom.capnp
+++ b/cereal/custom.capnp
@@ -10,7 +10,11 @@ $Cxx.namespace("cereal");
# DO rename the structs
# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)
## Pub Sub Backends
-struct CustomReserved0 @0x81c2f05a394cf4af {
+struct SteeringInfo @0x81c2f05a394cf4af {
+ active @0 :Bool;
+ steeringAngleDeg @1 :Float32;
+ steeringRateDeg @2 :Float32;
+ steeringAccelDeg @3 :Float32;
}
struct CustomReserved1 @0xaedffd8f31e7b55d {
diff --git a/cereal/log.capnp b/cereal/log.capnp
index 1209f3fd9..b189f58b6 100644
--- a/cereal/log.capnp
+++ b/cereal/log.capnp
@@ -2558,14 +2558,14 @@ struct Event {
# DO change the name of the field
# DON'T change anything after the "@"
- customReservedRawData0 @124 :Data;
+ rawCanData @124 :Data;
customReservedRawData1 @125 :Data;
customReservedRawData2 @126 :Data;
# DO change the name of the field and struct
# DON'T change the ID (e.g. @107)
# DON'T change which struct it points to
- customReserved0 @107 :Custom.CustomReserved0;
+ steeringInfo @107 :Custom.SteeringInfo;
customReserved1 @108 :Custom.CustomReserved1;
customReserved2 @109 :Custom.CustomReserved2;
customReserved3 @110 :Custom.CustomReserved3;
```
---
cereal supports two backends, one based on [zmq](https://zeromq.org/) and another called [msgq](messaging/msgq.cc), a custom pub sub based on shared memory that doesn't require the bytes to pass through the kernel.
Example
---
-20
View File
@@ -1,20 +0,0 @@
Import('env', 'common', 'msgq')
cereal_dir = Dir('.')
gen_dir = Dir('gen')
# Build cereal
schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp']
env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files],
schema_files,
f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
cereal = env.Library('cereal', [f'gen/cpp/{s}.c++' for s in schema_files])
# Build messaging
services_h = env.Command(['services.h'], ['services.py'], 'python3 ' + cereal_dir.path + '/services.py > $TARGET')
env.Program('messaging/bridge', ['messaging/bridge.cc', 'messaging/msgq_to_zmq.cc'], LIBS=[msgq, common, 'pthread'])
socketmaster = env.Library('socketmaster', ['messaging/socketmaster.cc'])
Export('cereal', 'socketmaster')
+5 -6
View File
@@ -1,11 +1,10 @@
# pylint: skip-file
import os
import capnp
from importlib.resources import as_file, files
CEREAL_PATH = os.path.dirname(os.path.abspath(__file__))
capnp.remove_import_hook()
with as_file(files("cereal")) as fspath:
CEREAL_PATH = fspath.as_posix()
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
custom = capnp.load(os.path.join(CEREAL_PATH, "custom.capnp"))
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
custom = capnp.load(os.path.join(CEREAL_PATH, "custom.capnp"))
-1
View File
@@ -1 +0,0 @@
../opendbc_repo/opendbc/car/car.capnp
+689
View File
@@ -0,0 +1,689 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
@0x8e2af1e708af8b8d;
# ******* events causing controls state machine transition *******
struct CarEvent @0x9b1657f34caf3ad3 {
name @0 :EventName;
# event types
enable @1 :Bool;
noEntry @2 :Bool;
warning @3 :Bool; # alerts presented only when enabled or soft disabling
userDisable @4 :Bool;
softDisable @5 :Bool;
immediateDisable @6 :Bool;
preEnable @7 :Bool;
permanent @8 :Bool; # alerts presented regardless of openpilot state
overrideLateral @10 :Bool;
overrideLongitudinal @9 :Bool;
enum EventName @0xbaa8c5d505f727de {
canError @0;
steerUnavailable @1;
wrongGear @4;
doorOpen @5;
seatbeltNotLatched @6;
espDisabled @7;
wrongCarMode @8;
steerTempUnavailable @9;
reverseGear @10;
buttonCancel @11;
buttonEnable @12;
pedalPressed @13; # exits active state
preEnableStandstill @73; # added during pre-enable state with brake
gasPressedOverride @108; # added when user is pressing gas with no disengage on gas
steerOverride @114;
cruiseDisabled @14;
speedTooLow @17;
outOfSpace @18;
overheat @19;
calibrationIncomplete @20;
calibrationInvalid @21;
calibrationRecalibrating @117;
controlsMismatch @22;
pcmEnable @23;
pcmDisable @24;
radarFault @26;
brakeHold @28;
parkBrake @29;
manualRestart @30;
lowSpeedLockout @31;
plannerError @32;
joystickDebug @34;
steerTempUnavailableSilent @35;
resumeRequired @36;
preDriverDistracted @37;
promptDriverDistracted @38;
driverDistracted @39;
preDriverUnresponsive @43;
promptDriverUnresponsive @44;
driverUnresponsive @45;
belowSteerSpeed @46;
lowBattery @48;
vehicleModelInvalid @50;
accFaulted @51;
sensorDataInvalid @52;
commIssue @53;
commIssueAvgFreq @109;
tooDistracted @54;
posenetInvalid @55;
soundsUnavailable @56;
preLaneChangeLeft @57;
preLaneChangeRight @58;
laneChange @59;
lowMemory @63;
stockAeb @64;
ldw @65;
carUnrecognized @66;
invalidLkasSetting @69;
speedTooHigh @70;
laneChangeBlocked @71;
relayMalfunction @72;
stockFcw @74;
startup @75;
startupNoCar @76;
startupNoControl @77;
startupMaster @78;
startupNoFw @104;
fcw @79;
steerSaturated @80;
belowEngageSpeed @84;
noGps @85;
wrongCruiseMode @87;
modeldLagging @89;
deviceFalling @90;
fanMalfunction @91;
cameraMalfunction @92;
cameraFrameRate @110;
gpsMalfunction @94;
processNotRunning @95;
dashcamMode @96;
controlsInitializing @98;
usbError @99;
roadCameraError @100;
driverCameraError @101;
wideRoadCameraError @102;
localizerMalfunction @103;
highCpuUsage @105;
cruiseMismatch @106;
lkasDisabled @107;
canBusMissing @111;
controlsdLagging @112;
resumeBlocked @113;
steerTimeLimit @115;
vehicleSensorsInvalid @116;
radarCanErrorDEPRECATED @15;
communityFeatureDisallowedDEPRECATED @62;
radarCommIssueDEPRECATED @67;
driverMonitorLowAccDEPRECATED @68;
gasUnavailableDEPRECATED @3;
dataNeededDEPRECATED @16;
modelCommIssueDEPRECATED @27;
ipasOverrideDEPRECATED @33;
geofenceDEPRECATED @40;
driverMonitorOnDEPRECATED @41;
driverMonitorOffDEPRECATED @42;
calibrationProgressDEPRECATED @47;
invalidGiraffeHondaDEPRECATED @49;
invalidGiraffeToyotaDEPRECATED @60;
internetConnectivityNeededDEPRECATED @61;
whitePandaUnsupportedDEPRECATED @81;
commIssueWarningDEPRECATED @83;
focusRecoverActiveDEPRECATED @86;
neosUpdateRequiredDEPRECATED @88;
modelLagWarningDEPRECATED @93;
startupOneplusDEPRECATED @82;
startupFuzzyFingerprintDEPRECATED @97;
noTargetDEPRECATED @25;
brakeUnavailableDEPRECATED @2;
}
}
# ******* main car state @ 100hz *******
# all speeds in m/s
struct CarState {
events @13 :List(CarEvent);
# CAN health
canValid @26 :Bool; # invalid counter/checksums
canTimeout @40 :Bool; # CAN bus dropped out
# car speed
vEgo @1 :Float32; # best estimate of speed
aEgo @16 :Float32; # best estimate of acceleration
vEgoRaw @17 :Float32; # unfiltered speed from CAN sensors
vEgoCluster @44 :Float32; # best estimate of speed shown on car's instrument cluster, used for UI
yawRate @22 :Float32; # best estimate of yaw rate
standstill @18 :Bool;
wheelSpeeds @2 :WheelSpeeds;
# gas pedal, 0.0-1.0
gas @3 :Float32; # this is user pedal only
gasPressed @4 :Bool; # this is user pedal only
engineRpm @46 :Float32;
# brake pedal, 0.0-1.0
brake @5 :Float32; # this is user pedal only
brakePressed @6 :Bool; # this is user pedal only
regenBraking @45 :Bool; # this is user pedal only
parkingBrake @39 :Bool;
brakeHoldActive @38 :Bool;
# steering wheel
steeringAngleDeg @7 :Float32;
steeringAngleOffsetDeg @37 :Float32; # Offset betweens sensors in case there multiple
steeringRateDeg @15 :Float32;
steeringTorque @8 :Float32; # TODO: standardize units
steeringTorqueEps @27 :Float32; # TODO: standardize units
steeringPressed @9 :Bool; # if the user is using the steering wheel
steerFaultTemporary @35 :Bool; # temporary EPS fault
steerFaultPermanent @36 :Bool; # permanent EPS fault
stockAeb @30 :Bool;
stockFcw @31 :Bool;
espDisabled @32 :Bool;
accFaulted @42 :Bool;
carFaultedNonCritical @47 :Bool; # some ECU is faulted, but car remains controllable
# cruise state
cruiseState @10 :CruiseState;
# gear
gearShifter @14 :GearShifter;
# button presses
buttonEvents @11 :List(ButtonEvent);
leftBlinker @20 :Bool;
rightBlinker @21 :Bool;
genericToggle @23 :Bool;
# lock info
doorOpen @24 :Bool;
seatbeltUnlatched @25 :Bool;
# clutch (manual transmission only)
clutchPressed @28 :Bool;
# blindspot sensors
leftBlindspot @33 :Bool; # Is there something blocking the left lane change
rightBlindspot @34 :Bool; # Is there something blocking the right lane change
fuelGauge @41 :Float32; # battery or fuel tank level from 0.0 to 1.0
charging @43 :Bool;
struct WheelSpeeds {
# optional wheel speeds
fl @0 :Float32;
fr @1 :Float32;
rl @2 :Float32;
rr @3 :Float32;
}
struct CruiseState {
enabled @0 :Bool;
speed @1 :Float32;
speedCluster @6 :Float32; # Set speed as shown on instrument cluster
available @2 :Bool;
speedOffset @3 :Float32;
standstill @4 :Bool;
nonAdaptive @5 :Bool;
}
enum GearShifter {
unknown @0;
park @1;
drive @2;
neutral @3;
reverse @4;
sport @5;
low @6;
brake @7;
eco @8;
manumatic @9;
}
# send on change
struct ButtonEvent {
pressed @0 :Bool;
type @1 :Type;
enum Type {
unknown @0;
leftBlinker @1;
rightBlinker @2;
accelCruise @3;
decelCruise @4;
cancel @5;
altButton1 @6;
altButton2 @7;
altButton3 @8;
setCruise @9;
resumeCruise @10;
gapAdjustCruise @11;
}
}
# deprecated
errorsDEPRECATED @0 :List(CarEvent.EventName);
brakeLightsDEPRECATED @19 :Bool;
steeringRateLimitedDEPRECATED @29 :Bool;
canMonoTimesDEPRECATED @12: List(UInt64);
}
# ******* radar state @ 20hz *******
struct RadarData @0x888ad6581cf0aacb {
errors @0 :List(Error);
points @1 :List(RadarPoint);
enum Error {
canError @0;
fault @1;
wrongConfig @2;
}
# similar to LiveTracks
# is one timestamp valid for all? I think so
struct RadarPoint {
trackId @0 :UInt64; # no trackId reuse
# these 3 are the minimum required
dRel @1 :Float32; # m from the front bumper of the car
yRel @2 :Float32; # m
vRel @3 :Float32; # m/s
# these are optional and valid if they are not NaN
aRel @4 :Float32; # m/s^2
yvRel @5 :Float32; # m/s
# some radars flag measurements VS estimates
measured @6 :Bool;
}
# deprecated
canMonoTimesDEPRECATED @2 :List(UInt64);
}
# ******* car controls @ 100hz *******
struct CarControl {
# must be true for any actuator commands to work
enabled @0 :Bool;
latActive @11: Bool;
longActive @12: Bool;
# Actuator commands as computed by controlsd
actuators @6 :Actuators;
leftBlinker @15: Bool;
rightBlinker @16: Bool;
# Any car specific rate limits or quirks applied by
# the CarController are reflected in actuatorsOutput
# and matches what is sent to the car
actuatorsOutput @10 :Actuators;
orientationNED @13 :List(Float32);
angularVelocity @14 :List(Float32);
cruiseControl @4 :CruiseControl;
hudControl @5 :HUDControl;
struct Actuators {
# range from 0.0 - 1.0
gas @0: Float32;
brake @1: Float32;
# range from -1.0 - 1.0
steer @2: Float32;
# value sent over can to the car
steerOutputCan @8: Float32;
steeringAngleDeg @3: Float32;
curvature @7: Float32;
speed @6: Float32; # m/s
accel @4: Float32; # m/s^2
longControlState @5: LongControlState;
enum LongControlState @0xe40f3a917d908282{
off @0;
pid @1;
stopping @2;
starting @3;
}
}
struct CruiseControl {
cancel @0: Bool;
resume @1: Bool;
override @4: Bool;
speedOverrideDEPRECATED @2: Float32;
accelOverrideDEPRECATED @3: Float32;
}
struct HUDControl {
speedVisible @0: Bool;
setSpeed @1: Float32;
lanesVisible @2: Bool;
leadVisible @3: Bool;
visualAlert @4: VisualAlert;
audibleAlert @5: AudibleAlert;
rightLaneVisible @6: Bool;
leftLaneVisible @7: Bool;
rightLaneDepart @8: Bool;
leftLaneDepart @9: Bool;
enum VisualAlert {
# these are the choices from the Honda
# map as good as you can for your car
none @0;
fcw @1;
steerRequired @2;
brakePressed @3;
wrongGear @4;
seatbeltUnbuckled @5;
speedTooHigh @6;
ldw @7;
}
enum AudibleAlert {
none @0;
engage @1;
disengage @2;
refuse @3;
warningSoft @4;
warningImmediate @5;
prompt @6;
promptRepeat @7;
promptDistracted @8;
}
}
gasDEPRECATED @1 :Float32;
brakeDEPRECATED @2 :Float32;
steeringTorqueDEPRECATED @3 :Float32;
activeDEPRECATED @7 :Bool;
rollDEPRECATED @8 :Float32;
pitchDEPRECATED @9 :Float32;
}
# ****** car param ******
struct CarParams {
carName @0 :Text;
carFingerprint @1 :Text;
fuzzyFingerprint @55 :Bool;
notCar @66 :Bool; # flag for non-car robotics platforms
enableGasInterceptor @2 :Bool;
pcmCruise @3 :Bool; # is openpilot's state tied to the PCM's cruise state?
enableDsu @5 :Bool; # driving support unit
enableBsm @56 :Bool; # blind spot monitoring
flags @64 :UInt32; # flags for car specific quirks
experimentalLongitudinalAvailable @71 :Bool;
minEnableSpeed @7 :Float32;
minSteerSpeed @8 :Float32;
safetyConfigs @62 :List(SafetyConfig);
alternativeExperience @65 :Int16; # panda flag for features like no disengage on gas
# Car docs fields
maxLateralAccel @68 :Float32;
autoResumeSng @69 :Bool; # describes whether car can resume from a stop automatically
# things about the car in the manual
mass @17 :Float32; # [kg] curb weight: all fluids no cargo
wheelbase @18 :Float32; # [m] distance from rear axle to front axle
centerToFront @19 :Float32; # [m] distance from center of mass to front axle
steerRatio @20 :Float32; # [] ratio of steering wheel angle to front wheel angle
steerRatioRear @21 :Float32; # [] ratio of steering wheel angle to rear wheel angle (usually 0)
# things we can derive
rotationalInertia @22 :Float32; # [kg*m2] body rotational inertia
tireStiffnessFactor @72 :Float32; # scaling factor used in calculating tireStiffness[Front,Rear]
tireStiffnessFront @23 :Float32; # [N/rad] front tire coeff of stiff
tireStiffnessRear @24 :Float32; # [N/rad] rear tire coeff of stiff
longitudinalTuning @25 :LongitudinalPIDTuning;
lateralParams @48 :LateralParams;
lateralTuning :union {
pid @26 :LateralPIDTuning;
indi @27 :LateralINDITuning;
lqr @40 :LateralLQRTuning;
torque @67 :LateralTorqueTuning;
}
steerLimitAlert @28 :Bool;
steerLimitTimer @47 :Float32; # time before steerLimitAlert is issued
vEgoStopping @29 :Float32; # Speed at which the car goes into stopping state
vEgoStarting @59 :Float32; # Speed at which the car goes into starting state
stoppingControl @31 :Bool; # Does the car allow full control even at lows speeds when stopping
steerControlType @34 :SteerControlType;
radarUnavailable @35 :Bool; # True when radar objects aren't visible on CAN or aren't parsed out
stopAccel @60 :Float32; # Required acceleration to keep vehicle stationary
stoppingDecelRate @52 :Float32; # m/s^2/s while trying to stop
startAccel @32 :Float32; # Required acceleration to get car moving
startingState @70 :Bool; # Does this car make use of special starting state
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
longitudinalActuatorDelayLowerBound @61 :Float32; # Gas/Brake actuator delay in seconds, lower bound
longitudinalActuatorDelayUpperBound @58 :Float32; # Gas/Brake actuator delay in seconds, upper bound
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
carVin @38 :Text; # VIN number queried during fingerprinting
dashcamOnly @41: Bool;
transmissionType @43 :TransmissionType;
carFw @44 :List(CarFw);
radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
fingerprintSource @49: FingerprintSource;
networkLocation @50 :NetworkLocation; # Where Panda/C2 is integrated into the car's CAN network
wheelSpeedFactor @63 :Float32; # Multiplier on wheels speeds to computer actual speeds
struct SafetyConfig {
safetyModel @0 :SafetyModel;
safetyParam @3 :UInt16;
safetyParamDEPRECATED @1 :Int16;
safetyParam2DEPRECATED @2 :UInt32;
}
struct LateralParams {
torqueBP @0 :List(Int32);
torqueV @1 :List(Int32);
}
struct LateralPIDTuning {
kpBP @0 :List(Float32);
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
kf @4 :Float32;
}
struct LateralTorqueTuning {
useSteeringAngle @0 :Bool;
kp @1 :Float32;
ki @2 :Float32;
friction @3 :Float32;
kf @4 :Float32;
steeringAngleDeadzoneDeg @5 :Float32;
latAccelFactor @6 :Float32;
latAccelOffset @7 :Float32;
}
struct LongitudinalPIDTuning {
kpBP @0 :List(Float32);
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
kf @6 :Float32;
deadzoneBP @4 :List(Float32);
deadzoneV @5 :List(Float32);
}
struct LateralINDITuning {
outerLoopGainBP @4 :List(Float32);
outerLoopGainV @5 :List(Float32);
innerLoopGainBP @6 :List(Float32);
innerLoopGainV @7 :List(Float32);
timeConstantBP @8 :List(Float32);
timeConstantV @9 :List(Float32);
actuatorEffectivenessBP @10 :List(Float32);
actuatorEffectivenessV @11 :List(Float32);
outerLoopGainDEPRECATED @0 :Float32;
innerLoopGainDEPRECATED @1 :Float32;
timeConstantDEPRECATED @2 :Float32;
actuatorEffectivenessDEPRECATED @3 :Float32;
}
struct LateralLQRTuning {
scale @0 :Float32;
ki @1 :Float32;
dcGain @2 :Float32;
# State space system
a @3 :List(Float32);
b @4 :List(Float32);
c @5 :List(Float32);
k @6 :List(Float32); # LQR gain
l @7 :List(Float32); # Kalman gain
}
enum SafetyModel {
silent @0;
hondaNidec @1;
toyota @2;
elm327 @3;
gm @4;
hondaBoschGiraffe @5;
ford @6;
cadillac @7;
hyundai @8;
chrysler @9;
tesla @10;
subaru @11;
gmPassive @12;
mazda @13;
nissan @14;
volkswagen @15;
toyotaIpas @16;
allOutput @17;
gmAscm @18;
noOutput @19; # like silent but without silent CAN TXs
hondaBosch @20;
volkswagenPq @21;
subaruPreglobal @22; # pre-Global platform
hyundaiLegacy @23;
hyundaiCommunity @24;
volkswagenMlb @25;
hongqi @26;
body @27;
hyundaiCanfd @28;
volkswagenMqbEvo @29;
}
enum SteerControlType {
torque @0;
angle @1;
curvatureDEPRECATED @2;
}
enum TransmissionType {
unknown @0;
automatic @1; # Traditional auto, including DSG
manual @2; # True "stick shift" only
direct @3; # Electric vehicle or other direct drive
cvt @4;
}
struct CarFw {
ecu @0 :Ecu;
fwVersion @1 :Data;
address @2 :UInt32;
subAddress @3 :UInt8;
responseAddress @4 :UInt32;
request @5 :List(Data);
brand @6 :Text;
bus @7 :UInt8;
logging @8 :Bool;
obdMultiplexing @9 :Bool;
}
enum Ecu {
eps @0;
abs @1;
fwdRadar @2;
fwdCamera @3;
engine @4;
unknown @5;
transmission @8; # Transmission Control Module
hybrid @18; # hybrid control unit, e.g. Chrysler's HCP, Honda's IMA Control Unit, Toyota's hybrid control computer
srs @9; # airbag
gateway @10; # can gateway
hud @11; # heads up display
combinationMeter @12; # instrument cluster
electricBrakeBooster @15;
shiftByWire @16;
adas @19;
cornerRadar @21;
hvac @20;
parkingAdas @7; # parking assist system ECU, e.g. Toyota's IPAS, Hyundai's RSPA, etc.
epb @22; # electronic parking brake
telematics @23;
body @24; # body control module
# Toyota only
dsu @6;
# Honda only
vsa @13; # Vehicle Stability Assist
programmedFuelInjection @14;
debug @17;
}
enum FingerprintSource {
can @0;
fw @1;
fixed @2;
}
enum NetworkLocation {
fwdCamera @0; # Standard/default integration at LKAS camera
gateway @1; # Integration at vehicle's CAN gateway
}
enableCameraDEPRECATED @4 :Bool;
enableApgsDEPRECATED @6 :Bool;
steerRateCostDEPRECATED @33 :Float32;
isPandaBlackDEPRECATED @39 :Bool;
hasStockCameraDEPRECATED @57 :Bool;
safetyParamDEPRECATED @10 :Int16;
safetyModelDEPRECATED @9 :SafetyModel;
safetyModelPassiveDEPRECATED @42 :SafetyModel = silent;
minSpeedCanDEPRECATED @51 :Float32;
communityFeatureDEPRECATED @46: Bool;
startingAccelRateDEPRECATED @53 :Float32;
steerMaxBPDEPRECATED @11 :List(Float32);
steerMaxVDEPRECATED @12 :List(Float32);
gasMaxBPDEPRECATED @13 :List(Float32);
gasMaxVDEPRECATED @14 :List(Float32);
brakeMaxBPDEPRECATED @15 :List(Float32);
brakeMaxVDEPRECATED @16 :List(Float32);
directAccelControlDEPRECATED @30 :Bool;
maxSteeringAngleDegDEPRECATED @54 :Float32;
}
+78 -120
View File
@@ -7,104 +7,92 @@ $Cxx.namespace("cereal");
# These structs are guaranteed to remain reserved and empty in mainline
# cereal, so use these if you want custom events in your fork.
# DO rename the structs
# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)
# you can rename the struct, but don't change the identifier
struct LiveMapData @0x81c2f05a394cf4af {
speedLimitValid @0 :Bool;
speedLimit @1 :Float32;
speedLimitAheadValid @2 :Bool;
speedLimitAhead @3 :Float32;
speedLimitAheadDistance @4 :Float32;
turnSpeedLimitValid @5 :Bool;
turnSpeedLimit @6 :Float32;
turnSpeedLimitEndDistance @7 :Float32;
turnSpeedLimitSign @8 :Int16;
turnSpeedLimitsAhead @9 :List(Float32);
turnSpeedLimitsAheadDistances @10 :List(Float32);
turnSpeedLimitsAheadSigns @11 :List(Int16);
lastGpsTimestamp @12 :Int64; # Milliseconds since January 1, 1970.
currentRoadName @13 :Text;
lastGpsLatitude @14 :Float64;
lastGpsLongitude @15 :Float64;
lastGpsSpeed @16 :Float32;
lastGpsBearingDeg @17 :Float32;
lastGpsAccuracy @18 :Float32;
lastGpsBearingAccuracyDeg @19 :Float32;
}
struct ControlsStateExt @0x81c2f05a394cf4af {
struct LongitudinalPlanExt @0xaedffd8f31e7b55d {
visionTurnControllerState @0 :VisionTurnControllerState;
visionTurnSpeed @1 :Float32;
speedLimitControlState @2 :SpeedLimitControlState;
speedLimit @3 :Float32;
speedLimitOffset @4 :Float32;
distToSpeedLimit @5 :Float32;
isMapSpeedLimit @6 :Bool;
speedLimitPercOffset @7 :Bool;
speedLimitValueOffset @8 :Float32;
distToTurn @9 :Float32;
turnSpeed @10 :Float32;
turnSpeedControlState @11 :SpeedLimitControlState;
turnSign @12 :Int16;
dpE2EIsBlended @13 :Bool;
longitudinalPlanExtSource @14 :LongitudinalPlanExtSource;
enum LongitudinalPlanExtSource {
cruise @0;
lead0 @1;
lead1 @2;
lead2 @3;
e2e @4;
turn @5;
limit @6;
turnlimit @7;
}
enum SpeedLimitControlState {
inactive @0; # No speed limit set or not enabled by parameter.
tempInactive @1; # User wants to ignore speed limit until it changes.
adapting @2; # Reducing speed to match new speed limit.
active @3; # Cruising at speed limit.
}
enum VisionTurnControllerState {
disabled @0; # No predicted substancial turn on vision range or feature disabled.
entering @1; # A subsantial turn is predicted ahead, adapting speed to turn confort levels.
turning @2; # Actively turning. Managing acceleration to provide a roll on turn feeling.
leaving @3; # Road ahead straightens. Start to allow positive acceleration.
}
}
struct LateralPlanExt @0xf35cc4560bbf6ec2 {
dPathWLinesX @0 :List(Float32);
dPathWLinesY @1 :List(Float32);
}
struct ControlsStateExt @0xda96579883444c35 {
alkaActive @0 :Bool;
alkaEnabled @1 :Bool;
}
struct CarStateExt @0xaedffd8f31e7b55d {
# dp - ALKA: lkasOn state from carstate (mirrors panda's lkas_on)
lkasOn @0 :Bool;
struct CustomReserved4 @0x80ae746ee2596b11 {
}
struct ModelExt @0xf35cc4560bbf6ec2 {
leftEdgeDetected @0 :Bool;
rightEdgeDetected @1 :Bool;
struct CustomReserved5 @0xa5cd762cd951a455 {
}
struct LiveGPS @0xda96579883444c35 {
# Position
latitude @0 :Float64; # degrees
longitude @1 :Float64; # degrees
altitude @2 :Float64; # meters (WGS84)
# Motion
speed @3 :Float32; # m/s (horizontal speed)
bearingDeg @4 :Float32; # degrees (heading)
# Accuracy
horizontalAccuracy @5 :Float32; # meters
verticalAccuracy @6 :Float32; # meters
# Status
gpsOK @7 :Bool; # livePose valid + GPS fresh
status @8 :Status;
enum Status {
uninitialized @0; # no GPS data yet
uncalibrated @1; # has GPS but fusion not ready (raw passthrough)
valid @2; # fusion active with calibrated bearing
}
# Metadata
unixTimestampMillis @9 :Int64;
lastGpsTimestamp @10 :UInt64; # logMonoTime of last GPS
# livePose health (for debugging fusion issues)
livePoseOk @11 :Bool; # livePose valid and providing orientation/velocity
}
struct MaaControl @0x80ae746ee2596b11 {
# Map-Aware Assist control signals
# Curvature data (for lateral control)
curvature @0 :Float32; # current nav curvature (1/m)
curvatureValid @1 :Bool; # curvature data is valid
# Turn speed data (for longitudinal control)
turnSpeedLimit @2 :Float32; # target speed for turn (m/s)
turnDistance @3 :Float32; # distance to turn (m)
turnDirection @4 :TurnDirection;
turnValid @5 :Bool; # turn data is valid
maneuverType @6 :ManeuverType; # type of maneuver (turn vs lane change)
turnAngle @7 :Float32; # expected turn angle in degrees (positive=left, negative=right)
turnCurvature @8 :Float32; # curvature at turn point (1/m), used for speed limit calc
# Turn execution (heading-based tracking)
desireActive @9 :Bool; # true when turn desire should be sent to model
turnState @10 :UInt8; # TurnState enum: 0=none, 1=approaching, 2=executing, 3=complete
turnProgress @11 :Float32; # accumulated heading change during turn (degrees)
# Driver acknowledgment (blinker = commit to turn)
driverAcknowledged @12 :Bool; # driver turned on blinker matching turn direction
speedLimitActive @13 :Bool; # turn speed limit should be enforced (blinker on)
blockLaneChange @14 :Bool; # within commit distance, block lane change desire
enum TurnDirection {
none @0;
left @1;
right @2;
}
enum ManeuverType {
none @0;
turn @1; # intersection turn - use turnLeft/Right desire
laneChange @2; # highway exit/fork - use laneChangeLeft/Right desire
}
}
struct DashyState @0xa5cd762cd951a455 {
# Pre-serialized JSON bytes for dashy UI
# Aggregates all topics needed by dashy into single message
json @0 :Data;
}
struct NavInstructionExt @0xf98d843bfd7004a3 {
# Extension fields for NavInstruction (not in upstream)
turnAngle @0 :Float32; # degrees, positive=left, negative=right
turnCurvature @1 :Float32; # 1/m, positive=left, negative=right
struct CustomReserved6 @0xf98d843bfd7004a3 {
}
struct CustomReserved7 @0xb86e6369214c01c8 {
@@ -115,33 +103,3 @@ struct CustomReserved8 @0xf416ec09499d9d19 {
struct CustomReserved9 @0xa1680744031fdb2d {
}
struct CustomReserved10 @0xcb9fd56c7057593a {
}
struct CustomReserved11 @0xc2243c65e0340384 {
}
struct CustomReserved12 @0x9ccdc8676701b412 {
}
struct CustomReserved13 @0xcd96dafb67a082d0 {
}
struct CustomReserved14 @0xb057204d7deadf3f {
}
struct CustomReserved15 @0xbd443b539493bc68 {
}
struct CustomReserved16 @0xfc6241ed8877b611 {
}
struct CustomReserved17 @0xa30662f84033036c {
}
struct CustomReserved18 @0xc86a3d38d13eb3ef {
}
struct CustomReserved19 @0xa4f1eb3323f5f582 {
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
rm -r gen/ts
rm -r gen/js
mkdir gen/ts
mkdir gen/js
echo "Installing needed npm modules"
npm i capnpc-ts capnp-ts
capnpc -o node_modules/.bin/capnpc-ts:gen/ts log.capnp car.capnp
capnpc -o node_modules/.bin/capnpc-ts:gen/ts car.capnp
cat log.capnp | egrep '\([a-zA-Z]*\.[^\s]+\.[^s]+\)' | sed 's/^.*([a-zA-Z]*\.\([a-zA-Z.]*\)).*/\1/' | while read line
do
TOKEN=`echo $line | sed 's/\./_/g'`
ROOT=`echo $line | sed 's/\..*$//g'`
cat gen/ts/log.capnp.ts | grep '^import.*'${TOKEN}
if [[ "$?" == "1" ]]
then
sed -i 's/^\(import {.*\)'${ROOT}'\(,*\) \(.*\)$/\1'${ROOT}', '${TOKEN}'\2 \3/' ./gen/ts/log.capnp.ts
fi
done
tsc ./gen/ts/* --lib es2015 --outDir ./gen/js
BIN
View File
Binary file not shown.
+164 -477
View File
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
@0xa086df597ef5d7a0;
# Geometry
struct Point {
x @0: Float64;
y @1: Float64;
z @2: Float64;
}
struct PolyLine {
points @0: List(Point);
}
# Map features
struct Lane {
id @0 :Text;
leftBoundary @1 :LaneBoundary;
rightBoundary @2 :LaneBoundary;
leftAdjacentId @3 :Text;
rightAdjacentId @4 :Text;
inboundIds @5 :List(Text);
outboundIds @6 :List(Text);
struct LaneBoundary {
polyLine @0 :PolyLine;
startHeading @1 :Float32; # WRT north
}
}
# Map tiles
struct TileSummary {
version @0 :Text;
updatedAt @1 :UInt64; # Millis since epoch
level @2 :UInt8;
x @3 :UInt16;
y @4 :UInt16;
}
struct MapTile {
summary @0 :TileSummary;
lanes @1 :List(Lane);
}
+10
View File
@@ -0,0 +1,10 @@
demo
bridge
test_runner
*.o
*.os
*.d
*.a
*.so
messaging_pyx.cpp
build/
+157 -130
View File
@@ -1,53 +1,49 @@
# must be built with scons
from msgq.ipc_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \
from .messaging_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \
set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event
from msgq.ipc_pyx import MultiplePublishersError, IpcError
from msgq import fake_event_handle, drain_sock_raw
import msgq
from .messaging_pyx import MultiplePublishersError, MessagingError
import os
import capnp
import time
from typing import Optional, List, Union, Dict
from typing import Optional, List, Union, Dict, Deque
from collections import deque
from cereal import log
from cereal.services import SERVICE_LIST
from openpilot.common.util import MovingAverage
assert MultiplePublishersError
assert MessagingError
assert toggle_fake_events
assert set_fake_prefix
assert get_fake_prefix
assert delete_fake_prefix
assert wait_for_one_event
NO_TRAVERSAL_LIMIT = 2**64-1
AVG_FREQ_HISTORY = 100
context = Context()
def pub_sock(endpoint: str) -> PubSocket:
service = SERVICE_LIST.get(endpoint)
segment_size = service.queue_size if service else 0
return msgq.pub_sock(endpoint, segment_size)
def fake_event_handle(endpoint: str, identifier: Optional[str] = None, override: bool = True, enable: bool = False) -> SocketEventHandle:
identifier = identifier or get_fake_prefix()
handle = SocketEventHandle(endpoint, identifier, override)
if override:
handle.enabled = enable
return handle
def sub_sock(endpoint: str, poller: Optional[Poller] = None, addr: str = "127.0.0.1",
conflate: bool = False, timeout: Optional[int] = None) -> SubSocket:
service = SERVICE_LIST.get(endpoint)
segment_size = service.queue_size if service else 0
return msgq.sub_sock(endpoint, poller=poller, addr=addr, conflate=conflate,
timeout=timeout, segment_size=segment_size)
def log_from_bytes(dat: bytes) -> capnp.lib.capnp._DynamicStructReader:
return log.Event.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT)
def reset_context():
msgq.context = Context()
def log_from_bytes(dat: bytes, struct: capnp.lib.capnp._StructModule = log.Event) -> capnp.lib.capnp._DynamicStructReader:
with struct.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT) as msg:
return msg
def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) -> capnp.lib.capnp._DynamicStructBuilder:
args = {
'valid': False,
'logMonoTime': int(time.monotonic() * 1e9),
**kwargs
}
dat = log.Event.new_message(**args)
def new_message(service: Optional[str] = None, size: Optional[int] = None) -> capnp.lib.capnp._DynamicStructBuilder:
dat = log.Event.new_message()
dat.logMonoTime = int(time.monotonic() * 1e9)
dat.valid = True
if service is not None:
if size is None:
dat.init(service)
@@ -56,10 +52,58 @@ def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) ->
return dat
def pub_sock(endpoint: str) -> PubSocket:
sock = PubSocket()
sock.connect(context, endpoint)
return sock
def sub_sock(endpoint: str, poller: Optional[Poller] = None, addr: str = "127.0.0.1",
conflate: bool = False, timeout: Optional[int] = None) -> SubSocket:
sock = SubSocket()
sock.connect(context, endpoint, addr.encode('utf8'), conflate)
if timeout is not None:
sock.setTimeout(timeout)
if poller is not None:
poller.registerSocket(sock)
return sock
def drain_sock_raw(sock: SubSocket, wait_for_one: bool = False) -> List[bytes]:
"""Receive all message currently available on the queue"""
ret: List[bytes] = []
while 1:
if wait_for_one and len(ret) == 0:
dat = sock.receive()
else:
dat = sock.receive(non_blocking=True)
if dat is None:
break
ret.append(dat)
return ret
def drain_sock(sock: SubSocket, wait_for_one: bool = False) -> List[capnp.lib.capnp._DynamicStructReader]:
"""Receive all message currently available on the queue"""
msgs = drain_sock_raw(sock, wait_for_one=wait_for_one)
return [log_from_bytes(m) for m in msgs]
ret: List[capnp.lib.capnp._DynamicStructReader] = []
while 1:
if wait_for_one and len(ret) == 0:
dat = sock.receive()
else:
dat = sock.receive(non_blocking=True)
if dat is None: # Timeout hit
break
dat = log_from_bytes(dat)
ret.append(dat)
return ret
# TODO: print when we drop packets?
@@ -69,14 +113,14 @@ def recv_sock(sock: SubSocket, wait: bool = False) -> Optional[capnp.lib.capnp._
while 1:
if wait and dat is None:
recv = sock.receive()
rcv = sock.receive()
else:
recv = sock.receive(non_blocking=True)
rcv = sock.receive(non_blocking=True)
if recv is None: # Timeout hit
if rcv is None: # Timeout hit
break
dat = recv
dat = rcv
if dat is not None:
dat = log_from_bytes(dat)
@@ -106,104 +150,54 @@ def recv_one_retry(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader:
return log_from_bytes(dat)
class FrequencyTracker:
def __init__(self, service_freq: float, update_freq: float, is_poll: bool):
freq = max(min(service_freq, update_freq), 1.)
if is_poll:
min_freq = max_freq = freq
else:
max_freq = min(freq, update_freq)
if service_freq >= 2 * update_freq:
min_freq = update_freq
elif update_freq >= 2* service_freq:
min_freq = freq
else:
min_freq = min(freq, freq / 2.)
self.min_freq = min_freq * 0.8
self.max_freq = max_freq * 1.2
self.avg_dt = MovingAverage(int(10 * freq))
self.recent_avg_dt = MovingAverage(int(freq))
self.prev_time = 0.0
def record_recv_time(self, cur_time: float) -> None:
# TODO: Handle case where cur_time is less than prev_time
if self.prev_time > 1e-5:
dt = cur_time - self.prev_time
self.avg_dt.add_value(dt)
self.recent_avg_dt.add_value(dt)
self.prev_time = cur_time
@property
def valid(self) -> bool:
if self.avg_dt.count == 0:
return False
avg_freq = 1.0 / self.avg_dt.get_average()
if self.min_freq <= avg_freq <= self.max_freq:
return True
avg_freq_recent = 1.0 / self.recent_avg_dt.get_average()
return self.min_freq <= avg_freq_recent <= self.max_freq
class SubMaster:
def __init__(self, services: List[str], poll: Optional[str] = None,
def __init__(self, services: List[str], poll: Optional[List[str]] = None,
ignore_alive: Optional[List[str]] = None, ignore_avg_freq: Optional[List[str]] = None,
ignore_valid: Optional[List[str]] = None, addr: str = "127.0.0.1", frequency: Optional[float] = None):
addr: str = "127.0.0.1"):
self.frame = -1
self.services = services
self.seen = {s: False for s in services}
self.updated = {s: False for s in services}
self.recv_time = {s: 0. for s in services}
self.recv_frame = {s: 0 for s in services}
self.rcv_time = {s: 0. for s in services}
self.rcv_frame = {s: 0 for s in services}
self.alive = {s: False for s in services}
self.freq_ok = {s: False for s in services}
self.recv_dts: Dict[str, Deque[float]] = {s: deque(maxlen=AVG_FREQ_HISTORY) for s in services}
self.sock = {}
self.freq = {}
self.data = {}
self.logMonoTime = {s: 0 for s in services}
self.valid = {}
self.logMonoTime = {}
# zero-frequency / on-demand services are always alive and presumed valid; all others must pass checks
on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in services}
self.static_freq_services = set(s for s in services if not on_demand[s])
self.alive = {s: on_demand[s] for s in services}
self.freq_ok = {s: on_demand[s] for s in services}
self.valid = {s: on_demand[s] for s in services}
self.freq_tracker: Dict[str, FrequencyTracker] = {}
self.poller = Poller()
polled_services = set([poll, ] if poll is not None else services)
self.non_polled_services = set(services) - polled_services
self.non_polled_services = [s for s in services if poll is not None and
len(poll) and s not in poll]
self.ignore_average_freq = [] if ignore_avg_freq is None else ignore_avg_freq
self.ignore_alive = [] if ignore_alive is None else ignore_alive
self.ignore_valid = [] if ignore_valid is None else ignore_valid
self.simulation = bool(int(os.getenv("SIMULATION", "0")))
# if freq and poll aren't specified, assume the max to be conservative
assert frequency is None or poll is None, "Do not specify 'frequency' - frequency of the polled service will be used."
self.update_freq = frequency or max([SERVICE_LIST[s].frequency for s in polled_services])
for s in services:
p = self.poller if s not in self.non_polled_services else None
self.sock[s] = sub_sock(s, poller=p, addr=addr, conflate=True)
if addr is not None:
p = self.poller if s not in self.non_polled_services else None
self.sock[s] = sub_sock(s, poller=p, addr=addr, conflate=True)
self.freq[s] = SERVICE_LIST[s].frequency
try:
data = new_message(s)
except capnp.lib.capnp.KjException:
except capnp.lib.capnp.KjException: # pylint: disable=c-extension-no-member
data = new_message(s, 0) # lists
self.data[s] = getattr(data.as_reader(), s)
self.freq_tracker[s] = FrequencyTracker(SERVICE_LIST[s].frequency, self.update_freq, s == poll)
self.data[s] = getattr(data, s)
self.logMonoTime[s] = 0
self.valid[s] = data.valid
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
return self.data[s]
def _check_avg_freq(self, s: str) -> bool:
return SERVICE_LIST[s].frequency > 0.99 and (s not in self.ignore_average_freq) and (s not in self.ignore_alive)
def _check_avg_freq(self, s):
return self.rcv_time[s] > 1e-5 and self.freq[s] > 1e-5 and (s not in self.non_polled_services) \
and (s not in self.ignore_average_freq)
def update(self, timeout: int = 100) -> None:
def update(self, timeout: int = 1000) -> None:
msgs = []
for sock in self.poller.poll(timeout):
msgs.append(recv_one_or_none(sock))
@@ -215,38 +209,70 @@ class SubMaster:
def update_msgs(self, cur_time: float, msgs: List[capnp.lib.capnp._DynamicStructReader]) -> None:
self.frame += 1
self.updated = dict.fromkeys(self.services, False)
self.updated = dict.fromkeys(self.updated, False)
for msg in msgs:
if msg is None:
continue
s = msg.which()
self.seen[s] = True
self.updated[s] = True
self.freq_tracker[s].record_recv_time(cur_time)
self.recv_time[s] = cur_time
self.recv_frame[s] = self.frame
if self._check_avg_freq(s):
self.recv_dts[s].append(cur_time - self.rcv_time[s])
self.rcv_time[s] = cur_time
self.rcv_frame[s] = self.frame
self.data[s] = getattr(msg, s)
self.logMonoTime[s] = msg.logMonoTime
self.valid[s] = msg.valid
for s in self.static_freq_services:
# alive if delay is within 10x the expected frequency; checks relaxed in simulator
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency) or (self.seen[s] and self.simulation)
self.freq_ok[s] = self.freq_tracker[s].valid or self.simulation
if self.simulation:
self.freq_ok[s] = True
self.alive[s] = True
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
return all(self.alive[s] for s in (service_list or self.services) if s not in self.ignore_alive)
if not self.simulation:
for s in self.data:
# arbitrary small number to avoid float comparison. If freq is 0, we can skip the check
if self.freq[s] > 1e-5:
# alive if delay is within 10x the expected frequency
self.alive[s] = (cur_time - self.rcv_time[s]) < (10. / self.freq[s])
def all_freq_ok(self, service_list: Optional[List[str]] = None) -> bool:
return all(self.freq_ok[s] for s in (service_list or self.services) if self._check_avg_freq(s))
# TODO: check if update frequency is high enough to not drop messages
# freq_ok if average frequency is higher than 90% of expected frequency
if self._check_avg_freq(s):
if len(self.recv_dts[s]) > 0:
avg_dt = sum(self.recv_dts[s]) / len(self.recv_dts[s])
expected_dt = 1 / (self.freq[s] * 0.90)
self.freq_ok[s] = (avg_dt < expected_dt)
else:
self.freq_ok[s] = False
else:
self.freq_ok[s] = True
else:
self.freq_ok[s] = True
self.alive[s] = True
def all_valid(self, service_list: Optional[List[str]] = None) -> bool:
return all(self.valid[s] for s in (service_list or self.services) if s not in self.ignore_valid)
def all_alive(self, service_list=None) -> bool:
if service_list is None: # check all
service_list = self.alive.keys()
return all(self.alive[s] for s in service_list if s not in self.ignore_alive)
def all_checks(self, service_list: Optional[List[str]] = None) -> bool:
return self.all_alive(service_list) and self.all_freq_ok(service_list) and self.all_valid(service_list)
def all_freq_ok(self, service_list=None) -> bool:
if service_list is None: # check all
service_list = self.alive.keys()
return all(self.freq_ok[s] for s in service_list if s not in self.ignore_alive)
def all_valid(self, service_list=None) -> bool:
if service_list is None: # check all
service_list = self.valid.keys()
return all(self.valid[s] for s in service_list)
def all_checks(self, service_list=None) -> bool:
if service_list is None: # check all
service_list = self.alive.keys()
return self.all_alive(service_list=service_list) \
and self.all_freq_ok(service_list=service_list) \
and self.all_valid(service_list=service_list)
class PubMaster:
@@ -260,7 +286,8 @@ class PubMaster:
dat = dat.to_bytes()
self.sock[s].send(dat)
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
def wait_for_readers_to_update(self, s: str, timeout: int) -> bool:
dt = 0.05
for _ in range(int(timeout*(1./dt))):
if self.sock[s].all_readers_updated():
return True
Binary file not shown.
+29
View File
@@ -0,0 +1,29 @@
import time
from messaging_pyx import Context, Poller, SubSocket, PubSocket # pylint: disable=no-name-in-module, import-error
MSGS = 1e5
if __name__ == "__main__":
c = Context()
sub_sock = SubSocket()
pub_sock = PubSocket()
sub_sock.connect(c, "controlsState")
pub_sock.connect(c, "controlsState")
poller = Poller()
poller.registerSocket(sub_sock)
t = time.time()
for i in range(int(MSGS)):
bts = i.to_bytes(4, 'little')
pub_sock.send(bts)
for s in poller.poll(100):
dat = s.receive()
ii = int.from_bytes(dat, 'little')
assert(i == ii)
dt = time.time() - t
print("%.1f msg/s" % (MSGS / dt))
@@ -11,8 +11,8 @@
#include <fcntl.h>
#include <unistd.h>
#include "msgq/ipc.h"
#include "msgq/event.h"
#include "cereal/messaging/messaging.h"
#include "cereal/messaging/event.h"
template<typename TSubSocket>
class FakeSubSocket: public TSubSocket {
@@ -31,7 +31,7 @@ public:
}
}
int connect(Context *context, std::string endpoint, std::string address, bool conflate=false, bool check_endpoint=true, size_t segment_size=0) override {
int connect(Context *context, std::string endpoint, std::string address, bool conflate=false, bool check_endpoint=true) override {
const char* cereal_prefix = std::getenv("CEREAL_FAKE_PREFIX");
char* mem;
@@ -42,7 +42,7 @@ public:
this->recv_called = new Event(state->fds[EventPurpose::RECV_CALLED]);
this->recv_ready = new Event(state->fds[EventPurpose::RECV_READY]);
return TSubSocket::connect(context, endpoint, address, conflate, check_endpoint, segment_size);
return TSubSocket::connect(context, endpoint, address, conflate, check_endpoint);
}
Message *receive(bool non_blocking=false) override {
@@ -63,5 +63,5 @@ private:
public:
void registerSocket(SubSocket *socket) override;
std::vector<SubSocket*> poll(int timeout) override;
~FakePoller() {}
~FakePoller() {};
};
@@ -3,8 +3,8 @@
#include <string>
#include <vector>
#include "msgq/ipc.h"
#include "msgq/msgq.h"
#include "cereal/messaging/messaging.h"
#include "cereal/messaging/msgq.h"
#define MAX_POLLERS 128
@@ -36,7 +36,7 @@ private:
msgq_queue_t * q = NULL;
int timeout;
public:
int connect(Context *context, std::string endpoint, std::string address, bool conflate=false, bool check_endpoint=true, size_t segment_size=0);
int connect(Context *context, std::string endpoint, std::string address, bool conflate=false, bool check_endpoint=true);
void setTimeout(int timeout);
void * getRawSocket() {return (void*)q;}
Message *receive(bool non_blocking=false);
@@ -47,7 +47,7 @@ class MSGQPubSocket : public PubSocket {
private:
msgq_queue_t * q = NULL;
public:
int connect(Context *context, std::string endpoint, bool check_endpoint=true, size_t segment_size=0);
int connect(Context *context, std::string endpoint, bool check_endpoint=true);
int sendMessage(Message *message);
int send(char *data, size_t size);
bool all_readers_updated();
@@ -63,5 +63,5 @@ private:
public:
void registerSocket(SubSocket *socket);
std::vector<SubSocket*> poll(int timeout);
~MSGQPoller(){}
~MSGQPoller(){};
};
@@ -4,7 +4,7 @@
#include <string>
#include <vector>
#include "msgq/ipc.h"
#include "cereal/messaging/messaging.h"
#define MAX_POLLERS 128
@@ -35,7 +35,7 @@ private:
void * sock;
std::string full_endpoint;
public:
int connect(Context *context, std::string endpoint, std::string address, bool conflate=false, bool check_endpoint=true, size_t segment_size=0);
int connect(Context *context, std::string endpoint, std::string address, bool conflate=false, bool check_endpoint=true);
void setTimeout(int timeout);
void * getRawSocket() {return sock;}
Message *receive(bool non_blocking=false);
@@ -46,9 +46,8 @@ class ZMQPubSocket : public PubSocket {
private:
void * sock;
std::string full_endpoint;
int pid = -1;
public:
int connect(Context *context, std::string endpoint, bool check_endpoint=true, size_t segment_size=0);
int connect(Context *context, std::string endpoint, bool check_endpoint=true);
int sendMessage(Message *message);
int send(char *data, size_t size);
bool all_readers_updated();
@@ -64,5 +63,5 @@ private:
public:
void registerSocket(SubSocket *socket);
std::vector<SubSocket*> poll(int timeout);
~ZMQPoller(){}
~ZMQPoller(){};
};
+63 -3
View File
@@ -5,12 +5,69 @@
#include <string>
#include <vector>
#include <utility>
#include <time.h>
#include <capnp/serialize.h>
#include "cereal/gen/cpp/log.capnp.h"
#include "common/timing.h"
#include "msgq/ipc.h"
#ifdef __APPLE__
#define CLOCK_BOOTTIME CLOCK_MONOTONIC
#endif
#define MSG_MULTIPLE_PUBLISHERS 100
bool messaging_use_zmq();
class Context {
public:
virtual void * getRawContext() = 0;
static Context * create();
virtual ~Context(){}
};
class Message {
public:
virtual void init(size_t size) = 0;
virtual void init(char * data, size_t size) = 0;
virtual void close() = 0;
virtual size_t getSize() = 0;
virtual char * getData() = 0;
virtual ~Message(){};
};
class SubSocket {
public:
virtual int connect(Context *context, std::string endpoint, std::string address, bool conflate=false, bool check_endpoint=true) = 0;
virtual void setTimeout(int timeout) = 0;
virtual Message *receive(bool non_blocking=false) = 0;
virtual void * getRawSocket() = 0;
static SubSocket * create();
static SubSocket * create(Context * context, std::string endpoint, std::string address="127.0.0.1", bool conflate=false, bool check_endpoint=true);
virtual ~SubSocket(){};
};
class PubSocket {
public:
virtual int connect(Context *context, std::string endpoint, bool check_endpoint=true) = 0;
virtual int sendMessage(Message *message) = 0;
virtual int send(char *data, size_t size) = 0;
virtual bool all_readers_updated() = 0;
static PubSocket * create();
static PubSocket * create(Context * context, std::string endpoint, bool check_endpoint=true);
static PubSocket * create(Context * context, std::string endpoint, int port, bool check_endpoint=true);
virtual ~PubSocket(){};
};
class Poller {
public:
virtual void registerSocket(SubSocket *socket) = 0;
virtual std::vector<SubSocket*> poll(int timeout) = 0;
static Poller * create();
static Poller * create(std::vector<SubSocket*> sockets);
virtual ~Poller(){};
};
class SubMaster {
public:
@@ -46,7 +103,10 @@ public:
cereal::Event::Builder initEvent(bool valid = true) {
cereal::Event::Builder event = initRoot<cereal::Event>();
event.setLogMonoTime(nanos_since_boot());
struct timespec t;
clock_gettime(CLOCK_BOOTTIME, &t);
uint64_t current_time = t.tv_sec * 1000000000ULL + t.tv_nsec;
event.setLogMonoTime(current_time);
event.setValid(valid);
return event;
}
+68
View File
@@ -0,0 +1,68 @@
# distutils: language = c++
#cython: language_level=3
from libcpp.string cimport string
from libcpp.vector cimport vector
from libcpp cimport bool
cdef extern from "cereal/messaging/impl_fake.h":
cdef cppclass Event:
@staticmethod
int wait_for_one(vector[Event], int) except +
Event()
Event(int)
void set()
int clear()
void wait(int) except +
bool peek()
int fd()
cdef cppclass SocketEventHandle:
@staticmethod
void toggle_fake_events(bool)
@staticmethod
void set_fake_prefix(string)
@staticmethod
string fake_prefix()
SocketEventHandle(string, string, bool)
bool is_enabled()
void set_enabled(bool)
Event recv_called()
Event recv_ready()
cdef extern from "cereal/messaging/messaging.h":
cdef cppclass Context:
@staticmethod
Context * create()
cdef cppclass Message:
void init(size_t)
void init(char *, size_t)
void close()
size_t getSize()
char *getData()
cdef cppclass SubSocket:
@staticmethod
SubSocket * create()
int connect(Context *, string, string, bool)
Message * receive(bool)
void setTimeout(int)
cdef cppclass PubSocket:
@staticmethod
PubSocket * create()
int connect(Context *, string)
int sendMessage(Message *)
int send(char *, size_t)
bool all_readers_updated()
cdef cppclass Poller:
@staticmethod
Poller * create()
void registerSocket(SubSocket *)
vector[SubSocket*] poll(int) nogil
BIN
View File
Binary file not shown.
@@ -5,8 +5,8 @@
#include <string>
#include <atomic>
#define DEFAULT_SEGMENT_SIZE (1 * 1024 * 1024)
#define NUM_READERS 25
#define DEFAULT_SEGMENT_SIZE (10 * 1024 * 1024)
#define NUM_READERS 18 //default comma is 12
#define ALIGN(n) ((n + (8 - 1)) & -8)
#define UNUSED(x) (void)x
+54
View File
@@ -0,0 +1,54 @@
# MSGQ: A lock free single producer multi consumer message queue
## What is MSGQ?
MSGQ is a system to pass messages from a single producer to multiple consumers. All the consumers need to be able to receive all the messages. It is designed to be a high performance replacement for ZMQ-like SUB/PUB patterns. It uses a ring buffer in shared memory to efficiently read and write data. Each read requires a copy. Writing can be done without a copy, as long as the size of the data is known in advance.
## Storage
The storage for the queue consists of an area of metadata, and the actual buffer. The metadata contains:
1. A counter to the number of readers that are active
2. A pointer to the head of the queue for writing. From now on referred to as *write pointer*
3. A cycle counter for the writer. This counter is incremented when the writer wraps around
4. N pointers, pointing to the current read position for all the readers. From now on referred to as *read pointer*
5. N counters, counting the number of cycles for all the readers
6. N booleans, indicating validity for all the readers. From now on referred to as *validity flag*
The counter and the pointer are both 32 bit values, packed into 64 bit so they can be read and written atomically.
The data buffer is a ring buffer. All messages are prefixed by an 8 byte size field, followed by the data. A size of -1 indicates a wrap-around, and means the next message is stored at the beginning of the buffer.
## Writing
Writing involves the following steps:
1. Check if the area that is to be written overlaps with any of the read pointers, mark those readers as invalid by clearing the validity flag.
2. Write the message
3. Increase the write pointer by the size of the message
In case there is not enough space at the end of the buffer, a special empty message with a prefix of -1 is written. The cycle counter is incremented by one. In this case step 1 will check there are no read pointers pointing to the remainder of the buffer. Then another write cycle will start with the actual message.
There always needs to be 8 bytes of empty space at the end of the buffer. By doing this there is always space to write the -1.
## Reset reader
When the reader is lagging too much behind the read pointer becomes invalid and no longer points to the beginning of a valid message. To reset a reader to the current write pointer, the following steps are performed:
1. Set valid flag
2. Set read cycle counter to that of the writer
3. Set read pointer to write pointer
## Reading
Reading involves the following steps:
1. Read the size field at the current read pointer
2. Read the validity flag
3. Copy the data out of the buffer
4. Increase the read pointer by the size of the message
5. Check the validity flag again
Before starting the copy, the valid flag is checked. This is to prevent a race condition where the size prefix was invalid, and the read could read outside of the buffer. Make sure that step 1 and 2 are not reordered by your compiler or CPU.
If a writer overwrites the data while it's being copied out, the data will be invalid. Therefore the validity flag is also checked after reading it. The order of step 4 and 5 does not matter.
If at steps 2 or 5 the validity flag is not set, the reader is reset. Any data that was already read is discarded. After the reader is reset, the reading starts from the beginning.
If a message with size -1 is encountered, step 3 and 4 are replaced by increasing the cycle counter and setting the read pointer to the beginning of the buffer. After that another read is performed.
-37
View File
@@ -1,37 +0,0 @@
#pragma once
#include <condition_variable>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#define private public
#include "msgq/impl_msgq.h"
#include "msgq/impl_zmq.h"
class MsgqToZmq {
public:
MsgqToZmq() {}
void run(const std::vector<std::string> &endpoints, const std::string &ip);
protected:
void registerSockets();
void zmqMonitorThread();
struct SocketPair {
std::string endpoint;
std::unique_ptr<ZMQPubSocket> pub_sock;
std::unique_ptr<MSGQSubSocket> sub_sock;
int connected_clients = 0;
};
std::unique_ptr<MSGQContext> msgq_context;
std::unique_ptr<ZMQContext> zmq_context;
std::mutex mutex;
std::condition_variable cv;
std::unique_ptr<MSGQPoller> msgq_poller;
std::map<SubSocket *, ZMQPubSocket *> sub2pub;
std::vector<SocketPair> socket_pairs;
};
+14
View File
@@ -0,0 +1,14 @@
from messaging_pyx import Context, SubSocket, PubSocket # pylint: disable=no-name-in-module, import-error
if __name__ == "__main__":
c = Context()
pub_sock = PubSocket()
pub_sock.connect(c, "controlsState")
for i in range(int(1e10)):
print(i)
sub_sock = SubSocket()
sub_sock.connect(c, "controlsState")
pub_sock.send(b'a')
print(sub_sock.receive())
-185
View File
@@ -1,185 +0,0 @@
import os
import capnp
import multiprocessing
import numbers
import random
import threading
import time
from parameterized import parameterized
import pytest
from cereal import log, car
import cereal.messaging as messaging
from cereal.services import SERVICE_LIST
events = [evt for evt in log.Event.schema.union_fields if evt in SERVICE_LIST.keys()]
def random_sock():
return random.choice(events)
def random_socks(num_socks=10):
return list({random_sock() for _ in range(num_socks)})
def random_bytes(length=1000):
return bytes([random.randrange(0xFF) for _ in range(length)])
def zmq_sleep(t=1):
if "ZMQ" in os.environ:
time.sleep(t)
# TODO: this should take any capnp struct and returrn a msg with random populated data
def random_carstate():
fields = ["vEgo", "aEgo", "brake", "steeringAngleDeg"]
msg = messaging.new_message("carState")
cs = msg.carState
for f in fields:
setattr(cs, f, random.random() * 10)
return msg
# TODO: this should compare any capnp structs
def assert_carstate(cs1, cs2):
for f in car.CarState.schema.non_union_fields:
# TODO: check all types
val1, val2 = getattr(cs1, f), getattr(cs2, f)
if isinstance(val1, numbers.Number):
assert val1 == val2, f"{f}: sent '{val1}' vs recvd '{val2}'"
def delayed_send(delay, sock, dat):
def send_func():
sock.send(dat)
threading.Timer(delay, send_func).start()
class TestMessaging:
def setUp(self):
# TODO: ZMQ tests are too slow; all sleeps will need to be
# replaced with logic to block on the necessary condition
if "ZMQ" in os.environ:
pytest.skip()
# ZMQ pub socket takes too long to die
# sleep to prevent multiple publishers error between tests
zmq_sleep()
@parameterized.expand(events)
def test_new_message(self, evt):
try:
msg = messaging.new_message(evt)
except capnp.lib.capnp.KjException:
msg = messaging.new_message(evt, random.randrange(200))
assert (time.monotonic() - msg.logMonoTime) < 0.1
assert not msg.valid
assert evt == msg.which()
@parameterized.expand(events)
def test_pub_sock(self, evt):
messaging.pub_sock(evt)
@parameterized.expand(events)
def test_sub_sock(self, evt):
messaging.sub_sock(evt)
@parameterized.expand([
(messaging.drain_sock, capnp._DynamicStructReader),
(messaging.drain_sock_raw, bytes),
])
def test_drain_sock(self, func, expected_type):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=1000)
zmq_sleep()
# no wait and no msgs in queue
msgs = func(sub_sock)
assert isinstance(msgs, list)
assert len(msgs) == 0
# no wait but msgs are queued up
num_msgs = random.randrange(3, 10)
for _ in range(num_msgs):
pub_sock.send(messaging.new_message(sock).to_bytes())
time.sleep(0.1)
msgs = func(sub_sock)
assert isinstance(msgs, list)
assert all(isinstance(msg, expected_type) for msg in msgs)
assert len(msgs) == num_msgs
def test_recv_sock(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=100)
zmq_sleep()
# no wait and no msg in queue, socket should timeout
recvd = messaging.recv_sock(sub_sock)
assert recvd is None
# no wait and one msg in queue
msg = random_carstate()
pub_sock.send(msg.to_bytes())
time.sleep(0.01)
recvd = messaging.recv_sock(sub_sock)
assert isinstance(recvd, capnp._DynamicStructReader)
# https://github.com/python/mypy/issues/13038
assert_carstate(msg.carState, recvd.carState)
def test_recv_one(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=1000)
zmq_sleep()
# no msg in queue, socket should timeout
recvd = messaging.recv_one(sub_sock)
assert recvd is None
# one msg in queue
msg = random_carstate()
pub_sock.send(msg.to_bytes())
recvd = messaging.recv_one(sub_sock)
assert isinstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState)
@pytest.mark.xfail(condition="ZMQ" in os.environ, reason='ZMQ detected')
def test_recv_one_or_none(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock)
zmq_sleep()
# no msg in queue, socket shouldn't block
recvd = messaging.recv_one_or_none(sub_sock)
assert recvd is None
# one msg in queue
msg = random_carstate()
pub_sock.send(msg.to_bytes())
recvd = messaging.recv_one_or_none(sub_sock)
assert isinstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState)
def test_recv_one_retry(self):
sock = "carState"
sock_timeout = 0.1
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=round(sock_timeout*1000))
zmq_sleep()
# this test doesn't work with ZMQ since multiprocessing interrupts it
if "ZMQ" not in os.environ:
# wait 5 socket timeouts and make sure it's still retrying
p = multiprocessing.Process(target=messaging.recv_one_retry, args=(sub_sock,))
p.start()
time.sleep(sock_timeout*5)
assert p.is_alive()
p.terminate()
# wait 5 socket timeouts before sending
msg = random_carstate()
start_time = time.monotonic()
delayed_send(sock_timeout*5, pub_sock, msg.to_bytes())
recvd = messaging.recv_one_retry(sub_sock)
assert (time.monotonic() - start_time) >= sock_timeout*5
assert isinstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState)
@@ -1,160 +0,0 @@
import random
import time
from typing import Sized, cast
import cereal.messaging as messaging
from cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \
random_bytes, random_carstate, assert_carstate, \
zmq_sleep
from cereal.services import SERVICE_LIST
class TestSubMaster:
def setup_method(self):
# ZMQ pub socket takes too long to die
# sleep to prevent multiple publishers error between tests
zmq_sleep(3)
def test_init(self):
sm = messaging.SubMaster(events)
for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive,
sm.sock, sm.data, sm.logMonoTime, sm.valid]:
assert len(cast(Sized, p)) == len(events)
def test_init_state(self):
socks = random_socks()
sm = messaging.SubMaster(socks)
assert sm.frame == -1
assert not any(sm.updated.values())
assert not any(sm.seen.values())
on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in sm.services}
assert all(sm.alive[s] == sm.valid[s] == sm.freq_ok[s] == on_demand[s] for s in sm.services)
assert all(t == 0. for t in sm.recv_time.values())
assert all(f == 0 for f in sm.recv_frame.values())
assert all(t == 0 for t in sm.logMonoTime.values())
for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive,
sm.sock, sm.data, sm.logMonoTime, sm.valid]:
assert len(cast(Sized, p)) == len(socks)
def test_getitem(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sm = messaging.SubMaster([sock,])
zmq_sleep()
msg = random_carstate()
pub_sock.send(msg.to_bytes())
sm.update(1000)
assert_carstate(msg.carState, sm[sock])
# TODO: break this test up to individually test SubMaster.update and SubMaster.update_msgs
def test_update(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sm = messaging.SubMaster([sock,])
zmq_sleep()
for i in range(10):
msg = messaging.new_message(sock)
pub_sock.send(msg.to_bytes())
sm.update(1000)
assert sm.frame == i
assert all(sm.updated.values())
def test_update_timeout(self):
sock = random_sock()
sm = messaging.SubMaster([sock,])
timeout = random.randrange(1000, 3000)
start_time = time.monotonic()
sm.update(timeout)
t = time.monotonic() - start_time
assert t >= timeout/1000.
assert t < 3
assert not any(sm.updated.values())
def test_avg_frequency_checks(self):
for poll in (True, False):
sm = messaging.SubMaster(["modelV2", "carParams", "carState", "cameraOdometry", "liveCalibration"],
poll=("modelV2" if poll else None),
frequency=(20. if not poll else None))
checks = {
"carState": (20, 20),
"modelV2": (20, 20 if poll else 10),
"cameraOdometry": (20, 10),
"liveCalibration": (4, 4),
"carParams": (None, None),
"userBookmark": (None, None),
}
for service, (max_freq, min_freq) in checks.items():
if max_freq is not None:
assert sm._check_avg_freq(service)
assert sm.freq_tracker[service].max_freq == max_freq*1.2
assert sm.freq_tracker[service].min_freq == min_freq*0.8
else:
assert not sm._check_avg_freq(service)
def test_alive(self):
pass
def test_ignore_alive(self):
pass
def test_valid(self):
pass
# SubMaster should always conflate
def test_conflate(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sm = messaging.SubMaster([sock,])
n = 10
for i in range(n+1):
msg = messaging.new_message(sock)
msg.carState.vEgo = i
pub_sock.send(msg.to_bytes())
time.sleep(0.01)
sm.update(1000)
assert sm[sock].vEgo == n
class TestPubMaster:
def setup_method(self):
# ZMQ pub socket takes too long to die
# sleep to prevent multiple publishers error between tests
zmq_sleep(3)
def test_init(self):
messaging.PubMaster(events)
def test_send(self):
socks = random_socks()
pm = messaging.PubMaster(socks)
sub_socks = {s: messaging.sub_sock(s, conflate=True, timeout=1000) for s in socks}
zmq_sleep()
# PubMaster accepts either a capnp msg builder or bytes
for capnp in [True, False]:
for i in range(100):
sock = socks[i % len(socks)]
if capnp:
try:
msg = messaging.new_message(sock)
except Exception:
msg = messaging.new_message(sock, random.randrange(50))
else:
msg = random_bytes()
pm.send(sock, msg)
recvd = sub_socks[sock].receive()
if capnp:
msg.clear_write_flag()
msg = msg.to_bytes()
assert msg == recvd, i
-21
View File
@@ -1,21 +0,0 @@
import os
import tempfile
from typing import Dict
from parameterized import parameterized
import cereal.services as services
from cereal.services import SERVICE_LIST
class TestServices:
@parameterized.expand(SERVICE_LIST.keys())
def test_services(self, s):
service = SERVICE_LIST[s]
assert service.frequency <= 104
assert service.decimation != 0
def test_generated_header(self):
with tempfile.NamedTemporaryFile(suffix=".h") as f:
ret = os.system(f"python3 {services.__file__} > {f.name} && clang++ {f.name} -std=c++11")
assert ret == 0, "generated services header is not valid C"
+20
View File
@@ -0,0 +1,20 @@
# https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml
[tool.ruff]
select = ["E", "F", "W", "PIE", "C4", "ISC", "RUF100", "A"]
ignore = ["W292", "E741", "E402", "C408", "ISC003"]
line-length = 160
target-version="py311"
flake8-implicit-str-concat.allow-multiline=false
[mypy.tool]
# third-party packages
ignore_missing_imports=true
# helpful warnings
warn_redundant_casts=true
warn_unreachable=true
warn_unused_ignores=true
# restrict dynamic typing
warn_return_any=true
check_untyped_defs=true
+79 -87
View File
@@ -2,94 +2,86 @@
#ifndef __SERVICES_H
#define __SERVICES_H
#include <map>
#include <string>
struct service { std::string name; bool should_log; float frequency; int decimation; size_t queue_size; };
struct service { std::string name; int port; bool should_log; int frequency; int decimation; };
static std::map<std::string, service> services = {
{ "gyroscope", {"gyroscope", true, 104.000000, 104, 256000}},
{ "accelerometer", {"accelerometer", true, 104.000000, 104, 256000}},
{ "magnetometer", {"magnetometer", true, 25.000000, -1, 256000}},
{ "lightSensor", {"lightSensor", true, 100.000000, 100, 256000}},
{ "temperatureSensor", {"temperatureSensor", true, 2.000000, 200, 256000}},
{ "gpsNMEA", {"gpsNMEA", true, 9.000000, -1, 256000}},
{ "deviceState", {"deviceState", true, 2.000000, 1, 256000}},
{ "touch", {"touch", true, 20.000000, 1, 256000}},
{ "can", {"can", true, 100.000000, 2053, 10485760}},
{ "controlsState", {"controlsState", true, 100.000000, 10, 2097152}},
{ "selfdriveState", {"selfdriveState", true, 100.000000, 10, 256000}},
{ "pandaStates", {"pandaStates", true, 10.000000, 1, 256000}},
{ "peripheralState", {"peripheralState", true, 2.000000, 1, 256000}},
{ "radarState", {"radarState", true, 20.000000, 5, 256000}},
{ "roadEncodeIdx", {"roadEncodeIdx", false, 20.000000, 1, 256000}},
{ "liveTracks", {"liveTracks", true, 20.000000, -1, 256000}},
{ "sendcan", {"sendcan", true, 100.000000, 139, 2097152}},
{ "logMessage", {"logMessage", true, 0.000000, -1, 256000}},
{ "errorLogMessage", {"errorLogMessage", true, 0.000000, 1, 256000}},
{ "liveCalibration", {"liveCalibration", true, 4.000000, 4, 256000}},
{ "liveTorqueParameters", {"liveTorqueParameters", true, 4.000000, 1, 256000}},
{ "liveDelay", {"liveDelay", true, 4.000000, 1, 256000}},
{ "androidLog", {"androidLog", true, 0.000000, -1, 256000}},
{ "carState", {"carState", true, 100.000000, 10, 256000}},
{ "carControl", {"carControl", true, 100.000000, 10, 256000}},
{ "carOutput", {"carOutput", true, 100.000000, 10, 256000}},
{ "longitudinalPlan", {"longitudinalPlan", true, 20.000000, 10, 256000}},
{ "driverAssistance", {"driverAssistance", true, 20.000000, 20, 256000}},
{ "procLog", {"procLog", true, 0.500000, 15, 10485760}},
{ "gpsLocationExternal", {"gpsLocationExternal", true, 10.000000, 10, 256000}},
{ "gpsLocation", {"gpsLocation", true, 1.000000, 1, 256000}},
{ "ubloxGnss", {"ubloxGnss", true, 10.000000, -1, 256000}},
{ "qcomGnss", {"qcomGnss", true, 2.000000, -1, 256000}},
{ "gnssMeasurements", {"gnssMeasurements", true, 10.000000, 10, 256000}},
{ "clocks", {"clocks", true, 0.100000, 1, 256000}},
{ "ubloxRaw", {"ubloxRaw", true, 20.000000, -1, 256000}},
{ "livePose", {"livePose", true, 20.000000, 4, 256000}},
{ "liveParameters", {"liveParameters", true, 20.000000, 5, 256000}},
{ "cameraOdometry", {"cameraOdometry", true, 20.000000, 10, 256000}},
{ "thumbnail", {"thumbnail", true, 0.016667, 1, 256000}},
{ "onroadEvents", {"onroadEvents", true, 1.000000, 1, 256000}},
{ "carParams", {"carParams", true, 0.020000, 1, 256000}},
{ "roadCameraState", {"roadCameraState", true, 20.000000, 20, 256000}},
{ "driverCameraState", {"driverCameraState", true, 20.000000, 20, 256000}},
{ "driverEncodeIdx", {"driverEncodeIdx", false, 20.000000, 1, 256000}},
{ "driverStateV2", {"driverStateV2", true, 20.000000, 10, 256000}},
{ "driverMonitoringState", {"driverMonitoringState", true, 20.000000, 10, 256000}},
{ "wideRoadEncodeIdx", {"wideRoadEncodeIdx", false, 20.000000, 1, 256000}},
{ "wideRoadCameraState", {"wideRoadCameraState", true, 20.000000, 20, 256000}},
{ "drivingModelData", {"drivingModelData", true, 20.000000, 10, 256000}},
{ "modelV2", {"modelV2", true, 20.000000, -1, 10485760}},
{ "managerState", {"managerState", true, 2.000000, 1, 256000}},
{ "uploaderState", {"uploaderState", true, 0.000000, 1, 256000}},
{ "navRoute", {"navRoute", true, 0.000000, -1, 256000}},
{ "navThumbnail", {"navThumbnail", true, 0.000000, -1, 256000}},
{ "qRoadEncodeIdx", {"qRoadEncodeIdx", false, 20.000000, -1, 256000}},
{ "userBookmark", {"userBookmark", true, 0.000000, 1, 256000}},
{ "soundPressure", {"soundPressure", true, 10.000000, 10, 256000}},
{ "rawAudioData", {"rawAudioData", false, 20.000000, -1, 256000}},
{ "bookmarkButton", {"bookmarkButton", true, 0.000000, 1, 256000}},
{ "audioFeedback", {"audioFeedback", true, 0.000000, 1, 256000}},
{ "roadEncodeData", {"roadEncodeData", false, 20.000000, -1, 10485760}},
{ "driverEncodeData", {"driverEncodeData", false, 20.000000, -1, 10485760}},
{ "wideRoadEncodeData", {"wideRoadEncodeData", false, 20.000000, -1, 10485760}},
{ "qRoadEncodeData", {"qRoadEncodeData", false, 20.000000, -1, 10485760}},
{ "uiDebug", {"uiDebug", true, 0.000000, 1, 256000}},
{ "testJoystick", {"testJoystick", true, 0.000000, -1, 256000}},
{ "alertDebug", {"alertDebug", true, 20.000000, 5, 256000}},
{ "livestreamWideRoadEncodeIdx", {"livestreamWideRoadEncodeIdx", false, 20.000000, -1, 256000}},
{ "livestreamRoadEncodeIdx", {"livestreamRoadEncodeIdx", false, 20.000000, -1, 256000}},
{ "livestreamDriverEncodeIdx", {"livestreamDriverEncodeIdx", false, 20.000000, -1, 256000}},
{ "livestreamWideRoadEncodeData", {"livestreamWideRoadEncodeData", false, 20.000000, -1, 2097152}},
{ "livestreamRoadEncodeData", {"livestreamRoadEncodeData", false, 20.000000, -1, 2097152}},
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20.000000, -1, 2097152}},
{ "customReservedRawData0", {"customReservedRawData0", true, 0.000000, -1, 256000}},
{ "customReservedRawData1", {"customReservedRawData1", true, 0.000000, -1, 256000}},
{ "customReservedRawData2", {"customReservedRawData2", true, 0.000000, -1, 256000}},
{ "controlsStateExt", {"controlsStateExt", true, 100.000000, -1, 256000}},
{ "carStateExt", {"carStateExt", true, 100.000000, -1, 256000}},
{ "modelExt", {"modelExt", true, 20.000000, -1, 256000}},
{ "navInstruction", {"navInstruction", true, 0.000000, -1, 256000}},
{ "navInstructionExt", {"navInstructionExt", true, 0.000000, -1, 256000}},
{ "liveGPS", {"liveGPS", true, 0.000000, -1, 256000}},
{ "maaControl", {"maaControl", true, 0.000000, -1, 256000}},
{ "dashyState", {"dashyState", true, 0.000000, -1, 256000}},
{ "gyroscope", {"gyroscope", 8001, true, 104, 104}},
{ "gyroscope2", {"gyroscope2", 8002, true, 100, 100}},
{ "accelerometer", {"accelerometer", 8003, true, 104, 104}},
{ "accelerometer2", {"accelerometer2", 8004, true, 100, 100}},
{ "magnetometer", {"magnetometer", 8005, true, 25, 25}},
{ "lightSensor", {"lightSensor", 8006, true, 100, 100}},
{ "temperatureSensor", {"temperatureSensor", 8007, true, 2, 200}},
{ "temperatureSensor2", {"temperatureSensor2", 8008, true, 2, 200}},
{ "gpsNMEA", {"gpsNMEA", 8009, true, 9, -1}},
{ "deviceState", {"deviceState", 8010, true, 2, 1}},
{ "can", {"can", 8011, true, 100, 1223}},
{ "controlsState", {"controlsState", 8012, true, 100, 10}},
{ "pandaStates", {"pandaStates", 8013, true, 2, 1}},
{ "peripheralState", {"peripheralState", 8014, true, 2, 1}},
{ "radarState", {"radarState", 8015, true, 20, 5}},
{ "roadEncodeIdx", {"roadEncodeIdx", 8016, false, 20, 1}},
{ "liveTracks", {"liveTracks", 8017, true, 20, -1}},
{ "sendcan", {"sendcan", 8018, true, 100, 139}},
{ "logMessage", {"logMessage", 8019, true, 0, -1}},
{ "errorLogMessage", {"errorLogMessage", 8020, true, 0, 1}},
{ "liveCalibration", {"liveCalibration", 8021, true, 4, 4}},
{ "liveTorqueParameters", {"liveTorqueParameters", 8023, true, 4, 1}},
{ "androidLog", {"androidLog", 8024, true, 0, -1}},
{ "carState", {"carState", 8025, true, 100, 10}},
{ "carControl", {"carControl", 8026, true, 100, 10}},
{ "longitudinalPlan", {"longitudinalPlan", 8027, true, 20, 5}},
{ "procLog", {"procLog", 8028, true, 0, 15}},
{ "gpsLocationExternal", {"gpsLocationExternal", 8029, true, 10, 10}},
{ "gpsLocation", {"gpsLocation", 8030, true, 1, 1}},
{ "ubloxGnss", {"ubloxGnss", 8031, true, 10, -1}},
{ "qcomGnss", {"qcomGnss", 8032, true, 2, -1}},
{ "gnssMeasurements", {"gnssMeasurements", 8033, true, 10, 10}},
{ "clocks", {"clocks", 8034, true, 1, 1}},
{ "ubloxRaw", {"ubloxRaw", 8035, true, 20, -1}},
{ "liveLocationKalman", {"liveLocationKalman", 8036, true, 20, 5}},
{ "liveParameters", {"liveParameters", 8037, true, 20, 5}},
{ "cameraOdometry", {"cameraOdometry", 8038, true, 20, 5}},
{ "lateralPlan", {"lateralPlan", 8039, true, 20, 5}},
{ "thumbnail", {"thumbnail", 8040, true, 0, 1}},
{ "carEvents", {"carEvents", 8041, true, 1, 1}},
{ "carParams", {"carParams", 8042, true, 0, 1}},
{ "roadCameraState", {"roadCameraState", 8043, true, 20, 20}},
{ "driverCameraState", {"driverCameraState", 8044, true, 10, 10}},
{ "driverEncodeIdx", {"driverEncodeIdx", 8045, true, 10, 1}},
{ "driverStateV2", {"driverStateV2", 8046, true, 20, 10}},
{ "driverMonitoringState", {"driverMonitoringState", 8047, true, 10, 5}},
{ "wideRoadEncodeIdx", {"wideRoadEncodeIdx", 8048, false, 20, 1}},
{ "wideRoadCameraState", {"wideRoadCameraState", 8049, true, 20, 20}},
{ "modelV2", {"modelV2", 8050, true, 20, 40}},
{ "managerState", {"managerState", 8051, true, 2, 1}},
{ "uploaderState", {"uploaderState", 8052, true, 0, 1}},
{ "navInstruction", {"navInstruction", 8053, true, 1, 10}},
{ "navRoute", {"navRoute", 8054, true, 0, -1}},
{ "navThumbnail", {"navThumbnail", 8055, true, 0, -1}},
{ "navModel", {"navModel", 8056, true, 2, 4}},
{ "mapRenderState", {"mapRenderState", 8057, true, 2, 1}},
{ "uiPlan", {"uiPlan", 8058, true, 20, 40}},
{ "qRoadEncodeIdx", {"qRoadEncodeIdx", 8059, false, 20, -1}},
{ "userFlag", {"userFlag", 8060, true, 0, 1}},
{ "microphone", {"microphone", 8061, true, 10, 10}},
{ "uiDebug", {"uiDebug", 8062, true, 0, 1}},
{ "testJoystick", {"testJoystick", 8063, true, 0, -1}},
{ "roadEncodeData", {"roadEncodeData", 8064, false, 20, -1}},
{ "driverEncodeData", {"driverEncodeData", 8065, false, 20, -1}},
{ "wideRoadEncodeData", {"wideRoadEncodeData", 8066, false, 20, -1}},
{ "qRoadEncodeData", {"qRoadEncodeData", 8067, false, 20, -1}},
{ "livestreamWideRoadEncodeIdx", {"livestreamWideRoadEncodeIdx", 8068, false, 20, -1}},
{ "livestreamRoadEncodeIdx", {"livestreamRoadEncodeIdx", 8069, false, 20, -1}},
{ "livestreamDriverEncodeIdx", {"livestreamDriverEncodeIdx", 8070, false, 20, -1}},
{ "livestreamWideRoadEncodeData", {"livestreamWideRoadEncodeData", 8071, false, 20, -1}},
{ "livestreamRoadEncodeData", {"livestreamRoadEncodeData", 8072, false, 20, -1}},
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", 8073, false, 20, -1}},
{ "driverState", {"driverState", 8074, true, 10, 5}},
{ "sensorEvents", {"sensorEvents", 8075, true, 100, 100}},
{ "liveMapData", {"liveMapData", 8076, false, 0, -1}},
{ "longitudinalPlanExt", {"longitudinalPlanExt", 8077, false, 20, 5}},
{ "lateralPlanExt", {"lateralPlanExt", 8078, false, 20, 5}},
{ "controlsStateExt", {"controlsStateExt", 8079, false, 100, 10}},
};
#endif
+59 -64
View File
@@ -1,119 +1,115 @@
#!/usr/bin/env python3
from enum import IntEnum
from typing import Optional
import os
TICI = os.path.isfile('/TICI')
RESERVED_PORT = 8022 # sshd
STARTING_PORT = 8001
# TODO: this should be automatically determined using the capnp schema
class QueueSize(IntEnum):
BIG = 10 * 1024 * 1024 # 10MB - video frames, large AI outputs
MEDIUM = 2 * 1024 * 1024 # 2MB - high freq (CAN), livestream
SMALL = 250 * 1024 # 250KB - most services
def new_port(port: int):
port += STARTING_PORT
return port + 1 if port >= RESERVED_PORT else port
class Service:
def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] = None,
queue_size: QueueSize = QueueSize.SMALL):
def __init__(self, port: int, should_log: bool, frequency: float, decimation: Optional[int] = None):
self.port = port
self.should_log = should_log
self.frequency = frequency
self.decimation = decimation
self.queue_size = queue_size
DCAM_FREQ = 10. if not TICI else 20.
_services: dict[str, tuple] = {
services = {
# service: (should_log, frequency, qlog decimation (optional))
# note: the "EncodeIdx" packets will still be in the log
"gyroscope": (True, 104., 104),
"gyroscope2": (True, 100., 100),
"accelerometer": (True, 104., 104),
"magnetometer": (True, 25.),
"accelerometer2": (True, 100., 100),
"magnetometer": (True, 25., 25),
"lightSensor": (True, 100., 100),
"temperatureSensor": (True, 2., 200),
"temperatureSensor2": (True, 2., 200),
"gpsNMEA": (True, 9.),
"deviceState": (True, 2., 1),
"touch": (True, 20., 1),
"can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment
"controlsState": (True, 100., 10, QueueSize.MEDIUM),
"selfdriveState": (True, 100., 10),
"pandaStates": (True, 10., 1),
"can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment
"controlsState": (True, 100., 10),
"pandaStates": (True, 2., 1),
"peripheralState": (True, 2., 1),
"radarState": (True, 20., 5),
"roadEncodeIdx": (False, 20., 1),
"liveTracks": (True, 20.),
"sendcan": (True, 100., 139, QueueSize.MEDIUM),
"sendcan": (True, 100., 139),
"logMessage": (True, 0.),
"errorLogMessage": (True, 0., 1),
"liveCalibration": (True, 4., 4),
"liveTorqueParameters": (True, 4., 1),
"liveDelay": (True, 4., 1),
"androidLog": (True, 0.),
"carState": (True, 100., 10),
"carControl": (True, 100., 10),
"carOutput": (True, 100., 10),
"longitudinalPlan": (True, 20., 10),
"driverAssistance": (True, 20., 20),
"procLog": (True, 0.5, 15, QueueSize.BIG),
"longitudinalPlan": (True, 20., 5),
"procLog": (True, 0.5, 15),
"gpsLocationExternal": (True, 10., 10),
"gpsLocation": (True, 1., 1),
"ubloxGnss": (True, 10.),
"qcomGnss": (True, 2.),
"gnssMeasurements": (True, 10., 10),
"clocks": (True, 0.1, 1),
"clocks": (True, 1., 1),
"ubloxRaw": (True, 20.),
"livePose": (True, 20., 4),
"liveLocationKalman": (True, 20., 5),
"liveParameters": (True, 20., 5),
"cameraOdometry": (True, 20., 10),
"thumbnail": (True, 1 / 60., 1),
"onroadEvents": (True, 1., 1),
"cameraOdometry": (True, 20., 5),
"lateralPlan": (True, 20., 5),
"thumbnail": (True, 0.2, 1),
"carEvents": (True, 1., 1),
"carParams": (True, 0.02, 1),
"roadCameraState": (True, 20., 20),
"driverCameraState": (True, 20., 20),
"driverEncodeIdx": (False, 20., 1),
"driverCameraState": (True, DCAM_FREQ, DCAM_FREQ),
"driverEncodeIdx": (True, DCAM_FREQ, 1),
"driverStateV2": (True, 20., 10),
"driverMonitoringState": (True, 20., 10),
"driverMonitoringState": (True, DCAM_FREQ, DCAM_FREQ / 2),
"wideRoadEncodeIdx": (False, 20., 1),
"wideRoadCameraState": (True, 20., 20),
"drivingModelData": (True, 20., 10),
"modelV2": (True, 20., None, QueueSize.BIG),
"modelV2": (True, 20., 40),
"managerState": (True, 2., 1),
"uploaderState": (True, 0., 1),
# "navInstruction": (True, 1., 10), # dp - make it 0 hz
"navInstruction": (True, 1., 10),
"navRoute": (True, 0.),
"navThumbnail": (True, 0.),
"navModel": (True, 2., 4.),
"mapRenderState": (True, 2., 1.),
"uiPlan": (True, 20., 40.),
"qRoadEncodeIdx": (False, 20.),
"userBookmark": (True, 0., 1),
"soundPressure": (True, 10., 10),
"rawAudioData": (False, 20.),
"bookmarkButton": (True, 0., 1),
"audioFeedback": (True, 0., 1),
"roadEncodeData": (False, 20., None, QueueSize.BIG),
"driverEncodeData": (False, 20., None, QueueSize.BIG),
"wideRoadEncodeData": (False, 20., None, QueueSize.BIG),
"qRoadEncodeData": (False, 20., None, QueueSize.BIG),
"userFlag": (True, 0., 1),
"microphone": (True, 10., 10),
# debug
"uiDebug": (True, 0., 1),
"testJoystick": (True, 0.),
"alertDebug": (True, 20., 5),
"roadEncodeData": (False, 20.),
"driverEncodeData": (False, 20.),
"wideRoadEncodeData": (False, 20.),
"qRoadEncodeData": (False, 20.),
"livestreamWideRoadEncodeIdx": (False, 20.),
"livestreamRoadEncodeIdx": (False, 20.),
"livestreamDriverEncodeIdx": (False, 20.),
"livestreamWideRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
"livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
"customReservedRawData0": (True, 0.),
"customReservedRawData1": (True, 0.),
"customReservedRawData2": (True, 0.),
"controlsStateExt": (True, 100.),
"carStateExt": (True, 100.),
"modelExt": (True, 20.),
# dashy
"navInstruction": (True, 0.),
"navInstructionExt": (True, 0.),
"liveGPS": (True, 0.), # GPS fusion from gpsd (optional)
"maaControl": (True, 0.), # Map-Aware Assist control signals (optional)
"dashyState": (True, 0.), # Aggregated dashy UI state (optional)
"livestreamWideRoadEncodeData": (False, 20.),
"livestreamRoadEncodeData": (False, 20.),
"livestreamDriverEncodeData": (False, 20.),
# legacy
"driverState": (True, 10, 5),
"sensorEvents": (True, 100., 100),
# mapd
"liveMapData": (False, 0.),
"longitudinalPlanExt": (False, 20., 5),
"lateralPlanExt": (False, 20., 5),
"controlsStateExt": (False, 100., 10),
}
SERVICE_LIST = {name: Service(*vals) for
idx, (name, vals) in enumerate(_services.items())}
SERVICE_LIST = {name: Service(new_port(idx), *vals) for # type: ignore
idx, (name, vals) in enumerate(services.items())}
def build_header():
@@ -123,15 +119,14 @@ def build_header():
h += "#define __SERVICES_H\n"
h += "#include <map>\n"
h += "#include <string>\n"
h += "struct service { std::string name; bool should_log; float frequency; int decimation; size_t queue_size; };\n"
h += "struct service { std::string name; int port; bool should_log; int frequency; int decimation; };\n"
h += "static std::map<std::string, service> services = {\n"
for k, v in SERVICE_LIST.items():
should_log = "true" if v.should_log else "false"
decimation = -1 if v.decimation is None else v.decimation
h += ' { "%s", {"%s", %s, %f, %d, %d}},\n' % \
(k, k, should_log, v.frequency, decimation, v.queue_size)
h += ' { "%s", {"%s", %d, %s, %d, %d}},\n' % \
(k, k, v.port, should_log, v.frequency, decimation)
h += "};\n"
h += "#endif\n"
+6
View File
@@ -0,0 +1,6 @@
from cereal.visionipc.visionipc_pyx import VisionBuf, VisionIpcClient, VisionIpcServer, VisionStreamType, get_endpoint_name
assert VisionBuf
assert VisionIpcClient
assert VisionIpcServer
assert VisionStreamType
assert get_endpoint_name
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <cstddef>
int ipc_connect(const char* socket_path);
int ipc_bind(const char* socket_path);
int ipc_sendrecv_with_fds(bool send, int fd, void *buf, size_t buf_size, int* fds, int num_fds,
int *out_num_fds);
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env python3
import os
import time
import random
import unittest
import numpy as np
from cereal.visionipc import VisionIpcServer, VisionIpcClient, VisionStreamType
def zmq_sleep(t=1):
if "ZMQ" in os.environ:
time.sleep(t)
class TestVisionIpc(unittest.TestCase):
def setup_vipc(self, name, *stream_types, num_buffers=1, rgb=False, width=100, height=100, conflate=False):
self.server = VisionIpcServer(name)
for stream_type in stream_types:
self.server.create_buffers(stream_type, num_buffers, rgb, width, height)
self.server.start_listener()
if len(stream_types):
self.client = VisionIpcClient(name, stream_types[0], conflate)
self.assertTrue(self.client.connect(True))
else:
self.client = None
zmq_sleep()
return self.server, self.client
def test_connect(self):
self.setup_vipc("camerad", VisionStreamType.VISION_STREAM_ROAD)
self.assertTrue(self.client.is_connected)
def test_available_streams(self):
for k in range(0, 4):
stream_types = set(random.choices([x.value for x in VisionStreamType], k=k))
self.setup_vipc("camerad", *stream_types)
available_streams = VisionIpcClient.available_streams("camerad", True)
self.assertEqual(available_streams, stream_types)
def test_buffers(self):
width, height, num_buffers = 100, 200, 5
self.setup_vipc("camerad", VisionStreamType.VISION_STREAM_ROAD, num_buffers=num_buffers, width=width, height=height)
self.assertEqual(self.client.width, width)
self.assertEqual(self.client.height, height)
self.assertGreater(self.client.buffer_len, 0)
self.assertEqual(self.client.num_buffers, num_buffers)
def test_yuv_rgb(self):
_, client_yuv = self.setup_vipc("camerad", VisionStreamType.VISION_STREAM_ROAD, rgb=False)
_, client_rgb = self.setup_vipc("navd", VisionStreamType.VISION_STREAM_MAP, rgb=True)
self.assertTrue(client_rgb.rgb)
self.assertFalse(client_yuv.rgb)
def test_send_single_buffer(self):
self.setup_vipc("camerad", VisionStreamType.VISION_STREAM_ROAD)
buf = np.zeros(self.client.buffer_len, dtype=np.uint8)
buf.view('<i4')[0] = 1234
self.server.send(VisionStreamType.VISION_STREAM_ROAD, buf, frame_id=1337)
recv_buf = self.client.recv()
self.assertIsNot(recv_buf, None)
self.assertEqual(recv_buf.data.view('<i4')[0], 1234)
self.assertEqual(self.client.frame_id, 1337)
def test_no_conflate(self):
self.setup_vipc("camerad", VisionStreamType.VISION_STREAM_ROAD)
buf = np.zeros(self.client.buffer_len, dtype=np.uint8)
self.server.send(VisionStreamType.VISION_STREAM_ROAD, buf, frame_id=1)
self.server.send(VisionStreamType.VISION_STREAM_ROAD, buf, frame_id=2)
recv_buf = self.client.recv()
self.assertIsNot(recv_buf, None)
self.assertEqual(self.client.frame_id, 1)
recv_buf = self.client.recv()
self.assertIsNot(recv_buf, None)
self.assertEqual(self.client.frame_id, 2)
def test_conflate(self):
self.setup_vipc("camerad", VisionStreamType.VISION_STREAM_ROAD, conflate=True)
buf = np.zeros(self.client.buffer_len, dtype=np.uint8)
self.server.send(VisionStreamType.VISION_STREAM_ROAD, buf, frame_id=1)
self.server.send(VisionStreamType.VISION_STREAM_ROAD, buf, frame_id=2)
recv_buf = self.client.recv()
self.assertIsNot(recv_buf, None)
self.assertEqual(self.client.frame_id, 2)
recv_buf = self.client.recv()
self.assertIs(recv_buf, None)
if __name__ == "__main__":
unittest.main()
@@ -1,6 +1,6 @@
#pragma once
#include "msgq/visionipc/visionipc.h"
#include "cereal/visionipc/visionipc.h"
#define CL_USE_DEPRECATED_OPENCL_1_2_APIS
#ifdef __APPLE__
@@ -13,6 +13,10 @@
#define VISIONBUF_SYNC_TO_DEVICE 1
enum VisionStreamType {
VISION_STREAM_RGB_ROAD,
VISION_STREAM_RGB_DRIVER,
VISION_STREAM_RGB_WIDE_ROAD,
VISION_STREAM_ROAD,
VISION_STREAM_DRIVER,
VISION_STREAM_WIDE_ROAD,
@@ -29,6 +33,7 @@ class VisionBuf {
uint64_t *frame_id;
int fd = 0;
bool rgb = false;
size_t width = 0;
size_t height = 0;
size_t stride = 0;
@@ -36,6 +41,8 @@ class VisionBuf {
// YUV
uint8_t * y = nullptr;
uint8_t * u = nullptr;
uint8_t * v = nullptr;
uint8_t * uv = nullptr;
// Visionipc
@@ -53,6 +60,7 @@ class VisionBuf {
void allocate(size_t len);
void import();
void init_cl(cl_device_id device_id, cl_context ctx);
void init_rgb(size_t width, size_t height, size_t stride);
void init_yuv(size_t width, size_t height, size_t stride, size_t uv_offset);
int sync(int dir);
int free();
@@ -60,3 +68,5 @@ class VisionBuf {
void set_frame_id(uint64_t id);
uint64_t get_frame_id();
};
void visionbuf_compute_aligned_width_and_height(int width, int height, int *aligned_w, int *aligned_h);
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
#include <cstddef>
constexpr int VISIONIPC_MAX_FDS = 128;
struct VisionIpcBufExtra {
uint32_t frame_id;
uint64_t timestamp_sof;
uint64_t timestamp_eof;
bool valid;
};
struct VisionIpcPacket {
uint64_t server_id;
size_t idx;
struct VisionIpcBufExtra extra;
};
@@ -7,7 +7,7 @@ from libcpp.set cimport set
from libc.stdint cimport uint32_t, uint64_t
from libcpp cimport bool, int
cdef extern from "msgq/visionipc/visionbuf.h":
cdef extern from "cereal/visionipc/visionbuf.h":
struct _cl_device_id
struct _cl_context
struct _cl_mem
@@ -21,35 +21,34 @@ cdef extern from "msgq/visionipc/visionbuf.h":
cdef cppclass VisionBuf:
void * addr
int fd
bool rgb
size_t len
size_t width
size_t height
size_t stride
size_t uv_offset
size_t idx
cl_mem buf_cl
void set_frame_id(uint64_t id)
cdef extern from "msgq/visionipc/visionipc.h":
cdef extern from "cereal/visionipc/visionipc.h":
struct VisionIpcBufExtra:
uint32_t frame_id
uint64_t timestamp_sof
uint64_t timestamp_eof
bool valid
cdef extern from "msgq/visionipc/visionipc_server.h":
cdef extern from "cereal/visionipc/visionipc_server.h":
string get_endpoint_name(string, VisionStreamType)
cdef cppclass VisionIpcServer:
VisionIpcServer(string, void*, void*)
void create_buffers(VisionStreamType, size_t, size_t, size_t)
void create_buffers_with_sizes(VisionStreamType, size_t, size_t, size_t, size_t, size_t, size_t)
void create_buffers(VisionStreamType, size_t, bool, size_t, size_t)
void create_buffers_with_sizes(VisionStreamType, size_t, bool, size_t, size_t, size_t, size_t, size_t)
VisionBuf * get_buffer(VisionStreamType)
void send(VisionBuf *, VisionIpcBufExtra *, bool)
void start_listener()
cdef extern from "msgq/visionipc/visionipc_client.h":
cdef extern from "cereal/visionipc/visionipc_client.h":
cdef cppclass VisionIpcClient:
int num_buffers
VisionBuf buffers[1]
@@ -2,10 +2,12 @@
#include <set>
#include <string>
#include <vector>
#include <unistd.h>
#include "msgq/ipc.h"
#include "msgq/visionipc/visionbuf.h"
#include "cereal/messaging/messaging.h"
#include "cereal/visionipc/visionipc.h"
#include "cereal/visionipc/visionbuf.h"
class VisionIpcClient {
private:
@@ -17,6 +19,8 @@ private:
cl_device_id device_id = nullptr;
cl_context ctx = nullptr;
void init_msgq(bool conflate);
public:
bool connected = false;
VisionStreamType type;
BIN
View File
Binary file not shown.
@@ -5,11 +5,11 @@
#include <atomic>
#include <map>
#include "msgq/ipc.h"
#include "msgq/visionipc/visionbuf.h"
#include "cereal/messaging/messaging.h"
#include "cereal/visionipc/visionipc.h"
#include "cereal/visionipc/visionbuf.h"
std::string get_endpoint_name(std::string name, VisionStreamType type);
std::string get_ipc_path(const std::string &name);
class VisionIpcServer {
private:
@@ -33,10 +33,10 @@ class VisionIpcServer {
VisionIpcServer(std::string name, cl_device_id device_id=nullptr, cl_context ctx=nullptr);
~VisionIpcServer();
VisionBuf * get_buffer(VisionStreamType type, int idx = -1);
VisionBuf * get_buffer(VisionStreamType type);
void create_buffers(VisionStreamType type, size_t num_buffers, size_t width, size_t height);
void create_buffers_with_sizes(VisionStreamType type, size_t num_buffers, size_t width, size_t height, size_t size, size_t stride, size_t uv_offset);
void create_buffers(VisionStreamType type, size_t num_buffers, bool rgb, size_t width, size_t height);
void create_buffers_with_sizes(VisionStreamType type, size_t num_buffers, bool rgb, size_t width, size_t height, size_t size, size_t stride, size_t uv_offset);
void send(VisionBuf * buf, VisionIpcBufExtra * extra, bool sync=true);
void start_listener();
};
-29
View File
@@ -1,29 +0,0 @@
Import('env', 'envCython', 'arch')
common_libs = [
'params.cc',
'swaglog.cc',
'util.cc',
'ratekeeper.cc',
'clutil.cc',
]
_common = env.Library('common', common_libs, LIBS="json11")
Export('_common')
if GetOption('extras'):
env.Program('tests/test_common',
['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([
'transformations/SConscript',
])
Import('transformations_python')
common_python = [params_python, transformations_python]
Export('common_python')
-62
View File
@@ -1,62 +0,0 @@
import jwt
import os
import requests
from datetime import datetime, timedelta, UTC
from openpilot.system.hardware.hw import Paths
from openpilot.system.version import get_version
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
# name: jwt signature algorithm
KEYS = {"id_rsa": "RS256",
"id_ecdsa": "ES256"}
class Api:
def __init__(self, dongle_id):
self.dongle_id = dongle_id
self.jwt_algorithm, self.private_key, _ = get_key_pair()
def get(self, *args, **kwargs):
return self.request('GET', *args, **kwargs)
def post(self, *args, **kwargs):
return self.request('POST', *args, **kwargs)
def request(self, method, endpoint, timeout=None, access_token=None, **params):
return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
def get_token(self, payload_extra=None, expiry_hours=1):
now = datetime.now(UTC).replace(tzinfo=None)
payload = {
'identity': self.dongle_id,
'nbf': now,
'iat': now,
'exp': now + timedelta(hours=expiry_hours)
}
if payload_extra is not None:
payload.update(payload_extra)
token = jwt.encode(payload, self.private_key, algorithm=self.jwt_algorithm)
if isinstance(token, bytes):
token = token.decode('utf8')
return token
def api_get(endpoint, method='GET', timeout=None, access_token=None, session=None, **params):
headers = {}
if access_token is not None:
headers['Authorization'] = "JWT " + access_token
headers['User-Agent'] = "openpilot-" + get_version()
# TODO: add session to Api
req = requests if session is None else session
return req.request(method, API_HOST + "/" + endpoint, timeout=timeout, headers=headers, params=params)
def get_key_pair() -> tuple[str, str, str] | tuple[None, None, None]:
for key in KEYS:
if os.path.isfile(Paths.persist_root() + f'/comma/{key}') and os.path.isfile(Paths.persist_root() + f'/comma/{key}.pub'):
with open(Paths.persist_root() + f'/comma/{key}') as private, open(Paths.persist_root() + f'/comma/{key}.pub') as public:
return KEYS[key], private.read(), public.read()
return None, None, None
+46
View File
@@ -0,0 +1,46 @@
import jwt
import os
import requests
from datetime import datetime, timedelta
from openpilot.common.basedir import PERSIST
from openpilot.system.version import get_version
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:
self.private_key = f.read()
def get(self, *args, **kwargs):
return self.request('GET', *args, **kwargs)
def post(self, *args, **kwargs):
return self.request('POST', *args, **kwargs)
def request(self, method, endpoint, timeout=None, access_token=None, **params):
return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
def get_token(self, expiry_hours=1):
now = datetime.utcnow()
payload = {
'identity': self.dongle_id,
'nbf': now,
'iat': now,
'exp': now + timedelta(hours=expiry_hours)
}
token = jwt.encode(payload, self.private_key, algorithm='RS256')
if isinstance(token, bytes):
token = token.decode('utf8')
return token
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
headers = {}
if access_token is not None:
headers['Authorization'] = "JWT " + access_token
headers['User-Agent'] = "openpilot-" + get_version()
return requests.request(method, API_HOST + "/" + endpoint, timeout=timeout, headers=headers, params=params)
+7
View File
@@ -1,4 +1,11 @@
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"
+2 -1
View File
@@ -23,6 +23,7 @@
cl_device_id cl_get_device_id(cl_device_type device_type);
cl_context cl_create_context(cl_device_id device_id);
void cl_release_context(cl_context context);
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args = nullptr);
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args = nullptr);
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args);
const char* cl_get_error_string(int err);
-23
View File
@@ -1,23 +0,0 @@
import numpy as np
# conversions
class CV:
# Speed
MPH_TO_KPH = 1.609344
KPH_TO_MPH = 1. / MPH_TO_KPH
MS_TO_KPH = 3.6
KPH_TO_MS = 1. / MS_TO_KPH
MS_TO_MPH = MS_TO_KPH * KPH_TO_MPH
MPH_TO_MS = MPH_TO_KPH * KPH_TO_MS
MS_TO_KNOTS = 1.9438
KNOTS_TO_MS = 1. / MS_TO_KNOTS
# Angle
DEG_TO_RAD = np.pi / 180.
RAD_TO_DEG = 1. / DEG_TO_RAD
# Mass
LB_TO_KG = 0.453592
ACCELERATION_DUE_TO_GRAVITY = 9.81 # m/s^2
@@ -1,6 +1,5 @@
import numpy as np
class Conversions:
# Speed
MPH_TO_KPH = 1.609344
+9
View File
@@ -0,0 +1,9 @@
# remove all keys that end in DEPRECATED
def strip_deprecated_keys(d):
for k in list(d.keys()):
if isinstance(k, str):
if k.endswith('DEPRECATED'):
d.pop(k)
elif isinstance(d[k], dict):
strip_deprecated_keys(d[k])
return d
+55
View File
@@ -0,0 +1,55 @@
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
+99
View File
@@ -0,0 +1,99 @@
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()
class CallbackReader:
"""Wraps a file, but overrides the read method to also
call a callback function with the number of bytes read so far."""
def __init__(self, f, callback, *args):
self.f = f
self.callback = callback
self.cb_args = args
self.total_read = 0
def __getattr__(self, attr):
return getattr(self.f, attr)
def read(self, *args, **kwargs):
chunk = self.f.read(*args, **kwargs)
self.total_read += len(chunk)
self.callback(*self.cb_args, self.total_read)
return chunk
def _get_fileobject_func(writer, temp_dir):
def _get_fileobject():
return writer.get_fileobject(dir=temp_dir)
return _get_fileobject
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)))
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)))
+1 -17
View File
@@ -1,4 +1,5 @@
class FirstOrderFilter:
# first order filter
def __init__(self, x0, rc, dt, initialized=True):
self.x = x0
self.dt = dt
@@ -15,20 +16,3 @@ class FirstOrderFilter:
self.initialized = True
self.x = x
return self.x
class BounceFilter(FirstOrderFilter):
def __init__(self, x0, rc, dt, initialized=True, bounce=2):
self.velocity = FirstOrderFilter(0.0, 0.15, dt)
self.bounce = bounce
super().__init__(x0, rc, dt, initialized)
def update(self, x):
super().update(x)
scale = self.dt / (1.0 / 60.0) # tuned at 60 fps
self.velocity.x += (x - self.x) * self.bounce * scale * self.dt
self.velocity.update(0.0)
if abs(self.velocity.x) < 1e-5:
self.velocity.x = 0.0
self.x += self.velocity.x
return self.x
-42
View File
@@ -1,42 +0,0 @@
from functools import cache
import subprocess
from openpilot.common.utils import run_cmd, run_cmd_default
@cache
def get_commit(cwd: str = None, branch: str = "HEAD") -> str:
return run_cmd_default(["git", "rev-parse", branch], cwd=cwd)
@cache
def get_commit_date(cwd: str = None, commit: str = "HEAD") -> str:
return run_cmd_default(["git", "show", "--no-patch", "--format='%ct %ci'", commit], cwd=cwd)
@cache
def get_short_branch(cwd: str = None) -> str:
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=cwd)
@cache
def get_branch(cwd: str = None) -> str:
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], cwd=cwd)
@cache
def get_origin(cwd: str = None) -> str:
try:
local_branch = run_cmd(["git", "name-rev", "--name-only", "HEAD"], cwd=cwd)
tracking_remote = run_cmd(["git", "config", "branch." + local_branch + ".remote"], cwd=cwd)
return run_cmd(["git", "config", "remote." + tracking_remote + ".url"], cwd=cwd)
except subprocess.CalledProcessError: # Not on a branch, fallback
return run_cmd_default(["git", "config", "--get", "remote.origin.url"], cwd=cwd)
@cache
def get_normalized_origin(cwd: str = None) -> str:
return get_origin(cwd) \
.replace("git@", "", 1) \
.replace(".git", "", 1) \
.replace("https://", "", 1) \
.replace(":", "/", 1)
+33
View File
@@ -0,0 +1,33 @@
#pragma once
// Pin definitions
#ifdef QCOM2
#define GPIO_HUB_RST_N 30
#define GPIO_UBLOX_RST_N 32
#define GPIO_UBLOX_SAFEBOOT_N 33
#define GPIO_UBLOX_PWR_EN 34
#define GPIO_STM_RST_N 124
#define GPIO_STM_BOOT0 134
#define GPIO_BMX_ACCEL_INT 21
#define GPIO_BMX_GYRO_INT 23
#define GPIO_BMX_MAGN_INT 87
#define GPIO_LSM_INT 84
#define GPIOCHIP_INT 0
#else
#define GPIO_HUB_RST_N 0
#define GPIO_UBLOX_RST_N 0
#define GPIO_UBLOX_SAFEBOOT_N 0
#define GPIO_UBLOX_PWR_EN 0
#define GPIO_STM_RST_N 0
#define GPIO_STM_BOOT0 0
#define GPIO_BMX_ACCEL_INT 0
#define GPIO_BMX_GYRO_INT 0
#define GPIO_BMX_MAGN_INT 0
#define GPIO_LSM_INT 0
#define GPIOCHIP_INT 0
#endif
int gpio_init(int pin_nr, bool output);
int gpio_set(int pin_nr, bool high);
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr);
+6 -40
View File
@@ -1,7 +1,6 @@
import os
import fcntl
import ctypes
from functools import cache
from functools import lru_cache
from typing import Optional, List
def gpio_init(pin: int, output: bool) -> None:
try:
@@ -17,7 +16,7 @@ def gpio_set(pin: int, high: bool) -> None:
except Exception as e:
print(f"Failed to set gpio {pin} value: {e}")
def gpio_read(pin: int) -> bool | None:
def gpio_read(pin: int) -> Optional[bool]:
val = None
try:
with open(f"/sys/class/gpio/gpio{pin}/value", 'rb') as f:
@@ -37,8 +36,8 @@ def gpio_export(pin: int) -> None:
except Exception:
print(f"Failed to export gpio {pin}")
@cache
def get_irq_action(irq: int) -> list[str]:
@lru_cache(maxsize=None)
def get_irq_action(irq: int) -> List[str]:
try:
with open(f"/sys/kernel/irq/{irq}/actions") as f:
actions = f.read().strip().split(',')
@@ -46,7 +45,7 @@ def get_irq_action(irq: int) -> list[str]:
except FileNotFoundError:
return []
def get_irqs_for_action(action: str) -> list[str]:
def get_irqs_for_action(action: str) -> List[str]:
ret = []
with open("/proc/interrupts") as f:
for l in f.readlines():
@@ -54,36 +53,3 @@ def get_irqs_for_action(action: str) -> list[str]:
if irq.isdigit() and action in get_irq_action(irq):
ret.append(irq)
return ret
# *** gpiochip ***
class gpioevent_data(ctypes.Structure):
_fields_ = [
("timestamp", ctypes.c_uint64),
("id", ctypes.c_uint32),
]
class gpioevent_request(ctypes.Structure):
_fields_ = [
("lineoffset", ctypes.c_uint32),
("handleflags", ctypes.c_uint32),
("eventflags", ctypes.c_uint32),
("label", ctypes.c_char * 32),
("fd", ctypes.c_int)
]
def gpiochip_get_ro_value_fd(label: str, gpiochip_id: int, pin: int) -> int:
GPIOEVENT_REQUEST_BOTH_EDGES = 0x3
GPIOHANDLE_REQUEST_INPUT = 0x1
GPIO_GET_LINEEVENT_IOCTL = 0xc030b404
rq = gpioevent_request()
rq.lineoffset = pin
rq.handleflags = GPIOHANDLE_REQUEST_INPUT
rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES
rq.label = label.encode('utf-8')[:31] + b'\0'
fd = os.open(f"/dev/gpiochip{gpiochip_id}", os.O_RDONLY)
fcntl.ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, rq)
os.close(fd)
return int(rq.fd)
-8
View File
@@ -1,8 +0,0 @@
from openpilot.common.params import Params
def get_gps_location_service(params: Params) -> str:
if params.get_bool("UbloxAvailable"):
return "gpsLocationExternal"
else:
return "gpsLocation"
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include <array>
#include "common/mat.h"
#include "system/hardware/hw.h"
const int TRAJECTORY_SIZE = 33;
const float MIN_DRAW_DISTANCE = 10.0;
const float MAX_DRAW_DISTANCE = 100.0;
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 int TICI_CAM_WIDTH = 1928;
namespace tici_dm_crop {
const int x_offset = -72;
const int y_offset = -144;
const int width = 954;
};
const mat3 FCAM_INTRINSIC_MATRIX =
Hardware::EON() ? (mat3){{910., 0., 1164.0 / 2,
0., 910., 874.0 / 2,
0., 0., 1.}}
: (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}};
static inline mat3 get_model_yuv_transform(bool bayer = true) {
float db_s = Hardware::EON() ? 0.5 : 1.0; // debayering does a 2x downscale on EON
const mat3 transform = (mat3){{
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0
}};
return bayer ? transform_scale_buffer(transform, db_s) : transform;
}

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