mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-26 18:53:44 +08:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f370bf5ba6 | |||
| d6074e554d | |||
| b205dd6954 | |||
| 9e7fb4680d | |||
| 40982f18ab | |||
| 4d47e1243d | |||
| 9ff1fb48de | |||
| 51aa86da12 | |||
| 6e00ef601d | |||
| db7ea2a599 | |||
| 682dc5ddad | |||
| 3b62a21fa7 | |||
| ffe062c774 | |||
| 4fd2b0e730 | |||
| 2d659de09c | |||
| 35bd9d9fb3 | |||
| f878928731 | |||
| 771a8b7a55 | |||
| fcd5a66252 | |||
| 23bbf52578 |
@@ -1,25 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve openpilot
|
||||
title: ''
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**How to reproduce or log data**
|
||||
Steps to reproduce the behavior, or a explorer/cabana link to the exact drive and timestamp of when the bug occurred.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Device/Version information (please complete the following information):**
|
||||
- Device: [e.g. EON/EON Gold]
|
||||
- Version: [e.g. 0.6.4], or commit hash when on devel
|
||||
- Car make/model [e.g. Toyota Prius 2016]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -1,21 +0,0 @@
|
||||
Choose one of the templates below:
|
||||
|
||||
# Fingerprint
|
||||
This pull requests adds a fingerprint for <Make - Model - Year - Trim>.
|
||||
|
||||
This is an explorer link to a drive with the stock system enabled: ...
|
||||
|
||||
# Car support
|
||||
This pull requests adds support for <Make - Model - Year - Trim>.
|
||||
|
||||
This is an explorer link to a drive with the stock system enabled: ...
|
||||
This is an explorer link to a drive with openpilot system enabled: ...
|
||||
|
||||
# Feature
|
||||
This pull requests adds feature X
|
||||
|
||||
## Description
|
||||
Explain what the feature does
|
||||
|
||||
## Testing
|
||||
Explain how the feature was tested. Either by the added unit tests, or what tests were performed while driving.
|
||||
@@ -54,9 +54,15 @@ openpilot
|
||||
notebooks
|
||||
xx
|
||||
panda_jungle
|
||||
apks
|
||||
openpilot-apks
|
||||
|
||||
.coverage*
|
||||
coverage.xml
|
||||
htmlcov
|
||||
pandaextra
|
||||
|
||||
.mypy_cache/
|
||||
flycheck_*
|
||||
|
||||
cppcheck_report.txt
|
||||
|
||||
+4
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use.
|
||||
|
||||
Most open source development activity is coordinated through our [Discord](https://discord.comma.ai). A lot of documentation is available on our [medium](https://medium.com/@comma_ai/)
|
||||
Most open source development activity is coordinated through our [Discord](https://discord.comma.ai). A lot of documentation is available on our [medium](https://medium.com/@comma_ai/).
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -18,11 +18,11 @@ You can test your changes on your machine by running `run_docker_tests.sh`. This
|
||||
|
||||
### Automated Testing
|
||||
|
||||
All PRs are automatically checked by Github Actions. Check out `.github/workflows/` for what Github Actions runs. Any new tests sould be added to Github Actions.
|
||||
All PRs and commits are automatically checked by Github Actions. Check out `.github/workflows/` for what Github Actions runs. Any new tests sould be added to Github Actions.
|
||||
|
||||
### Code Style and Linting
|
||||
|
||||
Code is automatically checked for style by Github Actions as part of the automated tests. You can also run these tests yourself by running `pylint_openpilot.sh` and `flake8_openpilot.sh`.
|
||||
Code is automatically checked for style by Github Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
|
||||
|
||||
## Car Ports (openpilot)
|
||||
|
||||
@@ -48,3 +48,4 @@ Modules that are in seperate repositories include:
|
||||
* laika
|
||||
* opendbc
|
||||
* panda
|
||||
* rednose
|
||||
|
||||
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
pipeline {
|
||||
agent {
|
||||
docker {
|
||||
image 'python:3.7.3'
|
||||
args '--user=root'
|
||||
}
|
||||
}
|
||||
environment {
|
||||
COMMA_JWT = credentials('athena-test-jwt')
|
||||
}
|
||||
|
||||
stages {
|
||||
|
||||
stage('Release Build') {
|
||||
when {
|
||||
branch 'devel-staging'
|
||||
}
|
||||
steps {
|
||||
lock(resource: "", label: 'eon-build', inversePrecedence: true, variable: 'eon_ip', quantity: 1){
|
||||
timeout(time: 60, unit: 'MINUTES') {
|
||||
dir(path: 'selfdrive/test') {
|
||||
sh 'pip install paramiko'
|
||||
sh 'python phone_ci.py "cd release && PUSH=1 ./build_release2.sh"'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('On-device Tests') {
|
||||
when {
|
||||
not {
|
||||
anyOf {
|
||||
branch 'master-ci'; branch 'devel'; branch 'devel-staging'; branch 'release2'; branch 'release2-staging'; branch 'dashcam'; branch 'dashcam-staging'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parallel {
|
||||
|
||||
stage('Build') {
|
||||
environment {
|
||||
CI_PUSH = "${env.BRANCH_NAME == 'master' ? 'master-ci' : ''}"
|
||||
}
|
||||
|
||||
steps {
|
||||
lock(resource: "", label: 'eon', inversePrecedence: true, variable: 'eon_ip', quantity: 1){
|
||||
timeout(time: 60, unit: 'MINUTES') {
|
||||
dir(path: 'selfdrive/test') {
|
||||
sh 'pip install paramiko'
|
||||
sh 'python phone_ci.py "cd release && ./build_devel.sh"'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Replay Tests') {
|
||||
steps {
|
||||
lock(resource: "", label: 'eon2', inversePrecedence: true, variable: 'eon_ip', quantity: 1){
|
||||
timeout(time: 60, unit: 'MINUTES') {
|
||||
dir(path: 'selfdrive/test') {
|
||||
sh 'pip install paramiko'
|
||||
sh 'python phone_ci.py "cd selfdrive/test/process_replay && ./camera_replay.py"'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('HW Tests') {
|
||||
steps {
|
||||
lock(resource: "", label: 'eon', inversePrecedence: true, variable: 'eon_ip', quantity: 1){
|
||||
timeout(time: 60, unit: 'MINUTES') {
|
||||
dir(path: 'selfdrive/test') {
|
||||
sh 'pip install paramiko'
|
||||
sh 'python phone_ci.py "SCONS_CACHE=1 scons -j3 cereal/ && \
|
||||
nosetests -s selfdrive/test/test_sounds.py && \
|
||||
nosetests -s selfdrive/boardd/tests/test_boardd_loopback.py"'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,12 +67,12 @@ Supported Cars
|
||||
| Acura | ILX 2016-18 | AcuraWatch Plus | openpilot | 25mph<sup>1</sup> | 25mph |
|
||||
| Acura | RDX 2016-18 | AcuraWatch Plus | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||
| Honda | Accord 2018-19 | All | Stock | 0mph | 3mph |
|
||||
| Honda | Accord Hybrid 2018-19 | All | Stock | 0mph | 3mph |
|
||||
| Honda | Accord Hybrid 2018-20 | All | Stock | 0mph | 3mph |
|
||||
| Honda | Civic Hatchback 2017-19 | Honda Sensing | Stock | 0mph | 12mph |
|
||||
| Honda | Civic Sedan/Coupe 2016-18 | Honda Sensing | openpilot | 0mph | 12mph |
|
||||
| Honda | Civic Sedan/Coupe 2019-20 | Honda Sensing | Stock | 0mph | 2mph<sup>2</sup> |
|
||||
| Honda | CR-V 2015-16 | Touring | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||
| Honda | CR-V 2017-19 | Honda Sensing | Stock | 0mph | 12mph |
|
||||
| Honda | CR-V 2017-20 | Honda Sensing | Stock | 0mph | 12mph |
|
||||
| Honda | CR-V Hybrid 2017-2019 | Honda Sensing | Stock | 0mph | 12mph |
|
||||
| Honda | Fit 2018-19 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||
| Honda | HR-V 2019 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||
@@ -82,6 +82,7 @@ Supported Cars
|
||||
| Honda | Pilot 2016-18 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||
| Honda | Pilot 2019 | All | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||
| Honda | Ridgeline 2017-20 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
|
||||
| Hyundai | Sonata 2020 | All | Stock | 0mph | 0mph |
|
||||
| Lexus | CT Hybrid 2017-18 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Lexus | ES 2019 | All | openpilot | 0mph | 0mph |
|
||||
| Lexus | ES Hybrid 2019 | All | openpilot | 0mph | 0mph |
|
||||
@@ -91,6 +92,7 @@ Supported Cars
|
||||
| Lexus | RX 2016-17 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Lexus | RX 2020 | All | openpilot | 0mph | 0mph |
|
||||
| Lexus | RX Hybrid 2016-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Lexus | RX Hybrid 2020 | All | openpilot | 0mph | 0mph |
|
||||
| Toyota | Avalon 2016 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
|
||||
| Toyota | Avalon 2017-18 | All | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
|
||||
| Toyota | Camry 2018-20 | All | Stock | 0mph<sup>4</sup> | 0mph |
|
||||
@@ -106,7 +108,7 @@ Supported Cars
|
||||
| Toyota | Highlander 2020 | All | openpilot | 0mph | 0mph |
|
||||
| Toyota | Highlander Hybrid 2020 | All | openpilot | 0mph | 0mph |
|
||||
| Toyota | Prius 2016 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Toyota | Prius 2017-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Toyota | Prius 2017-20 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Toyota | Prius Prime 2017-20 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Toyota | Rav4 2016 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
|
||||
| Toyota | Rav4 2017-18 | All | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
|
||||
@@ -114,11 +116,11 @@ Supported Cars
|
||||
| Toyota | Rav4 Hybrid 2016 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Toyota | Rav4 Hybrid 2017-18 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Toyota | Rav4 Hybrid 2019-20 | All | openpilot | 0mph | 0mph |
|
||||
| Toyota | Sienna 2018 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
| Toyota | Sienna 2018-20 | All | Stock<sup>3</sup>| 0mph | 0mph |
|
||||
|
||||
<sup>1</sup>[Comma Pedal](https://community.comma.ai/wiki/index.php/Comma_Pedal) is used to provide stop-and-go capability to some of the openpilot-supported cars that don't currently support stop-and-go. Here is how to [build a Comma Pedal](https://medium.com/@jfrux/comma-pedal-building-with-macrofab-6328bea791e8). ***NOTE: The Comma Pedal is not officially supported by [comma](https://comma.ai).*** <br />
|
||||
<sup>1</sup>[Comma Pedal](https://github.com/commaai/openpilot/wiki/comma-pedal) is used to provide stop-and-go capability to some of the openpilot-supported cars that don't currently support stop-and-go. ***NOTE: The Comma Pedal is not officially supported by [comma](https://comma.ai).*** <br />
|
||||
<sup>2</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
|
||||
<sup>3</sup>When disconnecting the Driver Support Unit (DSU), openpilot ACC will replace stock ACC. For DSU locations, see [Toyota Wiki page](https://community.comma.ai/wiki/index.php/Toyota). ***NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).*** <br />
|
||||
<sup>3</sup>When disconnecting the Driver Support Unit (DSU), openpilot ACC will replace stock ACC. ***NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).*** <br />
|
||||
<sup>4</sup>28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
|
||||
|
||||
Community Maintained Cars and Features
|
||||
@@ -134,35 +136,37 @@ Community Maintained Cars and Features
|
||||
| Chrysler | Pacifica 2020 | Adaptive Cruise | Stock | 0mph | 39mph |
|
||||
| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph |
|
||||
| Chrysler | Pacifica Hybrid 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph |
|
||||
| Genesis | G80 2018<sup>2</sup> | All | Stock | 0mph | 0mph |
|
||||
| Genesis | G90 2018<sup>2</sup> | All | Stock | 0mph | 0mph |
|
||||
| GMC | Acadia Denali 2018<sup>3</sup>| Adaptive Cruise | openpilot | 0mph | 7mph |
|
||||
| Genesis | G80 2018 | All | Stock | 0mph | 0mph |
|
||||
| Genesis | G90 2018 | All | Stock | 0mph | 0mph |
|
||||
| GMC | Acadia Denali 2018<sup>2</sup>| Adaptive Cruise | openpilot | 0mph | 7mph |
|
||||
| Holden | Astra 2017<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
|
||||
| Hyundai | Elantra 2017-19<sup>2</sup> | SCC + LKAS | Stock | 19mph | 34mph |
|
||||
| Hyundai | Genesis 2015-16<sup>2</sup> | SCC + LKAS | Stock | 19mph | 37mph |
|
||||
| Hyundai | Ioniq 2017<sup>2</sup> | SCC + LKAS | Stock | 0mph | 32mph |
|
||||
| Hyundai | Ioniq 2019 EV<sup>2</sup> | SCC + LKAS | Stock | 0mph | 32mph |
|
||||
| Hyundai | Kona 2017-19<sup>2</sup> | SCC + LKAS | Stock | 22mph | 0mph |
|
||||
| Hyundai | Kona 2019 EV<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Hyundai | Palisade 2020<sup>2</sup> | All | Stock | 0mph | 0mph |
|
||||
| Hyundai | Santa Fe 2019<sup>2</sup> | All | Stock | 0mph | 0mph |
|
||||
| Hyundai | Sonata 2020<sup>2</sup> | All | Stock | 0mph | 0mph |
|
||||
| Hyundai | Elantra 2017-19 | SCC + LKAS | Stock | 19mph | 34mph |
|
||||
| Hyundai | Genesis 2015-16 | SCC + LKAS | Stock | 19mph | 37mph |
|
||||
| Hyundai | Ioniq Electric Premium SE 2020| SCC + LKAS | Stock | 0mph | 32mph |
|
||||
| Hyundai | Ioniq Electric Limited 2019 | SCC + LKAS | Stock | 0mph | 32mph |
|
||||
| Hyundai | Kona 2017-19 | SCC + LKAS | Stock | 22mph | 0mph |
|
||||
| Hyundai | Kona EV 2019 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Hyundai | Palisade 2020 | All | Stock | 0mph | 0mph |
|
||||
| Hyundai | Santa Fe 2019 | All | Stock | 0mph | 0mph |
|
||||
| Hyundai | Sonata 2019 | All | Stock | 0mph | 0mph |
|
||||
| Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Stock | 0mph | 9mph |
|
||||
| Jeep | Grand Cherokee 2019 | Adaptive Cruise | Stock | 0mph | 39mph |
|
||||
| Kia | Forte 2018<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Kia | Optima 2017<sup>2</sup> | SCC + LKAS/LDWS | Stock | 0mph | 32mph |
|
||||
| Kia | Optima 2019<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Kia | Sorento 2018<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Kia | Stinger 2018<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Nissan | Leaf 2019 | Propilot | Stock | 0mph | 0mph |
|
||||
| Nissan | X-Trail 2018 | Propilot | Stock | 0mph | 0mph |
|
||||
| Jeep | Grand Cherokee 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph |
|
||||
| Kia | Forte 2018-19 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Kia | Optima 2017 | SCC + LKAS/LDWS | Stock | 0mph | 32mph |
|
||||
| Kia | Optima 2019 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Kia | Sorento 2018 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Kia | Stinger 2018 | SCC + LKAS | Stock | 0mph | 0mph |
|
||||
| Nissan | Leaf 2018-19<sup>2</sup> | Propilot | Stock | 0mph | 0mph |
|
||||
| Nissan | Rogue 2019<sup>2</sup> | Propilot | Stock | 0mph | 0mph |
|
||||
| Nissan | X-Trail 2017<sup>2</sup> | Propilot | Stock | 0mph | 0mph |
|
||||
| Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph |
|
||||
| Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph |
|
||||
| Subaru | Impreza 2018-20 | EyeSight | Stock | 0mph | 0mph |
|
||||
| Volkswagen| Golf 2016-19<sup>3</sup> | Driver Assistance | Stock | 0mph | 0mph |
|
||||
| Subaru | Forester 2019 | EyeSight | Stock | 0mph | 0mph |
|
||||
| Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph |
|
||||
| Volkswagen| Golf 2015-19 | Driver Assistance | Stock | 0mph | 0mph |
|
||||
|
||||
<sup>1</sup>Requires a [panda](https://comma.ai/shop/products/panda-obd-ii-dongle) and [community built giraffe](https://zoneos.com/volt/). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).*** <br />
|
||||
<sup>2</sup>Requires a [panda](https://comma.ai/shop/products/panda-obd-ii-dongle) and open sourced [Hyundai giraffe](https://github.com/commaai/neo/tree/master/giraffe/hyundai), designed for the 2019 Sante Fe; pinout may differ for other Hyundai and Kia models. <br />
|
||||
<sup>3</sup>Requires a [custom connector](https://community.comma.ai/wiki/index.php/Volkswagen#Integration_at_R242_Camera) for the [car harness](https://comma.ai/shop/products/car-harness) <br />
|
||||
<sup>1</sup>Requires an [OBD-II car harness](https://comma.ai/shop/products/comma-car-harness) and [community built giraffe](https://github.com/commaai/openpilot/wiki/GM). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).*** <br />
|
||||
<sup>2</sup>Requires a custom connector for the developer [car harness](https://comma.ai/shop/products/car-harness) <br />
|
||||
|
||||
Although it's not upstream, there's a community of people getting openpilot to run on Tesla's [here](https://tinkla.us/)
|
||||
|
||||
@@ -175,7 +179,7 @@ Installation Instructions
|
||||
|
||||
Install openpilot on an EON or comma two by entering ``https://openpilot.comma.ai`` during the installer setup.
|
||||
|
||||
Follow these [video instructions](https://youtu.be/3nlkomHathI) to properly mount the device on the windshield. Note: openpilot features an automatic pose calibration routine and openpilot performance should not be affected by small pitch and yaw misalignments caused by imprecise device mounting.
|
||||
Follow these [video instructions](https://youtu.be/lcjqxCymins) to properly mount the device on the windshield. Note: openpilot features an automatic pose calibration routine and openpilot performance should not be affected by small pitch and yaw misalignments caused by imprecise device mounting.
|
||||
|
||||
Before placing the device on your windshield, check the state and local laws and ordinances where you drive. Some state laws prohibit or restrict the placement of objects on the windshield of a motor vehicle.
|
||||
|
||||
@@ -278,7 +282,7 @@ openpilot is developed by [comma](https://comma.ai/) and by users like you. We w
|
||||
|
||||
You can add support for your car by following guides we have written for [Brand](https://medium.com/@comma_ai/how-to-write-a-car-port-for-openpilot-7ce0785eda84) and [Model](https://medium.com/@comma_ai/openpilot-port-guide-for-toyota-models-e5467f4b5fe6) 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/). We also have a [bounty program](https://comma.ai/bounties.html).
|
||||
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs/).
|
||||
|
||||
And [follow us on Twitter](https://twitter.com/comma_ai).
|
||||
|
||||
@@ -328,6 +332,7 @@ 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>
|
||||
|
||||
[](https://github.com/commaai/openpilot/actions)
|
||||
[](https://lgtm.com/projects/g/commaai/openpilot/alerts/)
|
||||
[](https://lgtm.com/projects/g/commaai/openpilot/context:python)
|
||||
[](https://lgtm.com/projects/g/commaai/openpilot/context:cpp)
|
||||
|
||||
+26
-1
@@ -1,3 +1,29 @@
|
||||
Version 0.7.7 (2020-07-20)
|
||||
========================
|
||||
* White panda is no longer supported, upgrade to comma two or black panda
|
||||
* Improved vehicle model estimation using high precision localizer
|
||||
* Improved thermal management on comma two
|
||||
* Improved autofocus for road-facing camera
|
||||
* Improved noise performance for driver-facing camera
|
||||
* Block lane change start using blindspot monitor on select Toyota, Hyundai, and Subaru
|
||||
* Fix GM ignition detection
|
||||
* Code cleanup and smaller release sizes
|
||||
* Hyundai Sonata 2020 promoted to officially supported car
|
||||
* Hyundai Ioniq Electric Limited 2019 and Ioniq SE 2020 support thanks to baldwalker!
|
||||
* Subaru Forester 2019 and Ascent 2019 support thanks to martinl!
|
||||
|
||||
Version 0.7.6.1 (2020-06-16)
|
||||
========================
|
||||
* Hotfix: update kernel on some comma twos (orders #8570-#8680)
|
||||
|
||||
Version 0.7.6 (2020-06-05)
|
||||
========================
|
||||
* White panda is deprecated, upgrade to comma two or black panda
|
||||
* 2017 Nissan X-Trail, 2018-19 Leaf and 2019 Rogue support thanks to avolmensky!
|
||||
* 2017 Mazda CX-5 support in dashcam mode thanks to Jafaral!
|
||||
* Huge CPU savings in modeld by using thneed!
|
||||
* Lots of code cleanup and refactors
|
||||
|
||||
Version 0.7.5 (2020-05-13)
|
||||
========================
|
||||
* Right-Hand Drive support for both driving and driver monitoring!
|
||||
@@ -5,7 +31,6 @@ Version 0.7.5 (2020-05-13)
|
||||
* New driver monitoring model: overall improvement on comma two
|
||||
* Driver camera preview in settings to improve mounting position
|
||||
* Added support for many Hyundai, Kia, Genesis models thanks to xx979xx!
|
||||
* 2019 Nissan X-Trail and 2018 Nissan Leaf support thanks to avolmensky!
|
||||
* Improved lateral tuning for 2020 Toyota Rav 4 (hybrid)
|
||||
|
||||
Version 0.7.4 (2020-03-20)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openpilot Safety
|
||||
======
|
||||
|
||||
openpilot is an Adaptive Cruise Control (ACC) and Automated Lane Centering (ALC) system.
|
||||
openpilot is an Adaptive Cruise Control (ACC) and Automated Lane Centering (ALC) system.
|
||||
Like other ACC and ALC systems, openpilot is a failsafe passive system and it requires the
|
||||
driver to be alert and to pay attention at all times.
|
||||
|
||||
@@ -22,7 +22,7 @@ hardware-in-the-loop and in-vehicle tests before each software release.
|
||||
Following Hazard and Risk Analysis and FMEA, at a very high level, we have designed openpilot
|
||||
ensuring two main safety requirements.
|
||||
|
||||
1. The driver must always be capable to immediately retake manual control of the vehicle,
|
||||
1. The driver must always be capable to immediately retake manual control of the vehicle,
|
||||
by stepping on either pedal or by pressing the cancel button.
|
||||
2. The vehicle must not alter its trajectory too quickly for the driver to safely
|
||||
react. This means that while the system is engaged, the actuators are constrained
|
||||
|
||||
+59
-43
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import platform
|
||||
@@ -18,6 +19,7 @@ if arch == "aarch64" and not os.path.isdir("/system"):
|
||||
arch = "larch64"
|
||||
|
||||
webcam = bool(ARGUMENTS.get("use_webcam", 0))
|
||||
QCOM_REPLAY = arch == "aarch64" and os.getenv("QCOM_REPLAY") is not None
|
||||
|
||||
if arch == "aarch64" or arch == "larch64":
|
||||
lenv = {
|
||||
@@ -43,46 +45,52 @@ if arch == "aarch64" or arch == "larch64":
|
||||
]
|
||||
|
||||
if arch == "larch64":
|
||||
cpppath += ["#phonelibs/capnp-cpp/include"]
|
||||
libpath += ["#phonelibs/snpe/larch64"]
|
||||
libpath += ["#phonelibs/libyuv/larch64/lib"]
|
||||
libpath += ["#external/capnparm/lib", "/usr/lib/aarch64-linux-gnu"]
|
||||
libpath += [
|
||||
"#phonelibs/snpe/larch64",
|
||||
"#phonelibs/libyuv/larch64/lib",
|
||||
"/usr/lib/aarch64-linux-gnu"
|
||||
]
|
||||
cflags = ["-DQCOM2", "-mcpu=cortex-a57"]
|
||||
cxxflags = ["-DQCOM2", "-mcpu=cortex-a57"]
|
||||
rpath = ["/usr/local/lib"]
|
||||
else:
|
||||
libpath += ["#phonelibs/snpe/aarch64"]
|
||||
libpath += ["#phonelibs/libyuv/lib"]
|
||||
libpath += [
|
||||
"#phonelibs/snpe/aarch64",
|
||||
"#phonelibs/libyuv/lib"
|
||||
]
|
||||
cflags = ["-DQCOM", "-mcpu=cortex-a57"]
|
||||
cxxflags = ["-DQCOM", "-mcpu=cortex-a57"]
|
||||
rpath = ["/system/vendor/lib64"]
|
||||
|
||||
if QCOM_REPLAY:
|
||||
cflags += ["-DQCOM_REPLAY"]
|
||||
cxxflags += ["-DQCOM_REPLAY"]
|
||||
|
||||
else:
|
||||
cflags = []
|
||||
cxxflags = []
|
||||
|
||||
lenv = {
|
||||
"PATH": "#external/bin:" + os.environ['PATH'],
|
||||
}
|
||||
cpppath = [
|
||||
"#phonelibs/capnp-cpp/include",
|
||||
"#phonelibs/zmq/x64/include",
|
||||
"#external/tensorflow/include",
|
||||
]
|
||||
|
||||
if arch == "Darwin":
|
||||
libpath = [
|
||||
"#phonelibs/capnp-cpp/mac/lib",
|
||||
"#phonelibs/libyuv/mac/lib",
|
||||
"#cereal",
|
||||
"#selfdrive/common",
|
||||
"/usr/local/lib",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Libraries",
|
||||
]
|
||||
cflags += ["-DGL_SILENCE_DEPRECATION"]
|
||||
cxxflags += ["-DGL_SILENCE_DEPRECATION"]
|
||||
else:
|
||||
libpath = [
|
||||
"#phonelibs/capnp-cpp/x64/lib",
|
||||
"#phonelibs/snpe/x86_64-linux-clang",
|
||||
"#phonelibs/zmq/x64/lib",
|
||||
"#phonelibs/libyuv/x64/lib",
|
||||
"#external/zmq/lib",
|
||||
"#external/tensorflow/lib",
|
||||
"#cereal",
|
||||
"#selfdrive/common",
|
||||
@@ -90,20 +98,21 @@ else:
|
||||
"/usr/local/lib",
|
||||
]
|
||||
|
||||
rpath = ["phonelibs/capnp-cpp/x64/lib",
|
||||
"phonelibs/zmq/x64/lib",
|
||||
"external/tensorflow/lib",
|
||||
"cereal",
|
||||
"selfdrive/common"]
|
||||
rpath = [
|
||||
"external/tensorflow/lib",
|
||||
"cereal",
|
||||
"selfdrive/common"
|
||||
]
|
||||
|
||||
# allows shared libraries to work globally
|
||||
rpath = [os.path.join(os.getcwd(), x) for x in rpath]
|
||||
|
||||
cflags = []
|
||||
cxxflags = []
|
||||
|
||||
ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] if GetOption('asan') else []
|
||||
ldflags_asan = ["-fsanitize=address"] if GetOption('asan') else []
|
||||
if GetOption('asan'):
|
||||
ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"]
|
||||
ldflags_asan = ["-fsanitize=address"]
|
||||
else:
|
||||
ccflags_asan = []
|
||||
ldflags_asan = []
|
||||
|
||||
# change pythonpath to this
|
||||
lenv["PYTHONPATH"] = Dir("#").path
|
||||
@@ -114,11 +123,10 @@ env = Environment(
|
||||
"-g",
|
||||
"-fPIC",
|
||||
"-O2",
|
||||
"-Werror=implicit-function-declaration",
|
||||
"-Werror=incompatible-pointer-types",
|
||||
"-Werror=int-conversion",
|
||||
"-Werror=return-type",
|
||||
"-Werror=format-extra-args",
|
||||
"-Wunused",
|
||||
"-Werror",
|
||||
"-Wno-deprecated-register",
|
||||
"-Wno-inconsistent-missing-override",
|
||||
] + cflags + ccflags_asan,
|
||||
|
||||
CPPPATH=cpppath + [
|
||||
@@ -128,7 +136,6 @@ env = Environment(
|
||||
"#phonelibs/libyuv/include",
|
||||
"#phonelibs/openmax/include",
|
||||
"#phonelibs/json11",
|
||||
"#phonelibs/eigen",
|
||||
"#phonelibs/curl/include",
|
||||
#"#phonelibs/opencv/include", # use opencv4 instead
|
||||
"#phonelibs/libgralloc/include",
|
||||
@@ -156,8 +163,7 @@ env = Environment(
|
||||
|
||||
CFLAGS=["-std=gnu11"] + cflags,
|
||||
CXXFLAGS=["-std=c++14"] + cxxflags,
|
||||
LIBPATH=libpath +
|
||||
[
|
||||
LIBPATH=libpath + [
|
||||
"#cereal",
|
||||
"#selfdrive/common",
|
||||
"#phonelibs",
|
||||
@@ -165,7 +171,19 @@ env = Environment(
|
||||
)
|
||||
|
||||
if os.environ.get('SCONS_CACHE'):
|
||||
CacheDir('/tmp/scons_cache')
|
||||
cache_dir = '/tmp/scons_cache'
|
||||
|
||||
if os.getenv('CI'):
|
||||
branch = os.getenv('GIT_BRANCH')
|
||||
|
||||
if QCOM_REPLAY:
|
||||
cache_dir = '/tmp/scons_cache_qcom_replay'
|
||||
elif branch is not None and branch != 'master':
|
||||
cache_dir_branch = '/tmp/scons_cache_' + branch
|
||||
if not os.path.isdir(cache_dir_branch) and os.path.isdir(cache_dir):
|
||||
shutil.copytree(cache_dir, cache_dir_branch)
|
||||
cache_dir = cache_dir_branch
|
||||
CacheDir(cache_dir)
|
||||
|
||||
node_interval = 5
|
||||
node_count = 0
|
||||
@@ -189,11 +207,8 @@ def abspath(x):
|
||||
return x[0].path.rsplit("/", 1)[1][:-3]
|
||||
|
||||
# still needed for apks
|
||||
if arch == 'larch64':
|
||||
zmq = 'zmq'
|
||||
else:
|
||||
zmq = FindFile("libzmq.a", libpath)
|
||||
Export('env', 'arch', 'zmq', 'SHARED', 'webcam')
|
||||
zmq = 'zmq'
|
||||
Export('env', 'arch', 'zmq', 'SHARED', 'webcam', 'QCOM_REPLAY')
|
||||
|
||||
# cereal and messaging are shared with the system
|
||||
SConscript(['cereal/SConscript'])
|
||||
@@ -221,11 +236,11 @@ SConscript(['opendbc/can/SConscript'])
|
||||
|
||||
SConscript(['common/SConscript'])
|
||||
SConscript(['common/kalman/SConscript'])
|
||||
SConscript(['common/transformations/SConscript'])
|
||||
SConscript(['phonelibs/SConscript'])
|
||||
|
||||
if arch != "Darwin":
|
||||
SConscript(['selfdrive/camerad/SConscript'])
|
||||
SConscript(['selfdrive/modeld/SConscript'])
|
||||
SConscript(['selfdrive/camerad/SConscript'])
|
||||
SConscript(['selfdrive/modeld/SConscript'])
|
||||
|
||||
SConscript(['selfdrive/controls/lib/cluster/SConscript'])
|
||||
SConscript(['selfdrive/controls/lib/lateral_mpc/SConscript'])
|
||||
@@ -238,11 +253,12 @@ SConscript(['selfdrive/proclogd/SConscript'])
|
||||
SConscript(['selfdrive/ui/SConscript'])
|
||||
SConscript(['selfdrive/loggerd/SConscript'])
|
||||
|
||||
SConscript(['selfdrive/locationd/SConscript'])
|
||||
SConscript(['selfdrive/locationd/models/SConscript'])
|
||||
|
||||
if arch == "aarch64":
|
||||
SConscript(['selfdrive/logcatd/SConscript'])
|
||||
SConscript(['selfdrive/sensord/SConscript'])
|
||||
SConscript(['selfdrive/clocksd/SConscript'])
|
||||
|
||||
SConscript(['selfdrive/locationd/SConscript'])
|
||||
SConscript(['selfdrive/locationd/kalman/SConscript'])
|
||||
SConscript(['tools/lib/index_log/SConscript'])
|
||||
else:
|
||||
SConscript(['tools/lib/index_log/SConscript'])
|
||||
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
.sconsign.dblite
|
||||
Vendored
-23
@@ -1,23 +0,0 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
runs-on: ubuntu-16.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build docker image
|
||||
run: docker build -t cereal .
|
||||
- name: Unit Tests
|
||||
run: |
|
||||
docker run cereal bash -c "scons --test --asan -j$(nproc) && messaging/test_runner"
|
||||
- name: Test ZMQ
|
||||
run: |
|
||||
docker run cereal bash -c "ZMQ=1 python -m unittest discover ."
|
||||
- name: Test MSGQ
|
||||
run: |
|
||||
docker run cereal bash -c "MSGQ=1 python -m unittest discover ."
|
||||
|
||||
+1
-1
@@ -11,4 +11,4 @@ libmessaging_shared.*
|
||||
services.h
|
||||
.sconsign.dblite
|
||||
libcereal_shared.*
|
||||
|
||||
.mypy_cache/
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
from ubuntu:16.04
|
||||
|
||||
RUN apt-get update && apt-get install -y libzmq3-dev clang wget git autoconf libtool curl make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl
|
||||
|
||||
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.7.3
|
||||
RUN pyenv global 3.7.3
|
||||
RUN pyenv rehash
|
||||
RUN pip3 install pyyaml==5.1.2 Cython==0.29.14 scons==3.1.1 pycapnp==0.6.4
|
||||
|
||||
WORKDIR /project/cereal
|
||||
COPY install_capnp.sh .
|
||||
RUN ./install_capnp.sh
|
||||
|
||||
ENV PYTHONPATH=/project
|
||||
|
||||
COPY . .
|
||||
RUN scons -c && scons -j$(nproc)
|
||||
@@ -1,41 +0,0 @@
|
||||
What is cereal?
|
||||
----
|
||||
|
||||
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
|
||||
----
|
||||
|
||||
You'll find the message types in [log.capnp](log.capnp). It uses [Cap'n proto](https://capnproto.org/capnp-tool.html) and defines one struct called Event.
|
||||
|
||||
All Events have a logMonoTime and a valid. Then a big union defines the packet type.
|
||||
|
||||
|
||||
Pub Sub Backends
|
||||
----
|
||||
|
||||
cereal supports two backends, one based on [zmq](https://zeromq.org/), the other called msgq, a custom pub sub based on shared memory that doesn't require the bytes to pass through the kernel.
|
||||
|
||||
Example
|
||||
---
|
||||
```python
|
||||
import cereal.messaging as messaging
|
||||
|
||||
# in subscriber
|
||||
sm = messaging.SubMaster(['sensorEvents'])
|
||||
while 1:
|
||||
sm.update()
|
||||
print(sm['sensorEvents'])
|
||||
|
||||
# in publisher
|
||||
pm = messaging.PubMaster(['sensorEvents'])
|
||||
dat = messaging.new_message('sensorEvents', size=1)
|
||||
dat.sensorEvents[0] = {"gyro": {"v": [0.1, -0.1, 0.1]}}
|
||||
pm.send('sensorEvents', dat)
|
||||
```
|
||||
+5
-2
@@ -36,6 +36,7 @@ messaging_objects = env.SharedObject([
|
||||
'messaging/impl_zmq.cc',
|
||||
'messaging/impl_msgq.cc',
|
||||
'messaging/msgq.cc',
|
||||
'messaging/socketmaster.cc',
|
||||
])
|
||||
|
||||
messaging_lib = env.Library('messaging', messaging_objects)
|
||||
@@ -43,8 +44,10 @@ Depends('messaging/impl_zmq.cc', services_h)
|
||||
|
||||
# note, this rebuilds the deps shared, zmq is statically linked to make APK happy
|
||||
# TODO: get APK to load system zmq to remove the static link
|
||||
shared_lib_shared_lib = [zmq, 'm', 'stdc++'] + ["gnustl_shared"] if arch == "aarch64" else [zmq]
|
||||
env.SharedLibrary('messaging_shared', messaging_objects, LIBS=shared_lib_shared_lib)
|
||||
if arch == "aarch64":
|
||||
zmq_static = FindFile("libzmq.a", "/usr/lib")
|
||||
shared_lib_shared_lib = [zmq_static, 'm', 'stdc++', "gnustl_shared", "kj", "capnp"]
|
||||
env.SharedLibrary('messaging_shared', messaging_objects, LIBS=shared_lib_shared_lib)
|
||||
|
||||
env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[messaging_lib, 'zmq'])
|
||||
Depends('messaging/bridge.cc', services_h)
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
zmq = 'zmq'
|
||||
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
|
||||
|
||||
cereal_dir = Dir('.')
|
||||
|
||||
cpppath = [
|
||||
cereal_dir,
|
||||
'/usr/lib/include',
|
||||
]
|
||||
|
||||
AddOption('--test',
|
||||
action='store_true',
|
||||
help='build test files')
|
||||
|
||||
AddOption('--asan',
|
||||
action='store_true',
|
||||
help='turn on ASAN')
|
||||
|
||||
ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] if GetOption('asan') else []
|
||||
ldflags_asan = ["-fsanitize=address"] if GetOption('asan') else []
|
||||
|
||||
env = Environment(
|
||||
ENV=os.environ,
|
||||
CC='clang',
|
||||
CXX='clang++',
|
||||
CCFLAGS=[
|
||||
"-g",
|
||||
"-fPIC",
|
||||
"-O2",
|
||||
"-Werror=implicit-function-declaration",
|
||||
"-Werror=incompatible-pointer-types",
|
||||
"-Werror=int-conversion",
|
||||
"-Werror=return-type",
|
||||
"-Werror=format-extra-args",
|
||||
] + ccflags_asan,
|
||||
LDFLAGS=ldflags_asan,
|
||||
LINKFLAGS=ldflags_asan,
|
||||
|
||||
CFLAGS="-std=gnu11",
|
||||
CXXFLAGS="-std=c++14",
|
||||
CPPPATH=cpppath,
|
||||
)
|
||||
|
||||
|
||||
Export('env', 'zmq', 'arch')
|
||||
SConscript(['SConscript'])
|
||||
@@ -1,3 +1,4 @@
|
||||
# pylint: skip-file
|
||||
import os
|
||||
import capnp
|
||||
|
||||
|
||||
+26
-9
@@ -13,12 +13,12 @@ struct CarEvent @0x9b1657f34caf3ad3 {
|
||||
name @0 :EventName;
|
||||
enable @1 :Bool;
|
||||
noEntry @2 :Bool;
|
||||
warning @3 :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;
|
||||
permanent @8 :Bool; # alerts presented regardless of openpilot state
|
||||
|
||||
enum EventName @0xbaa8c5d505f727de {
|
||||
# TODO: copy from error list
|
||||
@@ -38,7 +38,7 @@ struct CarEvent @0x9b1657f34caf3ad3 {
|
||||
pedalPressed @13;
|
||||
cruiseDisabled @14;
|
||||
radarCanError @15;
|
||||
dataNeeded @16;
|
||||
dataNeededDEPRECATED @16;
|
||||
speedTooLow @17;
|
||||
outOfSpace @18;
|
||||
overheat @19;
|
||||
@@ -55,23 +55,23 @@ struct CarEvent @0x9b1657f34caf3ad3 {
|
||||
manualRestart @30;
|
||||
lowSpeedLockout @31;
|
||||
plannerError @32;
|
||||
ipasOverride @33;
|
||||
ipasOverrideDEPRECATED @33;
|
||||
debugAlert @34;
|
||||
steerTempUnavailableMute @35;
|
||||
resumeRequired @36;
|
||||
preDriverDistracted @37;
|
||||
promptDriverDistracted @38;
|
||||
driverDistracted @39;
|
||||
geofence @40;
|
||||
driverMonitorOn @41;
|
||||
driverMonitorOff @42;
|
||||
geofenceDEPRECATED @40;
|
||||
driverMonitorOnDEPRECATED @41;
|
||||
driverMonitorOffDEPRECATED @42;
|
||||
preDriverUnresponsive @43;
|
||||
promptDriverUnresponsive @44;
|
||||
driverUnresponsive @45;
|
||||
belowSteerSpeed @46;
|
||||
calibrationProgress @47;
|
||||
calibrationProgressDEPRECATED @47;
|
||||
lowBattery @48;
|
||||
invalidGiraffeHonda @49;
|
||||
invalidGiraffeHondaDEPRECATED @49;
|
||||
vehicleModelInvalid @50;
|
||||
controlsFailed @51;
|
||||
sensorDataInvalid @52;
|
||||
@@ -97,6 +97,21 @@ struct CarEvent @0x9b1657f34caf3ad3 {
|
||||
relayMalfunction @72;
|
||||
gasPressed @73;
|
||||
stockFcw @74;
|
||||
startup @75;
|
||||
startupNoCar @76;
|
||||
startupNoControl @77;
|
||||
startupMaster @78;
|
||||
fcw @79;
|
||||
steerSaturated @80;
|
||||
whitePandaUnsupported @81;
|
||||
startupWhitePanda @82;
|
||||
canErrorPersistentDEPRECATED @83;
|
||||
belowEngageSpeed @84;
|
||||
noGps @85;
|
||||
focusRecoverActive @86;
|
||||
wrongCruiseMode @87;
|
||||
neosUpdateRequired @88;
|
||||
modeldLagging @89;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +193,7 @@ struct CarState {
|
||||
available @2 :Bool;
|
||||
speedOffset @3 :Float32;
|
||||
standstill @4 :Bool;
|
||||
nonAdaptive @5 :Bool;
|
||||
}
|
||||
|
||||
enum GearShifter {
|
||||
@@ -457,6 +473,7 @@ struct CarParams {
|
||||
hondaBoschHarness @20;
|
||||
volkswagenPq @21;
|
||||
subaruLegacy @22; # pre-Global platform
|
||||
hyundaiLegacy @23;
|
||||
}
|
||||
|
||||
enum SteerControlType {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/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
|
||||
@@ -1,40 +0,0 @@
|
||||
set -e
|
||||
echo "Installing capnp"
|
||||
|
||||
cd /tmp
|
||||
VERSION=0.6.1
|
||||
wget https://capnproto.org/capnproto-c++-${VERSION}.tar.gz
|
||||
tar xvf capnproto-c++-${VERSION}.tar.gz
|
||||
cd capnproto-c++-${VERSION}
|
||||
CXXFLAGS="-fPIC" ./configure
|
||||
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
# manually build binaries statically
|
||||
g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnp src/capnp/compiler/module-loader.o src/capnp/compiler/capnp.o ./.libs/libcapnpc.a ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread
|
||||
|
||||
g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnpc-c++ src/capnp/compiler/capnpc-c++.o ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread
|
||||
|
||||
g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnpc-capnp src/capnp/compiler/capnpc-capnp.o ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread
|
||||
|
||||
cp .libs/capnp /usr/local/bin/
|
||||
cp .libs/capnpc-c++ /usr/local/bin/
|
||||
cp .libs/capnpc-capnp /usr/local/bin/
|
||||
cp .libs/*.a /usr/local/lib
|
||||
|
||||
cd /tmp
|
||||
echo "Installing c-capnp"
|
||||
git clone https://github.com/commaai/c-capnproto.git
|
||||
cd c-capnproto
|
||||
git submodule update --init --recursive
|
||||
autoreconf -f -i -s
|
||||
CXXFLAGS="-fPIC" ./configure
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
# manually build binaries statically
|
||||
gcc -fPIC -o .libs/capnpc-c compiler/capnpc-c.o compiler/schema.capnp.o compiler/str.o ./.libs/libcapnp_c.a
|
||||
|
||||
cp .libs/capnpc-c /usr/local/bin/
|
||||
cp .libs/*.a /usr/local/lib
|
||||
+12
-2
@@ -130,6 +130,7 @@ struct FrameData {
|
||||
focusVal @16 :List(Int16);
|
||||
focusConf @17 :List(UInt8);
|
||||
sharpnessScore @18 :List(UInt16);
|
||||
recoverState @19 :Int32;
|
||||
|
||||
frameType @7 :FrameType;
|
||||
timestampSof @8 :UInt64;
|
||||
@@ -371,6 +372,7 @@ struct HealthData {
|
||||
interruptRateTim1 @16;
|
||||
interruptRateTim3 @17;
|
||||
registerDivergent @18;
|
||||
interruptRateKlineInit @19;
|
||||
# Update max fault type in boardd when adding faults
|
||||
}
|
||||
|
||||
@@ -381,6 +383,7 @@ struct HealthData {
|
||||
blackPanda @3;
|
||||
pedal @4;
|
||||
uno @5;
|
||||
dos @6;
|
||||
}
|
||||
|
||||
enum UsbPowerMode {
|
||||
@@ -596,8 +599,6 @@ struct ControlsState @0x97ff69c53601abf1 {
|
||||
lqrOutput @4 :Float32;
|
||||
saturated @5 :Bool;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
struct LiveEventData {
|
||||
@@ -607,6 +608,8 @@ struct LiveEventData {
|
||||
|
||||
struct ModelData {
|
||||
frameId @0 :UInt32;
|
||||
frameAge @12 :UInt32;
|
||||
frameDropPerc @13 :Float32;
|
||||
timestampEof @9 :UInt64;
|
||||
|
||||
path @1 :PathData;
|
||||
@@ -627,6 +630,7 @@ struct ModelData {
|
||||
std @2 :Float32;
|
||||
stds @3 :List(Float32);
|
||||
poly @4 :List(Float32);
|
||||
validLen @5 :Float32;
|
||||
}
|
||||
|
||||
struct LeadData {
|
||||
@@ -839,6 +843,7 @@ struct LiveLocationKalman {
|
||||
# These angles are all eulers and roll, pitch, yaw
|
||||
# orientationECEF transforms to rot matrix: ecef_from_device
|
||||
orientationECEF @6 : Measurement;
|
||||
calibratedOrientationECEF @20 : Measurement;
|
||||
orientationNED @7 : Measurement;
|
||||
angularVelocityDevice @8 : Measurement;
|
||||
|
||||
@@ -855,6 +860,10 @@ struct LiveLocationKalman {
|
||||
gpsTimeOfWeek @14 :Float64;
|
||||
status @15 :Status;
|
||||
unixTimestampMillis @16 :Int64;
|
||||
inputsOK @17 :Bool = true;
|
||||
posenetOK @18 :Bool = true;
|
||||
gpsOK @19 :Bool = true;
|
||||
sensorsOK @21 :Bool = true;
|
||||
|
||||
enum Status {
|
||||
uninitialized @0;
|
||||
@@ -1882,6 +1891,7 @@ struct DriverState {
|
||||
irPwrDEPRECATED @10 :Float32;
|
||||
faceOrientationStd @11 :List(Float32);
|
||||
facePositionStd @12 :List(Float32);
|
||||
sgProb @13 :Float32;
|
||||
}
|
||||
|
||||
struct DMonitoringState {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
using Cxx = import "./include/c++.capnp";
|
||||
$Cxx.namespace("cereal");
|
||||
|
||||
using Java = import "./include/java.capnp";
|
||||
$Java.package("ai.comma.openpilot.cereal");
|
||||
$Java.outerClassname("Map");
|
||||
|
||||
@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);
|
||||
}
|
||||
@@ -3,12 +3,12 @@ from .messaging_pyx import Context, Poller, SubSocket, PubSocket # pylint: disa
|
||||
from .messaging_pyx import MultiplePublishersError, MessagingError # pylint: disable=no-name-in-module, import-error
|
||||
import capnp
|
||||
|
||||
assert MultiplePublishersError
|
||||
assert MessagingError
|
||||
|
||||
from cereal import log
|
||||
from cereal.services import service_list
|
||||
|
||||
assert MultiplePublishersError
|
||||
assert MessagingError
|
||||
|
||||
# sec_since_boot is faster, but allow to run standalone too
|
||||
try:
|
||||
from common.realtime import sec_since_boot
|
||||
@@ -73,7 +73,7 @@ def drain_sock(sock, wait_for_one=False):
|
||||
else:
|
||||
dat = sock.receive(non_blocking=True)
|
||||
|
||||
if dat is None: # Timeout hit
|
||||
if dat is None: # Timeout hit
|
||||
break
|
||||
|
||||
dat = log.Event.from_bytes(dat)
|
||||
@@ -93,7 +93,7 @@ def recv_sock(sock, wait=False):
|
||||
else:
|
||||
rcv = sock.receive(non_blocking=True)
|
||||
|
||||
if rcv is None: # Timeout hit
|
||||
if rcv is None: # Timeout hit
|
||||
break
|
||||
|
||||
dat = rcv
|
||||
@@ -133,10 +133,10 @@ class SubMaster():
|
||||
def __init__(self, services, ignore_alive=None, addr="127.0.0.1"):
|
||||
self.poller = Poller()
|
||||
self.frame = -1
|
||||
self.updated = {s : False 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.updated = {s: False 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.sock = {}
|
||||
self.freq = {}
|
||||
self.data = {}
|
||||
@@ -155,7 +155,7 @@ class SubMaster():
|
||||
|
||||
try:
|
||||
data = new_message(s)
|
||||
except capnp.lib.capnp.KjException:
|
||||
except capnp.lib.capnp.KjException: # pylint: disable=c-extension-no-member
|
||||
# lists
|
||||
data = new_message(s, 0)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <cstddef>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <cassert>
|
||||
|
||||
#include "messaging.hpp"
|
||||
#include "impl_zmq.hpp"
|
||||
|
||||
#define MSGS 1e5
|
||||
|
||||
int main() {
|
||||
Context * c = Context::create();
|
||||
SubSocket * sub_sock = SubSocket::create(c, "controlsState");
|
||||
PubSocket * pub_sock = PubSocket::create(c, "controlsState");
|
||||
|
||||
char data[8];
|
||||
|
||||
Poller * poller = Poller::create({sub_sock});
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
for (uint64_t i = 0; i < MSGS; i++){
|
||||
*(uint64_t*)data = i;
|
||||
pub_sock->send(data, 8);
|
||||
|
||||
auto r = poller->poll(100);
|
||||
|
||||
for (auto p : r){
|
||||
Message * m = p->receive();
|
||||
uint64_t ii = *(uint64_t*)m->getData();
|
||||
assert(i == ii);
|
||||
delete m;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
double elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count() / 1e9;
|
||||
double throughput = ((double) MSGS / (double) elapsed);
|
||||
std::cout << throughput << " msg/s" << std::endl;
|
||||
|
||||
delete poller;
|
||||
delete sub_sock;
|
||||
delete pub_sock;
|
||||
delete c;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
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))
|
||||
@@ -143,7 +143,11 @@ int MSGQPubSocket::connect(Context *context, std::string endpoint){
|
||||
assert(context);
|
||||
|
||||
q = new msgq_queue_t;
|
||||
msgq_new_queue(q, endpoint.c_str(), DEFAULT_SEGMENT_SIZE);
|
||||
int r = msgq_new_queue(q, endpoint.c_str(), DEFAULT_SEGMENT_SIZE);
|
||||
if (r != 0){
|
||||
return r;
|
||||
}
|
||||
|
||||
msgq_init_publisher(q);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
#include "impl_zmq.hpp"
|
||||
#include "impl_msgq.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
const bool MUST_USE_ZMQ = true;
|
||||
#else
|
||||
const bool MUST_USE_ZMQ = false;
|
||||
#endif
|
||||
|
||||
Context * Context::create(){
|
||||
Context * c;
|
||||
if (std::getenv("ZMQ")){
|
||||
if (std::getenv("ZMQ") || MUST_USE_ZMQ){
|
||||
c = new ZMQContext();
|
||||
} else {
|
||||
c = new MSGQContext();
|
||||
@@ -14,7 +20,7 @@ Context * Context::create(){
|
||||
|
||||
SubSocket * SubSocket::create(){
|
||||
SubSocket * s;
|
||||
if (std::getenv("ZMQ")){
|
||||
if (std::getenv("ZMQ") || MUST_USE_ZMQ){
|
||||
s = new ZMQSubSocket();
|
||||
} else {
|
||||
s = new MSGQSubSocket();
|
||||
@@ -60,7 +66,7 @@ SubSocket * SubSocket::create(Context * context, std::string endpoint, std::stri
|
||||
|
||||
PubSocket * PubSocket::create(){
|
||||
PubSocket * s;
|
||||
if (std::getenv("ZMQ")){
|
||||
if (std::getenv("ZMQ") || MUST_USE_ZMQ){
|
||||
s = new ZMQPubSocket();
|
||||
} else {
|
||||
s = new MSGQPubSocket();
|
||||
@@ -82,7 +88,7 @@ PubSocket * PubSocket::create(Context * context, std::string endpoint){
|
||||
|
||||
Poller * Poller::create(){
|
||||
Poller * p;
|
||||
if (std::getenv("ZMQ")){
|
||||
if (std::getenv("ZMQ") || MUST_USE_ZMQ){
|
||||
p = new ZMQPoller();
|
||||
} else {
|
||||
p = new MSGQPoller();
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <capnp/serialize.h>
|
||||
#include "../gen/cpp/log.capnp.h"
|
||||
|
||||
#define MSG_MULTIPLE_PUBLISHERS 100
|
||||
|
||||
@@ -54,3 +57,36 @@ public:
|
||||
static Poller * create(std::vector<SubSocket*> sockets);
|
||||
virtual ~Poller(){};
|
||||
};
|
||||
|
||||
class SubMaster {
|
||||
public:
|
||||
SubMaster(const std::initializer_list<const char *> &service_list,
|
||||
const char *address = nullptr, const std::initializer_list<const char *> &ignore_alive = {});
|
||||
int update(int timeout = 1000);
|
||||
inline bool allAlive(const std::initializer_list<const char *> &service_list = {}) { return all_(service_list, false, true); }
|
||||
inline bool allValid(const std::initializer_list<const char *> &service_list = {}) { return all_(service_list, true, false); }
|
||||
inline bool allAliveAndValid(const std::initializer_list<const char *> &service_list = {}) { return all_(service_list, true, true); }
|
||||
bool updated(const char *name) const;
|
||||
void drain();
|
||||
cereal::Event::Reader &operator[](const char *name);
|
||||
~SubMaster();
|
||||
|
||||
private:
|
||||
bool all_(const std::initializer_list<const char *> &service_list, bool valid, bool alive);
|
||||
Poller *poller_ = nullptr;
|
||||
uint64_t frame_ = 0;
|
||||
struct SubMessage;
|
||||
std::map<SubSocket *, SubMessage *> messages_;
|
||||
std::map<std::string, SubMessage *> services_;
|
||||
};
|
||||
|
||||
class PubMaster {
|
||||
public:
|
||||
PubMaster(const std::initializer_list<const char *> &service_list);
|
||||
inline int send(const char *name, capnp::byte *data, size_t size) { return sockets_.at(name)->send((char *)data, size); }
|
||||
int send(const char *name, capnp::MessageBuilder &msg);
|
||||
~PubMaster();
|
||||
|
||||
private:
|
||||
std::map<std::string, PubSocket *> sockets_;
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@ class BuildExtWithoutPlatformSuffix(build_ext):
|
||||
|
||||
|
||||
sourcefiles = ['messaging_pyx.pyx']
|
||||
extra_compile_args = ["-std=c++11"]
|
||||
extra_compile_args = ["-std=c++14"]
|
||||
libraries = ['zmq']
|
||||
ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pylint: disable=unexpected-keyword-arg
|
||||
|
||||
|
||||
@@ -31,7 +31,13 @@ uint64_t msgq_get_uid(void){
|
||||
std::random_device rd("/dev/urandom");
|
||||
std::uniform_int_distribution<uint64_t> distribution(0,std::numeric_limits<uint32_t>::max());
|
||||
|
||||
uint64_t uid = distribution(rd) << 32 | syscall(SYS_gettid);
|
||||
#ifdef __APPLE__
|
||||
// TODO: this doesn't work
|
||||
uint64_t uid = distribution(rd) << 32 | getpid();
|
||||
#else
|
||||
uint64_t uid = distribution(rd) << 32 | syscall(SYS_gettid);
|
||||
#endif
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
@@ -88,10 +94,12 @@ int msgq_new_queue(msgq_queue_t * q, const char * path, size_t size){
|
||||
strcat(full_path, path);
|
||||
|
||||
auto fd = open(full_path, O_RDWR | O_CREAT, 0777);
|
||||
delete[] full_path;
|
||||
|
||||
if (fd < 0)
|
||||
if (fd < 0) {
|
||||
std::cout << "Warning, could not open: " << full_path << std::endl;
|
||||
delete[] full_path;
|
||||
return -1;
|
||||
}
|
||||
delete[] full_path;
|
||||
|
||||
int rc = ftruncate(fd, size + sizeof(msgq_header_t));
|
||||
if (rc < 0)
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
# MSGQ: A lock free single producer multi consumer message queue
|
||||
|
||||
[](https://dev.azure.com/commaai/default/_build/latest?definitionId=21&branchName=master)
|
||||
|
||||
## 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.
|
||||
@@ -1,395 +0,0 @@
|
||||
#include "catch2/catch.hpp"
|
||||
#include "msgq.hpp"
|
||||
|
||||
TEST_CASE("ALIGN"){
|
||||
REQUIRE(ALIGN(0) == 0);
|
||||
REQUIRE(ALIGN(1) == 8);
|
||||
REQUIRE(ALIGN(7) == 8);
|
||||
REQUIRE(ALIGN(8) == 8);
|
||||
REQUIRE(ALIGN(99999) == 100000);
|
||||
}
|
||||
|
||||
TEST_CASE("msgq_msg_init_size"){
|
||||
const size_t msg_size = 30;
|
||||
msgq_msg_t msg;
|
||||
|
||||
msgq_msg_init_size(&msg, msg_size);
|
||||
REQUIRE(msg.size == msg_size);
|
||||
|
||||
msgq_msg_close(&msg);
|
||||
}
|
||||
|
||||
TEST_CASE("msgq_msg_init_data"){
|
||||
const size_t msg_size = 30;
|
||||
char * data = new char[msg_size];
|
||||
|
||||
for (size_t i = 0; i < msg_size; i++){
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
msgq_msg_t msg;
|
||||
msgq_msg_init_data(&msg, data, msg_size);
|
||||
|
||||
REQUIRE(msg.size == msg_size);
|
||||
REQUIRE(memcmp(msg.data, data, msg_size) == 0);
|
||||
|
||||
delete[] data;
|
||||
msgq_msg_close(&msg);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("msgq_init_subscriber"){
|
||||
remove("/dev/shm/test_queue");
|
||||
msgq_queue_t q;
|
||||
msgq_new_queue(&q, "test_queue", 1024);
|
||||
REQUIRE(*q.num_readers == 0);
|
||||
|
||||
q.reader_id = 1;
|
||||
*q.read_valids[0] = false;
|
||||
*q.read_pointers[0] = ((uint64_t)1 << 32);
|
||||
|
||||
*q.write_pointer = 255;
|
||||
|
||||
msgq_init_subscriber(&q);
|
||||
REQUIRE(q.read_conflate == false);
|
||||
REQUIRE(*q.read_valids[0] == true);
|
||||
REQUIRE((*q.read_pointers[0] >> 32) == 0);
|
||||
REQUIRE((*q.read_pointers[0] & 0xFFFFFFFF) == 255);
|
||||
}
|
||||
|
||||
TEST_CASE("msgq_msg_send first message"){
|
||||
remove("/dev/shm/test_queue");
|
||||
msgq_queue_t q;
|
||||
msgq_new_queue(&q, "test_queue", 1024);
|
||||
msgq_init_publisher(&q);
|
||||
|
||||
REQUIRE(*q.write_pointer == 0);
|
||||
|
||||
size_t msg_size = 128;
|
||||
|
||||
SECTION("Aligned message size"){
|
||||
}
|
||||
SECTION("Unaligned message size"){
|
||||
msg_size--;
|
||||
}
|
||||
|
||||
char * data = new char[msg_size];
|
||||
|
||||
for (size_t i = 0; i < msg_size; i++){
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
msgq_msg_t msg;
|
||||
msgq_msg_init_data(&msg, data, msg_size);
|
||||
|
||||
|
||||
msgq_msg_send(&msg, &q);
|
||||
REQUIRE(*(int64_t*)q.data == msg_size); // Check size tag
|
||||
REQUIRE(*q.write_pointer == 128 + sizeof(int64_t));
|
||||
REQUIRE(memcmp(q.data + sizeof(int64_t), data, msg_size) == 0);
|
||||
|
||||
delete[] data;
|
||||
msgq_msg_close(&msg);
|
||||
}
|
||||
|
||||
TEST_CASE("msgq_msg_send test wraparound"){
|
||||
remove("/dev/shm/test_queue");
|
||||
msgq_queue_t q;
|
||||
msgq_new_queue(&q, "test_queue", 1024);
|
||||
msgq_init_publisher(&q);
|
||||
|
||||
REQUIRE((*q.write_pointer & 0xFFFFFFFF) == 0);
|
||||
REQUIRE((*q.write_pointer >> 32) == 0);
|
||||
|
||||
const size_t msg_size = 120;
|
||||
msgq_msg_t msg;
|
||||
msgq_msg_init_size(&msg, msg_size);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
msgq_msg_send(&msg, &q);
|
||||
}
|
||||
// Check 8th message was written at the beginning
|
||||
REQUIRE((*q.write_pointer & 0xFFFFFFFF) == msg_size + sizeof(int64_t));
|
||||
|
||||
// Check cycle count
|
||||
REQUIRE((*q.write_pointer >> 32) == 1);
|
||||
|
||||
// Check wraparound tag
|
||||
char * tag_location = q.data;
|
||||
tag_location += 7 * (msg_size + sizeof(int64_t));
|
||||
REQUIRE(*(int64_t*)tag_location == -1);
|
||||
|
||||
msgq_msg_close(&msg);
|
||||
}
|
||||
|
||||
TEST_CASE("msgq_msg_recv test wraparound"){
|
||||
remove("/dev/shm/test_queue");
|
||||
msgq_queue_t q_pub, q_sub;
|
||||
msgq_new_queue(&q_pub, "test_queue", 1024);
|
||||
msgq_new_queue(&q_sub, "test_queue", 1024);
|
||||
|
||||
msgq_init_publisher(&q_pub);
|
||||
msgq_init_subscriber(&q_sub);
|
||||
|
||||
REQUIRE((*q_pub.write_pointer >> 32) == 0);
|
||||
REQUIRE((*q_sub.read_pointers[0] >> 32) == 0);
|
||||
|
||||
const size_t msg_size = 120;
|
||||
msgq_msg_t msg1;
|
||||
msgq_msg_init_size(&msg1, msg_size);
|
||||
|
||||
|
||||
SECTION("Check cycle counter after reset") {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
msgq_msg_send(&msg1, &q_pub);
|
||||
}
|
||||
|
||||
msgq_msg_t msg2;
|
||||
msgq_msg_recv(&msg2, &q_sub);
|
||||
REQUIRE(msg2.size == 0); // Reader had to reset
|
||||
msgq_msg_close(&msg2);
|
||||
|
||||
}
|
||||
SECTION("Check cycle counter while keeping up with writer") {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
msgq_msg_send(&msg1, &q_pub);
|
||||
|
||||
msgq_msg_t msg2;
|
||||
msgq_msg_recv(&msg2, &q_sub);
|
||||
REQUIRE(msg2.size > 0);
|
||||
msgq_msg_close(&msg2);
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE((*q_sub.read_pointers[0] >> 32) == 1);
|
||||
msgq_msg_close(&msg1);
|
||||
}
|
||||
|
||||
TEST_CASE("msgq_msg_send test invalidation"){
|
||||
remove("/dev/shm/test_queue");
|
||||
msgq_queue_t q_pub, q_sub;
|
||||
msgq_new_queue(&q_pub, "test_queue", 1024);
|
||||
msgq_new_queue(&q_sub, "test_queue", 1024);
|
||||
|
||||
msgq_init_publisher(&q_pub);
|
||||
msgq_init_subscriber(&q_sub);
|
||||
*q_sub.write_pointer = (uint64_t)1 << 32;
|
||||
|
||||
REQUIRE(*q_sub.read_valids[0] == true);
|
||||
|
||||
SECTION("read pointer in tag"){
|
||||
*q_sub.read_pointers[0] = 0;
|
||||
}
|
||||
SECTION("read pointer in data section"){
|
||||
*q_sub.read_pointers[0] = 64;
|
||||
}
|
||||
SECTION("read pointer in wraparound section"){
|
||||
*q_pub.write_pointer = ((uint64_t)1 << 32) | 1000; // Writer is one cycle ahead
|
||||
*q_sub.read_pointers[0] = 1020;
|
||||
}
|
||||
|
||||
msgq_msg_t msg;
|
||||
msgq_msg_init_size(&msg, 128);
|
||||
msgq_msg_send(&msg, &q_pub);
|
||||
|
||||
REQUIRE(*q_sub.read_valids[0] == false);
|
||||
|
||||
msgq_msg_close(&msg);
|
||||
}
|
||||
|
||||
TEST_CASE("msgq_init_subscriber init 2 subscribers"){
|
||||
remove("/dev/shm/test_queue");
|
||||
msgq_queue_t q1, q2;
|
||||
msgq_new_queue(&q1, "test_queue", 1024);
|
||||
msgq_new_queue(&q2, "test_queue", 1024);
|
||||
|
||||
*q1.num_readers = 0;
|
||||
|
||||
REQUIRE(*q1.num_readers == 0);
|
||||
REQUIRE(*q2.num_readers == 0);
|
||||
|
||||
msgq_init_subscriber(&q1);
|
||||
REQUIRE(*q1.num_readers == 1);
|
||||
REQUIRE(*q2.num_readers == 1);
|
||||
REQUIRE(q1.reader_id == 0);
|
||||
|
||||
msgq_init_subscriber(&q2);
|
||||
REQUIRE(*q1.num_readers == 2);
|
||||
REQUIRE(*q2.num_readers == 2);
|
||||
REQUIRE(q2.reader_id == 1);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Write 1 msg, read 1 msg", "[integration]"){
|
||||
remove("/dev/shm/test_queue");
|
||||
const size_t msg_size = 128;
|
||||
msgq_queue_t writer, reader;
|
||||
|
||||
msgq_new_queue(&writer, "test_queue", 1024);
|
||||
msgq_new_queue(&reader, "test_queue", 1024);
|
||||
|
||||
msgq_init_publisher(&writer);
|
||||
msgq_init_subscriber(&reader);
|
||||
|
||||
// Build 128 byte message
|
||||
msgq_msg_t outgoing_msg;
|
||||
msgq_msg_init_size(&outgoing_msg, msg_size);
|
||||
|
||||
for (size_t i = 0; i < msg_size; i++){
|
||||
outgoing_msg.data[i] = i;
|
||||
}
|
||||
|
||||
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
|
||||
|
||||
msgq_msg_t incoming_msg1;
|
||||
REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size);
|
||||
REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0);
|
||||
|
||||
// Verify that there are no more messages
|
||||
msgq_msg_t incoming_msg2;
|
||||
REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == 0);
|
||||
|
||||
msgq_msg_close(&outgoing_msg);
|
||||
msgq_msg_close(&incoming_msg1);
|
||||
msgq_msg_close(&incoming_msg2);
|
||||
}
|
||||
|
||||
TEST_CASE("Write 2 msg, read 2 msg - conflate = false", "[integration]"){
|
||||
remove("/dev/shm/test_queue");
|
||||
const size_t msg_size = 128;
|
||||
msgq_queue_t writer, reader;
|
||||
|
||||
msgq_new_queue(&writer, "test_queue", 1024);
|
||||
msgq_new_queue(&reader, "test_queue", 1024);
|
||||
|
||||
msgq_init_publisher(&writer);
|
||||
msgq_init_subscriber(&reader);
|
||||
|
||||
// Build 128 byte message
|
||||
msgq_msg_t outgoing_msg;
|
||||
msgq_msg_init_size(&outgoing_msg, msg_size);
|
||||
|
||||
for (size_t i = 0; i < msg_size; i++){
|
||||
outgoing_msg.data[i] = i;
|
||||
}
|
||||
|
||||
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
|
||||
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
|
||||
|
||||
msgq_msg_t incoming_msg1;
|
||||
REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size);
|
||||
REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0);
|
||||
|
||||
msgq_msg_t incoming_msg2;
|
||||
REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == msg_size);
|
||||
REQUIRE(memcmp(incoming_msg2.data, outgoing_msg.data, msg_size) == 0);
|
||||
|
||||
msgq_msg_close(&outgoing_msg);
|
||||
msgq_msg_close(&incoming_msg1);
|
||||
msgq_msg_close(&incoming_msg2);
|
||||
}
|
||||
|
||||
TEST_CASE("Write 2 msg, read 2 msg - conflate = true", "[integration]"){
|
||||
remove("/dev/shm/test_queue");
|
||||
const size_t msg_size = 128;
|
||||
msgq_queue_t writer, reader;
|
||||
|
||||
msgq_new_queue(&writer, "test_queue", 1024);
|
||||
msgq_new_queue(&reader, "test_queue", 1024);
|
||||
|
||||
msgq_init_publisher(&writer);
|
||||
msgq_init_subscriber(&reader);
|
||||
reader.read_conflate = true;
|
||||
|
||||
// Build 128 byte message
|
||||
msgq_msg_t outgoing_msg;
|
||||
msgq_msg_init_size(&outgoing_msg, msg_size);
|
||||
|
||||
for (size_t i = 0; i < msg_size; i++){
|
||||
outgoing_msg.data[i] = i;
|
||||
}
|
||||
|
||||
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
|
||||
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
|
||||
|
||||
msgq_msg_t incoming_msg1;
|
||||
REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size);
|
||||
REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0);
|
||||
|
||||
// Verify that there are no more messages
|
||||
msgq_msg_t incoming_msg2;
|
||||
REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == 0);
|
||||
|
||||
msgq_msg_close(&outgoing_msg);
|
||||
msgq_msg_close(&incoming_msg1);
|
||||
msgq_msg_close(&incoming_msg2);
|
||||
}
|
||||
|
||||
TEST_CASE("1 publisher, 1 slow subscriber", "[integration]"){
|
||||
remove("/dev/shm/test_queue");
|
||||
msgq_queue_t writer, reader;
|
||||
|
||||
msgq_new_queue(&writer, "test_queue", 1024);
|
||||
msgq_new_queue(&reader, "test_queue", 1024);
|
||||
|
||||
msgq_init_publisher(&writer);
|
||||
msgq_init_subscriber(&reader);
|
||||
|
||||
int n_received = 0;
|
||||
int n_skipped = 0;
|
||||
|
||||
for (uint64_t i = 0; i < 1e5; i++) {
|
||||
msgq_msg_t outgoing_msg;
|
||||
msgq_msg_init_data(&outgoing_msg, (char*)&i, sizeof(uint64_t));
|
||||
msgq_msg_send(&outgoing_msg, &writer);
|
||||
msgq_msg_close(&outgoing_msg);
|
||||
|
||||
if (i % 10 == 0){
|
||||
msgq_msg_t msg1;
|
||||
msgq_msg_recv(&msg1, &reader);
|
||||
|
||||
if (msg1.size == 0){
|
||||
n_skipped++;
|
||||
} else {
|
||||
n_received++;
|
||||
}
|
||||
msgq_msg_close(&msg1);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: verify these numbers by hand
|
||||
REQUIRE(n_received == 8572);
|
||||
REQUIRE(n_skipped == 1428);
|
||||
}
|
||||
|
||||
TEST_CASE("1 publisher, 2 subscribers", "[integration]"){
|
||||
remove("/dev/shm/test_queue");
|
||||
msgq_queue_t writer, reader1, reader2;
|
||||
|
||||
msgq_new_queue(&writer, "test_queue", 1024);
|
||||
msgq_new_queue(&reader1, "test_queue", 1024);
|
||||
msgq_new_queue(&reader2, "test_queue", 1024);
|
||||
|
||||
msgq_init_publisher(&writer);
|
||||
msgq_init_subscriber(&reader1);
|
||||
msgq_init_subscriber(&reader2);
|
||||
|
||||
for (uint64_t i = 0; i < 1024 * 3; i++) {
|
||||
msgq_msg_t outgoing_msg;
|
||||
msgq_msg_init_data(&outgoing_msg, (char*)&i, sizeof(uint64_t));
|
||||
msgq_msg_send(&outgoing_msg, &writer);
|
||||
|
||||
msgq_msg_t msg1, msg2;
|
||||
msgq_msg_recv(&msg1, &reader1);
|
||||
msgq_msg_recv(&msg2, &reader2);
|
||||
|
||||
REQUIRE(msg1.size == sizeof(uint64_t));
|
||||
REQUIRE(msg2.size == sizeof(uint64_t));
|
||||
REQUIRE(*(uint64_t*)msg1.data == i);
|
||||
REQUIRE(*(uint64_t*)msg2.data == i);
|
||||
|
||||
msgq_msg_close(&outgoing_msg);
|
||||
msgq_msg_close(&msg1);
|
||||
msgq_msg_close(&msg2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include "messaging.hpp"
|
||||
#include "services.h"
|
||||
#ifdef __APPLE__
|
||||
#define CLOCK_BOOTTIME CLOCK_MONOTONIC
|
||||
#endif
|
||||
static inline uint64_t nanos_since_boot() {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_BOOTTIME, &t);
|
||||
return t.tv_sec * 1000000000ULL + t.tv_nsec;
|
||||
}
|
||||
static const service *get_service(const char *name) {
|
||||
for (const auto &it : services) {
|
||||
if (strcmp(it.name, name) == 0) return ⁢
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
static inline bool inList(const std::initializer_list<const char *> &list, const char *value) {
|
||||
for (auto &v : list) {
|
||||
if (strcmp(value, v) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class MessageContext {
|
||||
public:
|
||||
MessageContext() { ctx_ = Context::create(); }
|
||||
~MessageContext() { delete ctx_; }
|
||||
Context *ctx_;
|
||||
};
|
||||
MessageContext ctx;
|
||||
|
||||
struct SubMaster::SubMessage {
|
||||
std::string name;
|
||||
SubSocket *socket = nullptr;
|
||||
int freq = 0;
|
||||
bool updated = false, alive = false, valid = false, ignore_alive;
|
||||
uint64_t rcv_time = 0, rcv_frame = 0;
|
||||
void *allocated_msg_reader = nullptr;
|
||||
capnp::FlatArrayMessageReader *msg_reader = nullptr;
|
||||
kj::Array<capnp::word> buf;
|
||||
cereal::Event::Reader event;
|
||||
};
|
||||
|
||||
SubMaster::SubMaster(const std::initializer_list<const char *> &service_list, const char *address,
|
||||
const std::initializer_list<const char *> &ignore_alive) {
|
||||
poller_ = Poller::create();
|
||||
for (auto name : service_list) {
|
||||
const service *serv = get_service(name);
|
||||
assert(serv != nullptr);
|
||||
SubSocket *socket = SubSocket::create(ctx.ctx_, name, address ? address : "127.0.0.1", true);
|
||||
assert(socket != 0);
|
||||
poller_->registerSocket(socket);
|
||||
SubMessage *m = new SubMessage{
|
||||
.socket = socket,
|
||||
.freq = serv->frequency,
|
||||
.ignore_alive = inList(ignore_alive, name),
|
||||
.allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)),
|
||||
.buf = kj::heapArray<capnp::word>(1024)};
|
||||
messages_[socket] = m;
|
||||
services_[name] = m;
|
||||
}
|
||||
}
|
||||
|
||||
int SubMaster::update(int timeout) {
|
||||
if (++frame_ == UINT64_MAX) frame_ = 1;
|
||||
for (auto &kv : messages_) kv.second->updated = false;
|
||||
|
||||
int updated = 0;
|
||||
auto sockets = poller_->poll(timeout);
|
||||
uint64_t current_time = nanos_since_boot();
|
||||
for (auto s : sockets) {
|
||||
Message *msg = s->receive(true);
|
||||
if (msg == nullptr) continue;
|
||||
|
||||
SubMessage *m = messages_.at(s);
|
||||
const size_t size = (msg->getSize() / sizeof(capnp::word)) + 1;
|
||||
if (m->buf.size() < size) {
|
||||
m->buf = kj::heapArray<capnp::word>(size);
|
||||
}
|
||||
memcpy(m->buf.begin(), msg->getData(), msg->getSize());
|
||||
delete msg;
|
||||
|
||||
if (m->msg_reader) {
|
||||
m->msg_reader->~FlatArrayMessageReader();
|
||||
}
|
||||
m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader(kj::ArrayPtr<capnp::word>(m->buf.begin(), size));
|
||||
m->event = m->msg_reader->getRoot<cereal::Event>();
|
||||
m->updated = true;
|
||||
m->rcv_time = current_time;
|
||||
m->rcv_frame = frame_;
|
||||
m->valid = m->event.getValid();
|
||||
|
||||
++updated;
|
||||
}
|
||||
|
||||
for (auto &kv : messages_) {
|
||||
SubMessage *m = kv.second;
|
||||
m->alive = (m->freq <= (1e-5) || ((current_time - m->rcv_time) * (1e-9)) < (10.0 / m->freq));
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
bool SubMaster::all_(const std::initializer_list<const char *> &service_list, bool valid, bool alive) {
|
||||
int found = 0;
|
||||
for (auto &kv : messages_) {
|
||||
SubMessage *m = kv.second;
|
||||
if (service_list.size() == 0 || inList(service_list, m->name.c_str())) {
|
||||
found += (!valid || m->valid) && (!alive || (m->alive && !m->ignore_alive));
|
||||
}
|
||||
}
|
||||
return service_list.size() == 0 ? found == messages_.size() : found == service_list.size();
|
||||
}
|
||||
|
||||
void SubMaster::drain() {
|
||||
while (true) {
|
||||
auto polls = poller_->poll(0);
|
||||
if (polls.size() == 0)
|
||||
break;
|
||||
|
||||
for (auto sock : polls) {
|
||||
Message *msg = sock->receive(true);
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SubMaster::updated(const char *name) const { return services_.at(name)->updated; }
|
||||
cereal::Event::Reader &SubMaster::operator[](const char *name) { return services_.at(name)->event; };
|
||||
|
||||
SubMaster::~SubMaster() {
|
||||
delete poller_;
|
||||
for (auto &kv : messages_) {
|
||||
SubMessage *m = kv.second;
|
||||
if (m->msg_reader) {
|
||||
m->msg_reader->~FlatArrayMessageReader();
|
||||
}
|
||||
free(m->allocated_msg_reader);
|
||||
delete m->socket;
|
||||
delete m;
|
||||
}
|
||||
}
|
||||
|
||||
PubMaster::PubMaster(const std::initializer_list<const char *> &service_list) {
|
||||
for (auto name : service_list) {
|
||||
assert(get_service(name) != nullptr);
|
||||
PubSocket *socket = PubSocket::create(ctx.ctx_, name);
|
||||
assert(socket);
|
||||
sockets_[name] = socket;
|
||||
}
|
||||
}
|
||||
|
||||
int PubMaster::send(const char *name, capnp::MessageBuilder &msg) {
|
||||
auto words = capnp::messageToFlatArray(msg);
|
||||
auto bytes = words.asBytes();
|
||||
return send(name, bytes.begin(), bytes.size());
|
||||
}
|
||||
|
||||
PubMaster::~PubMaster() {
|
||||
for (auto s : sockets_) delete s.second;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
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())
|
||||
@@ -1,2 +0,0 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch2/catch.hpp"
|
||||
@@ -1,142 +0,0 @@
|
||||
import unittest
|
||||
import time
|
||||
import cereal.messaging as messaging
|
||||
|
||||
import concurrent.futures
|
||||
|
||||
|
||||
def poller():
|
||||
context = messaging.Context()
|
||||
|
||||
p = messaging.Poller()
|
||||
|
||||
sub = messaging.SubSocket()
|
||||
sub.connect(context, 'controlsState')
|
||||
p.registerSocket(sub)
|
||||
|
||||
socks = p.poll(10000)
|
||||
r = [s.receive(non_blocking=True) for s in socks]
|
||||
|
||||
return r
|
||||
|
||||
|
||||
class TestPoller(unittest.TestCase):
|
||||
def test_poll_once(self):
|
||||
context = messaging.Context()
|
||||
|
||||
pub = messaging.PubSocket()
|
||||
pub.connect(context, 'controlsState')
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor() as e:
|
||||
poll = e.submit(poller)
|
||||
|
||||
time.sleep(0.1) # Slow joiner syndrome
|
||||
|
||||
# Send message
|
||||
pub.send("a")
|
||||
|
||||
# Wait for poll result
|
||||
result = poll.result()
|
||||
|
||||
del pub
|
||||
context.term()
|
||||
|
||||
self.assertEqual(result, [b"a"])
|
||||
|
||||
def test_poll_and_create_many_subscribers(self):
|
||||
context = messaging.Context()
|
||||
|
||||
pub = messaging.PubSocket()
|
||||
pub.connect(context, 'controlsState')
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor() as e:
|
||||
poll = e.submit(poller)
|
||||
|
||||
time.sleep(0.1) # Slow joiner syndrome
|
||||
c = messaging.Context()
|
||||
for _ in range(10):
|
||||
messaging.SubSocket().connect(c, 'controlsState')
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
# Send message
|
||||
pub.send("a")
|
||||
|
||||
# Wait for poll result
|
||||
result = poll.result()
|
||||
|
||||
del pub
|
||||
context.term()
|
||||
|
||||
self.assertEqual(result, [b"a"])
|
||||
|
||||
def test_multiple_publishers_exception(self):
|
||||
context = messaging.Context()
|
||||
|
||||
with self.assertRaises(messaging.MultiplePublishersError):
|
||||
pub1 = messaging.PubSocket()
|
||||
pub1.connect(context, 'controlsState')
|
||||
|
||||
pub2 = messaging.PubSocket()
|
||||
pub2.connect(context, 'controlsState')
|
||||
|
||||
pub1.send("a")
|
||||
|
||||
del pub1
|
||||
del pub2
|
||||
context.term()
|
||||
|
||||
def test_multiple_messages(self):
|
||||
context = messaging.Context()
|
||||
|
||||
pub = messaging.PubSocket()
|
||||
pub.connect(context, 'controlsState')
|
||||
|
||||
sub = messaging.SubSocket()
|
||||
sub.connect(context, 'controlsState')
|
||||
|
||||
time.sleep(0.1) # Slow joiner
|
||||
|
||||
for i in range(100):
|
||||
pub.send(str(i))
|
||||
|
||||
msg_seen = False
|
||||
i = 0
|
||||
while True:
|
||||
r = sub.receive(non_blocking=True)
|
||||
|
||||
if r is not None:
|
||||
self.assertEqual(str(i), r.decode('utf8'))
|
||||
|
||||
msg_seen = True
|
||||
i += 1
|
||||
|
||||
if r is None and msg_seen: # ZMQ sometimes receives nothing on the first receive
|
||||
break
|
||||
|
||||
del pub
|
||||
del sub
|
||||
context.term()
|
||||
|
||||
def test_conflate(self):
|
||||
context = messaging.Context()
|
||||
|
||||
pub = messaging.PubSocket()
|
||||
pub.connect(context, 'controlsState')
|
||||
|
||||
sub = messaging.SubSocket()
|
||||
sub.connect(context, 'controlsState', conflate=True)
|
||||
|
||||
time.sleep(0.1) # Slow joiner
|
||||
pub.send('a')
|
||||
pub.send('b')
|
||||
|
||||
self.assertEqual(b'b', sub.receive())
|
||||
|
||||
del pub
|
||||
del sub
|
||||
context.term()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -30,7 +30,7 @@ androidLog: [8020, true, 0.]
|
||||
carState: [8021, true, 100., 10]
|
||||
# 8022 is reserved for sshd
|
||||
carControl: [8023, true, 100., 10]
|
||||
plan: [8024, true, 20.]
|
||||
plan: [8024, true, 20., 2]
|
||||
liveLocation: [8025, true, 0., 1]
|
||||
gpsLocation: [8026, true, 1., 1]
|
||||
ethernetData: [8027, true, 0.]
|
||||
@@ -57,7 +57,7 @@ orbslamCorrection: [8050, true, 0.]
|
||||
liveLocationCorrected: [8051, true, 0.]
|
||||
orbObservation: [8052, true, 0.]
|
||||
applanixLocation: [8053, true, 0.]
|
||||
liveLocationKalman: [8054, true, 0., 1]
|
||||
liveLocationKalman: [8054, true, 20., 2]
|
||||
uiNavigationEvent: [8055, true, 0.]
|
||||
orbOdometry: [8057, true, 0.]
|
||||
orbFeatures: [8058, false, 0.]
|
||||
@@ -66,10 +66,10 @@ uiLayoutState: [8060, true, 0.]
|
||||
frontEncodeIdx: [8061, true, 5.]
|
||||
orbFeaturesSummary: [8062, true, 0.]
|
||||
driverState: [8063, true, 5., 1]
|
||||
liveParameters: [8064, true, 10.]
|
||||
liveParameters: [8064, true, 20., 2]
|
||||
liveMapData: [8065, true, 0.]
|
||||
cameraOdometry: [8066, true, 20., 5]
|
||||
pathPlan: [8067, true, 20.]
|
||||
pathPlan: [8067, true, 20., 2]
|
||||
kalmanOdometry: [8068, true, 0.]
|
||||
thumbnail: [8069, true, 0.2, 1]
|
||||
carEvents: [8070, true, 1., 1]
|
||||
@@ -113,7 +113,7 @@ testJoystick: [8056, false, 0.]
|
||||
|
||||
# **** stateful data transformers ****
|
||||
|
||||
# modeld -- runs & publishes the model
|
||||
# modeld -- runs & publishes the model
|
||||
# publishes: model, cameraOdometry
|
||||
# subscribes: liveCalibration, pathPlan
|
||||
|
||||
|
||||
+3
-2
@@ -2,6 +2,7 @@
|
||||
import os
|
||||
import yaml
|
||||
|
||||
|
||||
class Service():
|
||||
def __init__(self, port, should_log, frequency, decimation=None):
|
||||
self.port = port
|
||||
@@ -9,6 +10,7 @@ class Service():
|
||||
self.frequency = frequency
|
||||
self.decimation = decimation
|
||||
|
||||
|
||||
service_list_path = os.path.join(os.path.dirname(__file__), "service_list.yaml")
|
||||
|
||||
service_list = {}
|
||||
@@ -24,10 +26,9 @@ if __name__ == "__main__":
|
||||
print("/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT service_list.yaml */")
|
||||
print("#ifndef __SERVICES_H")
|
||||
print("#define __SERVICES_H")
|
||||
print("struct service { int port; bool should_log; int frequency; int decimation; char name[0x100]; };")
|
||||
print("struct service { char name[0x100]; int port; bool should_log; int frequency; int decimation; };")
|
||||
print("static struct service services[] = {")
|
||||
for k, v in service_list.items():
|
||||
print(' { .name = "%s", .port = %d, .should_log = %s, .frequency = %d, .decimation = %d },' % (k, v.port, "true" if v.should_log else "false", v.frequency, -1 if v.decimation is None else v.decimation))
|
||||
print("};")
|
||||
print("#endif")
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
informational: true
|
||||
patch: off
|
||||
|
||||
+11
-6
@@ -12,6 +12,10 @@ NetworkStrength = log.ThermalData.NetworkStrength
|
||||
|
||||
ANDROID = os.path.isfile('/EON')
|
||||
|
||||
def get_sound_card_online():
|
||||
return (os.path.isfile('/proc/asound/card0/state') and
|
||||
open('/proc/asound/card0/state').read().strip() == 'ONLINE')
|
||||
|
||||
def getprop(key):
|
||||
if not ANDROID:
|
||||
return ""
|
||||
@@ -22,10 +26,10 @@ def get_imei(slot):
|
||||
if slot not in ("0", "1"):
|
||||
raise ValueError("SIM slot must be 0 or 1")
|
||||
|
||||
ret = parse_service_call_string(service_call(["iphonesubinfo", "3" ,"i32", str(slot)]))
|
||||
ret = parse_service_call_string(service_call(["iphonesubinfo", "3" , "i32", str(slot)]))
|
||||
if not ret:
|
||||
# allow non android to be identified differently
|
||||
ret = "%015d" % random.randint(0, 1<<32)
|
||||
ret = "%015d" % random.randint(0, 1 << 32)
|
||||
return ret
|
||||
|
||||
def get_serial():
|
||||
@@ -47,10 +51,10 @@ def reboot(reason=None):
|
||||
reason_args = ["s16", reason]
|
||||
|
||||
subprocess.check_output([
|
||||
"service", "call", "power", "16", # IPowerManager.reboot
|
||||
"i32", "0", # no confirmation,
|
||||
"service", "call", "power", "16", # IPowerManager.reboot
|
||||
"i32", "0", # no confirmation,
|
||||
*reason_args,
|
||||
"i32", "1" # wait
|
||||
"i32", "1" # wait
|
||||
])
|
||||
|
||||
def service_call(call):
|
||||
@@ -71,7 +75,7 @@ def parse_service_call_unpack(r, fmt):
|
||||
|
||||
def parse_service_call_string(r):
|
||||
try:
|
||||
r = r[8:] # Cut off length field
|
||||
r = r[8:] # Cut off length field
|
||||
r = r.decode('utf_16_be')
|
||||
|
||||
# All pairs of two characters seem to be swapped. Not sure why
|
||||
@@ -132,6 +136,7 @@ def get_network_type():
|
||||
|
||||
def get_network_strength(network_type):
|
||||
network_strength = NetworkStrength.unknown
|
||||
|
||||
# from SignalStrength.java
|
||||
def get_lte_level(rsrp, rssnr):
|
||||
INT_MAX = 2147483647
|
||||
|
||||
@@ -38,5 +38,4 @@ def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
|
||||
|
||||
headers['User-Agent'] = "openpilot-" + version
|
||||
|
||||
return requests.request(method, backend+endpoint, timeout=timeout, headers = headers, params=params)
|
||||
|
||||
return requests.request(method, backend+endpoint, timeout=timeout, headers=headers, params=params)
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ def get_installed_apks():
|
||||
ret = {}
|
||||
for x in dat:
|
||||
if x.startswith("package:"):
|
||||
v,k = x.split("package:")[1].split("=")
|
||||
v, k = x.split("package:")[1].split("=")
|
||||
ret[k] = v
|
||||
return ret
|
||||
|
||||
|
||||
@@ -8,4 +8,3 @@ if ANDROID:
|
||||
else:
|
||||
PERSIST = os.path.join(BASEDIR, "persist")
|
||||
PARAMS = os.path.join(BASEDIR, "persist", "params")
|
||||
|
||||
|
||||
+18
-5
@@ -3,13 +3,17 @@ import shutil
|
||||
import tempfile
|
||||
from atomicwrites import AtomicWriter
|
||||
|
||||
|
||||
def mkdirs_exists_ok(path):
|
||||
if path.startswith('http://') or path.startswith('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)
|
||||
@@ -17,12 +21,14 @@ def rm_not_exists_ok(path):
|
||||
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("/")
|
||||
@@ -32,6 +38,7 @@ def get_tmpdir_on_same_filesystem(path):
|
||||
return "/{}/runner/tmp".format(parts[1])
|
||||
return "/tmp"
|
||||
|
||||
|
||||
class AutoMoveTempdir():
|
||||
def __init__(self, target_path, temp_dir=None):
|
||||
self._target_path = target_path
|
||||
@@ -44,14 +51,16 @@ class AutoMoveTempdir():
|
||||
def close(self):
|
||||
os.rename(self._path, self._target_path)
|
||||
|
||||
def __enter__(self): return self
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
if type is None:
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if exc_type is None:
|
||||
self.close()
|
||||
else:
|
||||
shutil.rmtree(self._path)
|
||||
|
||||
|
||||
class NamedTemporaryDir():
|
||||
def __init__(self, temp_dir=None):
|
||||
self._path = tempfile.mkdtemp(dir=temp_dir)
|
||||
@@ -63,11 +72,13 @@ class NamedTemporaryDir():
|
||||
def close(self):
|
||||
shutil.rmtree(self._path)
|
||||
|
||||
def __enter__(self): return self
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
|
||||
def _get_fileobject_func(writer, temp_dir):
|
||||
def _get_fileobject():
|
||||
file_obj = writer.get_fileobject(dir=temp_dir)
|
||||
@@ -75,6 +86,7 @@ def _get_fileobject_func(writer, temp_dir):
|
||||
return file_obj
|
||||
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.
|
||||
@@ -92,6 +104,7 @@ def atomic_write_in_dir(path, **kwargs):
|
||||
writer = AtomicWriter(path, **kwargs)
|
||||
return writer._open(_get_fileobject_func(writer, os.path.dirname(path)))
|
||||
|
||||
|
||||
def atomic_write_in_dir_neos(path, contents, mode=None):
|
||||
"""
|
||||
Atomically writes contents to path using a temporary file in the same directory
|
||||
|
||||
@@ -50,7 +50,6 @@ class TestSimpleKalman(unittest.TestCase):
|
||||
self.assertAlmostEqual(x_old[0], x[0])
|
||||
self.assertAlmostEqual(x_old[1], x[1])
|
||||
|
||||
|
||||
def test_new_is_faster(self):
|
||||
setup = """
|
||||
import numpy as np
|
||||
|
||||
@@ -68,8 +68,11 @@ class SwagErrorFilter(logging.Filter):
|
||||
def filter(self, record):
|
||||
return record.levelno < logging.ERROR
|
||||
|
||||
_tmpfunc = lambda: 0
|
||||
_srcfile = os.path.normcase(_tmpfunc.__code__.co_filename)
|
||||
def _tmpfunc():
|
||||
return 0
|
||||
|
||||
def _srcfile():
|
||||
return os.path.normcase(_tmpfunc.__code__.co_filename)
|
||||
|
||||
class SwagLogger(logging.Logger):
|
||||
def __init__(self):
|
||||
@@ -112,9 +115,6 @@ class SwagLogger(logging.Logger):
|
||||
if args:
|
||||
evt['args'] = args
|
||||
evt.update(kwargs)
|
||||
ctx = self.get_ctx()
|
||||
if ctx:
|
||||
evt['ctx'] = self.get_ctx()
|
||||
if 'error' in kwargs:
|
||||
self.error(evt)
|
||||
else:
|
||||
@@ -140,7 +140,9 @@ class SwagLogger(logging.Logger):
|
||||
while hasattr(f, "f_code"):
|
||||
co = f.f_code
|
||||
filename = os.path.normcase(co.co_filename)
|
||||
if filename == _srcfile:
|
||||
|
||||
# TODO: is this pylint exception correct?
|
||||
if filename == _srcfile: # pylint: disable=comparison-with-callable
|
||||
f = f.f_back
|
||||
continue
|
||||
sinfo = None
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
def cputime_total(ct):
|
||||
return ct.cpuUser + ct.cpuSystem + ct.cpuChildrenUser + ct.cpuChildrenSystem
|
||||
|
||||
|
||||
def print_cpu_usage(first_proc, last_proc):
|
||||
r = 0
|
||||
procs = [
|
||||
("selfdrive.controls.controlsd", 59.46),
|
||||
("./_modeld", 48.94),
|
||||
("./loggerd", 28.49),
|
||||
("selfdrive.controls.plannerd", 19.77),
|
||||
("selfdrive.controls.radard", 9.54),
|
||||
("./_ui", 9.54),
|
||||
("./camerad", 7.07),
|
||||
("selfdrive.locationd.locationd", 7.13),
|
||||
("./_sensord", 6.17),
|
||||
("selfdrive.controls.dmonitoringd", 5.48),
|
||||
("./boardd", 3.63),
|
||||
("./_dmonitoringmodeld", 2.67),
|
||||
("selfdrive.logmessaged", 2.71),
|
||||
("selfdrive.thermald", 2.41),
|
||||
("./paramsd", 2.18),
|
||||
("selfdrive.locationd.calibrationd", 1.76),
|
||||
("./proclogd", 1.54),
|
||||
("./_gpsd", 0.09),
|
||||
("./clocksd", 0.02),
|
||||
("./ubloxd", 0.02),
|
||||
("selfdrive.tombstoned", 0),
|
||||
("./logcatd", 0),
|
||||
("selfdrive.updated", 0),
|
||||
]
|
||||
|
||||
dt = (last_proc.logMonoTime - first_proc.logMonoTime) / 1e9
|
||||
print("------------------------------------------------")
|
||||
for proc_name, normal_cpu_usage in procs:
|
||||
try:
|
||||
first = [p for p in first_proc.procLog.procs if proc_name in p.cmdline][0]
|
||||
last = [p for p in last_proc.procLog.procs if proc_name in p.cmdline][0]
|
||||
cpu_time = cputime_total(last) - cputime_total(first)
|
||||
cpu_usage = cpu_time / dt * 100.
|
||||
if cpu_usage > max(normal_cpu_usage * 1.1, normal_cpu_usage + 5.0):
|
||||
print(f"Warning {proc_name} using more CPU than normal")
|
||||
r = 1
|
||||
|
||||
print(f"{proc_name.ljust(35)} {cpu_usage:.2f}%")
|
||||
except IndexError:
|
||||
print(f"{proc_name.ljust(35)} NO METRICS FOUND")
|
||||
print("------------------------------------------------")
|
||||
|
||||
return r
|
||||
@@ -6,6 +6,7 @@ def clip(x, lo, hi):
|
||||
|
||||
def interp(x, xp, fp):
|
||||
N = len(xp)
|
||||
|
||||
def get_interp(xv):
|
||||
hi = 0
|
||||
while hi < N and xv > xp[hi]:
|
||||
@@ -14,8 +15,8 @@ def interp(x, xp, fp):
|
||||
return fp[-1] if hi == N and xv > xp[low] else (
|
||||
fp[0] if hi == 0 else
|
||||
(xv - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]) + fp[low])
|
||||
return [get_interp(v) for v in x] if hasattr(
|
||||
x, '__iter__') else get_interp(x)
|
||||
|
||||
return [get_interp(v) for v in x] if hasattr(x, '__iter__') else get_interp(x)
|
||||
|
||||
def mean(x):
|
||||
return sum(x) / len(x)
|
||||
|
||||
+15
-27
@@ -22,10 +22,7 @@ file in place without messing with <params_dir>/d.
|
||||
"""
|
||||
import time
|
||||
import os
|
||||
import string
|
||||
import binascii
|
||||
import errno
|
||||
import sys
|
||||
import shutil
|
||||
import fcntl
|
||||
import tempfile
|
||||
@@ -33,6 +30,7 @@ import threading
|
||||
from enum import Enum
|
||||
from common.basedir import PARAMS
|
||||
|
||||
|
||||
def mkdirs_exists_ok(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
@@ -62,6 +60,7 @@ keys = {
|
||||
"CompletedTrainingVersion": [TxType.PERSISTENT],
|
||||
"ControlsParams": [TxType.PERSISTENT],
|
||||
"DisablePowerDown": [TxType.PERSISTENT],
|
||||
"DisableUpdates": [TxType.PERSISTENT],
|
||||
"DoUninstall": [TxType.CLEAR_ON_MANAGER_START],
|
||||
"DongleId": [TxType.PERSISTENT],
|
||||
"GitBranch": [TxType.PERSISTENT],
|
||||
@@ -108,6 +107,7 @@ keys = {
|
||||
"Offroad_PandaFirmwareMismatch": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
|
||||
"Offroad_InvalidTime": [TxType.CLEAR_ON_MANAGER_START],
|
||||
"Offroad_IsTakingSnapshot": [TxType.CLEAR_ON_MANAGER_START],
|
||||
"Offroad_NeosUpdate": [TxType.CLEAR_ON_MANAGER_START],
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,10 @@ class DBAccessor():
|
||||
|
||||
def get(self, key):
|
||||
self._check_entered()
|
||||
|
||||
if self._vals is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
return self._vals[key]
|
||||
except KeyError:
|
||||
@@ -198,7 +202,8 @@ class DBReader(DBAccessor):
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
def __exit__(self, type, value, traceback): pass
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
|
||||
class DBWriter(DBAccessor):
|
||||
@@ -223,14 +228,14 @@ class DBWriter(DBAccessor):
|
||||
os.chmod(self._path, 0o777)
|
||||
self._lock = self._get_lock(True)
|
||||
self._vals = self._read_values_locked()
|
||||
except:
|
||||
except Exception:
|
||||
os.umask(self._prev_umask)
|
||||
self._prev_umask = None
|
||||
raise
|
||||
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self._check_entered()
|
||||
|
||||
try:
|
||||
@@ -304,12 +309,13 @@ def read_db(params_path, key):
|
||||
except IOError:
|
||||
return None
|
||||
|
||||
|
||||
def write_db(params_path, key, value):
|
||||
if isinstance(value, str):
|
||||
value = value.encode('utf8')
|
||||
|
||||
prev_umask = os.umask(0)
|
||||
lock = FileLock(params_path+"/.lock", True)
|
||||
lock = FileLock(params_path + "/.lock", True)
|
||||
lock.acquire()
|
||||
|
||||
try:
|
||||
@@ -326,12 +332,13 @@ def write_db(params_path, key, value):
|
||||
os.umask(prev_umask)
|
||||
lock.release()
|
||||
|
||||
|
||||
class Params():
|
||||
def __init__(self, db=PARAMS):
|
||||
self.db = db
|
||||
|
||||
# create the database if it doesn't exist...
|
||||
if not os.path.exists(self.db+"/d"):
|
||||
if not os.path.exists(self.db + "/d"):
|
||||
with self.transaction(write=True):
|
||||
pass
|
||||
|
||||
@@ -401,22 +408,3 @@ def put_nonblocking(key, val):
|
||||
t = threading.Thread(target=f, args=(key, val))
|
||||
t.start()
|
||||
return t
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
params = Params()
|
||||
if len(sys.argv) > 2:
|
||||
params.put(sys.argv[1], sys.argv[2])
|
||||
else:
|
||||
for k in keys:
|
||||
pp = params.get(k)
|
||||
if pp is None:
|
||||
print("%s is None" % k)
|
||||
elif all(chr(c) in string.printable for c in pp):
|
||||
print("%s = %s" % (k, pp))
|
||||
else:
|
||||
print("%s = %s" % (k, binascii.hexlify(pp)))
|
||||
|
||||
# Test multiprocess:
|
||||
# seq 0 100000 | xargs -P20 -I{} python common/params.py DongleId {} && sleep 0.05
|
||||
# while python common/params.py DongleId; do sleep 0.05; done
|
||||
|
||||
@@ -43,4 +43,3 @@ class Profiler():
|
||||
else:
|
||||
print("%30s: %9.2f percent: %3.0f" % (n, ms*1000.0, ms/self.tot*100))
|
||||
print("Iter clock: %2.6f TOTAL: %2.2f" % (self.tot/self.iter, self.tot))
|
||||
|
||||
|
||||
+21
-7
@@ -6,6 +6,7 @@ import subprocess
|
||||
import multiprocessing
|
||||
from cffi import FFI
|
||||
|
||||
from common.android import ANDROID
|
||||
from common.common_pyx import sec_since_boot # pylint: disable=no-name-in-module, import-error
|
||||
|
||||
|
||||
@@ -20,11 +21,7 @@ ffi = FFI()
|
||||
ffi.cdef("long syscall(long number, ...);")
|
||||
libc = ffi.dlopen(None)
|
||||
|
||||
|
||||
def set_realtime_priority(level):
|
||||
if os.getuid() != 0:
|
||||
print("not setting priority, not root")
|
||||
return
|
||||
def _get_tid():
|
||||
if platform.machine() == "x86_64":
|
||||
NR_gettid = 186
|
||||
elif platform.machine() == "aarch64":
|
||||
@@ -32,8 +29,25 @@ def set_realtime_priority(level):
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
tid = libc.syscall(NR_gettid)
|
||||
return subprocess.call(['chrt', '-f', '-p', str(level), str(tid)])
|
||||
return libc.syscall(NR_gettid)
|
||||
|
||||
|
||||
def set_realtime_priority(level):
|
||||
if os.getuid() != 0:
|
||||
print("not setting priority, not root")
|
||||
return
|
||||
|
||||
return subprocess.call(['chrt', '-f', '-p', str(level), str(_get_tid())])
|
||||
|
||||
def set_core_affinity(core):
|
||||
if os.getuid() != 0:
|
||||
print("not setting affinity, not root")
|
||||
return
|
||||
|
||||
if ANDROID:
|
||||
return subprocess.call(['taskset', '-p', str(core), str(_get_tid())])
|
||||
else:
|
||||
return -1
|
||||
|
||||
|
||||
class Ratekeeper():
|
||||
|
||||
+4
-4
@@ -36,12 +36,12 @@ class Spinner():
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
|
||||
class FakeSpinner():
|
||||
def __init__(self):
|
||||
class FakeSpinner(Spinner):
|
||||
def __init__(self): # pylint: disable=super-init-not-called
|
||||
pass
|
||||
|
||||
def __enter__(self):
|
||||
@@ -53,7 +53,7 @@ class FakeSpinner():
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ class RunningStat():
|
||||
self.S_last = 0.
|
||||
else:
|
||||
self.M = self.M_last + (new_data - self.M_last) / self.n
|
||||
self.S = self.S_last + (new_data - self.M_last) * (new_data - self.M);
|
||||
self.S = self.S_last + (new_data - self.M_last) * (new_data - self.M)
|
||||
self.M_last = self.M
|
||||
self.S_last = self.S
|
||||
|
||||
@@ -64,7 +64,7 @@ class RunningStatFilter():
|
||||
_std_last = self.raw_stat.std()
|
||||
self.raw_stat.push_data(new_data)
|
||||
_delta_std = self.raw_stat.std() - _std_last
|
||||
if _delta_std<=0:
|
||||
if _delta_std <= 0:
|
||||
self.filtered_stat.push_data(new_data)
|
||||
else:
|
||||
pass
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import os
|
||||
from nose.tools import nottest
|
||||
|
||||
def phone_only(x):
|
||||
if os.path.isfile("/init.qcom.rc"):
|
||||
return x
|
||||
else:
|
||||
return nottest(x)
|
||||
|
||||
@@ -39,12 +39,12 @@ class TextWindow():
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
|
||||
class FakeTextWindow():
|
||||
def __init__(self, s):
|
||||
class FakeTextWindow(TextWindow):
|
||||
def __init__(self, s): # pylint: disable=super-init-not-called
|
||||
pass
|
||||
|
||||
def get_status(self):
|
||||
@@ -59,7 +59,10 @@ class FakeTextWindow():
|
||||
def update(self, _):
|
||||
pass
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -25,4 +25,3 @@ class Timeout:
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
signal.alarm(0)
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Import('env')
|
||||
|
||||
d = Dir('.')
|
||||
|
||||
env.Command(
|
||||
['transformations.so'],
|
||||
['transformations.pxd', 'transformations.pyx',
|
||||
'coordinates.cc', 'orientation.cc', 'coordinates.hpp', 'orientation.hpp'],
|
||||
'cd ' + d.path + ' && python3 setup.py build_ext --inplace')
|
||||
@@ -59,7 +59,7 @@ def vp_from_ke(m):
|
||||
|
||||
The vanishing point is defined as lim x->infinity C (x, 0, 0, 1).T
|
||||
"""
|
||||
return (m[0, 0]/m[2,0], m[1,0]/m[2,0])
|
||||
return (m[0, 0]/m[2, 0], m[1, 0]/m[2, 0])
|
||||
|
||||
|
||||
def vp_from_rpy(rpy):
|
||||
@@ -81,10 +81,10 @@ def normalize(img_pts, intrinsics=eon_intrinsics):
|
||||
img_pts = np.array(img_pts)
|
||||
input_shape = img_pts.shape
|
||||
img_pts = np.atleast_2d(img_pts)
|
||||
img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0],1))))
|
||||
img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0], 1))))
|
||||
img_pts_normalized = img_pts.dot(intrinsics_inv.T)
|
||||
img_pts_normalized[(img_pts < 0).any(axis=1)] = np.nan
|
||||
return img_pts_normalized[:,:2].reshape(input_shape)
|
||||
return img_pts_normalized[:, :2].reshape(input_shape)
|
||||
|
||||
|
||||
def denormalize(img_pts, intrinsics=eon_intrinsics):
|
||||
@@ -93,13 +93,13 @@ def denormalize(img_pts, intrinsics=eon_intrinsics):
|
||||
img_pts = np.array(img_pts)
|
||||
input_shape = img_pts.shape
|
||||
img_pts = np.atleast_2d(img_pts)
|
||||
img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0],1))))
|
||||
img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0], 1))))
|
||||
img_pts_denormalized = img_pts.dot(intrinsics.T)
|
||||
img_pts_denormalized[img_pts_denormalized[:,0] > W] = np.nan
|
||||
img_pts_denormalized[img_pts_denormalized[:,0] < 0] = np.nan
|
||||
img_pts_denormalized[img_pts_denormalized[:,1] > H] = np.nan
|
||||
img_pts_denormalized[img_pts_denormalized[:,1] < 0] = np.nan
|
||||
return img_pts_denormalized[:,:2].reshape(input_shape)
|
||||
img_pts_denormalized[img_pts_denormalized[:, 0] > W] = np.nan
|
||||
img_pts_denormalized[img_pts_denormalized[:, 0] < 0] = np.nan
|
||||
img_pts_denormalized[img_pts_denormalized[:, 1] > H] = np.nan
|
||||
img_pts_denormalized[img_pts_denormalized[:, 1] < 0] = np.nan
|
||||
return img_pts_denormalized[:, :2].reshape(input_shape)
|
||||
|
||||
|
||||
def device_from_ecef(pos_ecef, orientation_ecef, pt_ecef):
|
||||
@@ -124,10 +124,10 @@ def img_from_device(pt_device):
|
||||
pt_view = np.einsum('jk,ik->ij', view_frame_from_device_frame, pt_device)
|
||||
|
||||
# This function should never return negative depths
|
||||
pt_view[pt_view[:,2] < 0] = np.nan
|
||||
pt_view[pt_view[:, 2] < 0] = np.nan
|
||||
|
||||
pt_img = pt_view/pt_view[:,2:3]
|
||||
return pt_img.reshape(input_shape)[:,:2]
|
||||
pt_img = pt_view/pt_view[:, 2:3]
|
||||
return pt_img.reshape(input_shape)[:, :2]
|
||||
|
||||
|
||||
def get_camera_frame_from_calib_frame(camera_frame_from_road_frame):
|
||||
@@ -145,4 +145,3 @@ def pretransform_from_calib(calib):
|
||||
camera_frame_from_road_frame = np.dot(eon_intrinsics, view_frame_from_road_frame)
|
||||
camera_frame_from_calib_frame = get_camera_frame_from_calib_frame(camera_frame_from_road_frame)
|
||||
return np.linalg.inv(camera_frame_from_calib_frame)
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <eigen3/Eigen/Dense>
|
||||
|
||||
#include "coordinates.hpp"
|
||||
|
||||
#define DEG2RAD(x) ((x) * M_PI / 180.0)
|
||||
#define RAD2DEG(x) ((x) * 180.0 / M_PI)
|
||||
|
||||
|
||||
double a = 6378137;
|
||||
double b = 6356752.3142;
|
||||
double esq = 6.69437999014 * 0.001;
|
||||
double e1sq = 6.73949674228 * 0.001;
|
||||
|
||||
|
||||
static Geodetic to_degrees(Geodetic geodetic){
|
||||
geodetic.lat = RAD2DEG(geodetic.lat);
|
||||
geodetic.lon = RAD2DEG(geodetic.lon);
|
||||
return geodetic;
|
||||
}
|
||||
|
||||
static Geodetic to_radians(Geodetic geodetic){
|
||||
geodetic.lat = DEG2RAD(geodetic.lat);
|
||||
geodetic.lon = DEG2RAD(geodetic.lon);
|
||||
return geodetic;
|
||||
}
|
||||
|
||||
|
||||
ECEF geodetic2ecef(Geodetic g){
|
||||
g = to_radians(g);
|
||||
double xi = sqrt(1.0 - esq * pow(sin(g.lat), 2));
|
||||
double x = (a / xi + g.alt) * cos(g.lat) * cos(g.lon);
|
||||
double y = (a / xi + g.alt) * cos(g.lat) * sin(g.lon);
|
||||
double z = (a / xi * (1.0 - esq) + g.alt) * sin(g.lat);
|
||||
return {x, y, z};
|
||||
}
|
||||
|
||||
Geodetic ecef2geodetic(ECEF e){
|
||||
// Convert from ECEF to geodetic using Ferrari's methods
|
||||
// https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution
|
||||
double x = e.x;
|
||||
double y = e.y;
|
||||
double z = e.z;
|
||||
|
||||
double r = sqrt(x * x + y * y);
|
||||
double Esq = a * a - b * b;
|
||||
double F = 54 * b * b * z * z;
|
||||
double G = r * r + (1 - esq) * z * z - esq * Esq;
|
||||
double C = (esq * esq * F * r * r) / (pow(G, 3));
|
||||
double S = cbrt(1 + C + sqrt(C * C + 2 * C));
|
||||
double P = F / (3 * pow((S + 1 / S + 1), 2) * G * G);
|
||||
double Q = sqrt(1 + 2 * esq * esq * P);
|
||||
double r_0 = -(P * esq * r) / (1 + Q) + sqrt(0.5 * a * a*(1 + 1.0 / Q) - P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r);
|
||||
double U = sqrt(pow((r - esq * r_0), 2) + z * z);
|
||||
double V = sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z);
|
||||
double Z_0 = b * b * z / (a * V);
|
||||
double h = U * (1 - b * b / (a * V));
|
||||
|
||||
double lat = atan((z + e1sq * Z_0) / r);
|
||||
double lon = atan2(y, x);
|
||||
|
||||
return to_degrees({lat, lon, h});
|
||||
}
|
||||
|
||||
LocalCoord::LocalCoord(Geodetic g, ECEF e){
|
||||
init_ecef << e.x, e.y, e.z;
|
||||
|
||||
g = to_radians(g);
|
||||
|
||||
ned2ecef_matrix <<
|
||||
-sin(g.lat)*cos(g.lon), -sin(g.lon), -cos(g.lat)*cos(g.lon),
|
||||
-sin(g.lat)*sin(g.lon), cos(g.lon), -cos(g.lat)*sin(g.lon),
|
||||
cos(g.lat), 0, -sin(g.lat);
|
||||
ecef2ned_matrix = ned2ecef_matrix.transpose();
|
||||
}
|
||||
|
||||
NED LocalCoord::ecef2ned(ECEF e) {
|
||||
Eigen::Vector3d ecef;
|
||||
ecef << e.x, e.y, e.z;
|
||||
|
||||
Eigen::Vector3d ned = (ecef2ned_matrix * (ecef - init_ecef));
|
||||
return {ned[0], ned[1], ned[2]};
|
||||
}
|
||||
|
||||
ECEF LocalCoord::ned2ecef(NED n) {
|
||||
Eigen::Vector3d ned;
|
||||
ned << n.n, n.e, n.d;
|
||||
|
||||
Eigen::Vector3d ecef = (ned2ecef_matrix * ned) + init_ecef;
|
||||
return {ecef[0], ecef[1], ecef[2]};
|
||||
}
|
||||
|
||||
NED LocalCoord::geodetic2ned(Geodetic g) {
|
||||
ECEF e = ::geodetic2ecef(g);
|
||||
return ecef2ned(e);
|
||||
}
|
||||
|
||||
Geodetic LocalCoord::ned2geodetic(NED n){
|
||||
ECEF e = ned2ecef(n);
|
||||
return ::ecef2geodetic(e);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
struct ECEF {
|
||||
double x, y, z;
|
||||
Eigen::Vector3d to_vector(){
|
||||
return Eigen::Vector3d(x, y, z);
|
||||
}
|
||||
};
|
||||
|
||||
struct NED {
|
||||
double n, e, d;
|
||||
};
|
||||
|
||||
struct Geodetic {
|
||||
double lat, lon, alt;
|
||||
bool radians=false;
|
||||
};
|
||||
|
||||
ECEF geodetic2ecef(Geodetic g);
|
||||
Geodetic ecef2geodetic(ECEF e);
|
||||
|
||||
class LocalCoord {
|
||||
public:
|
||||
Eigen::Matrix3d ned2ecef_matrix;
|
||||
Eigen::Matrix3d ecef2ned_matrix;
|
||||
Eigen::Vector3d init_ecef;
|
||||
LocalCoord(Geodetic g, ECEF e);
|
||||
LocalCoord(Geodetic g) : LocalCoord(g, ::geodetic2ecef(g)) {}
|
||||
LocalCoord(ECEF e) : LocalCoord(::ecef2geodetic(e), e) {}
|
||||
|
||||
NED ecef2ned(ECEF e);
|
||||
ECEF ned2ecef(NED n);
|
||||
NED geodetic2ned(Geodetic g);
|
||||
Geodetic ned2geodetic(NED n);
|
||||
};
|
||||
@@ -1,108 +1,19 @@
|
||||
import numpy as np
|
||||
"""
|
||||
Coordinate transformation module. All methods accept arrays as input
|
||||
with each row as a position.
|
||||
"""
|
||||
# pylint: skip-file
|
||||
from common.transformations.orientation import numpy_wrap
|
||||
from common.transformations.transformations import (ecef2geodetic_single,
|
||||
geodetic2ecef_single)
|
||||
from common.transformations.transformations import LocalCoord as LocalCoord_single
|
||||
|
||||
|
||||
|
||||
a = 6378137
|
||||
b = 6356752.3142
|
||||
esq = 6.69437999014 * 0.001
|
||||
e1sq = 6.73949674228 * 0.001
|
||||
class LocalCoord(LocalCoord_single):
|
||||
ecef2ned = numpy_wrap(LocalCoord_single.ecef2ned_single, (3,), (3,))
|
||||
ned2ecef = numpy_wrap(LocalCoord_single.ned2ecef_single, (3,), (3,))
|
||||
geodetic2ned = numpy_wrap(LocalCoord_single.geodetic2ned_single, (3,), (3,))
|
||||
ned2geodetic = numpy_wrap(LocalCoord_single.ned2geodetic_single, (3,), (3,))
|
||||
|
||||
|
||||
def geodetic2ecef(geodetic, radians=False):
|
||||
geodetic = np.array(geodetic)
|
||||
input_shape = geodetic.shape
|
||||
geodetic = np.atleast_2d(geodetic)
|
||||
geodetic2ecef = numpy_wrap(geodetic2ecef_single, (3,), (3,))
|
||||
ecef2geodetic = numpy_wrap(ecef2geodetic_single, (3,), (3,))
|
||||
|
||||
ratio = 1.0 if radians else (np.pi / 180.0)
|
||||
lat = ratio*geodetic[:,0]
|
||||
lon = ratio*geodetic[:,1]
|
||||
alt = geodetic[:,2]
|
||||
|
||||
xi = np.sqrt(1 - esq * np.sin(lat)**2)
|
||||
x = (a / xi + alt) * np.cos(lat) * np.cos(lon)
|
||||
y = (a / xi + alt) * np.cos(lat) * np.sin(lon)
|
||||
z = (a / xi * (1 - esq) + alt) * np.sin(lat)
|
||||
ecef = np.array([x, y, z]).T
|
||||
return ecef.reshape(input_shape)
|
||||
|
||||
|
||||
def ecef2geodetic(ecef, radians=False):
|
||||
"""
|
||||
Convert ECEF coordinates to geodetic using ferrari's method
|
||||
"""
|
||||
# Save shape and export column
|
||||
ecef = np.atleast_1d(ecef)
|
||||
input_shape = ecef.shape
|
||||
ecef = np.atleast_2d(ecef)
|
||||
x, y, z = ecef[:, 0], ecef[:, 1], ecef[:, 2]
|
||||
|
||||
ratio = 1.0 if radians else (180.0 / np.pi)
|
||||
|
||||
# Conver from ECEF to geodetic using Ferrari's methods
|
||||
# https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution
|
||||
r = np.sqrt(x * x + y * y)
|
||||
Esq = a * a - b * b
|
||||
F = 54 * b * b * z * z
|
||||
G = r * r + (1 - esq) * z * z - esq * Esq
|
||||
C = (esq * esq * F * r * r) / (pow(G, 3))
|
||||
S = np.cbrt(1 + C + np.sqrt(C * C + 2 * C))
|
||||
P = F / (3 * pow((S + 1 / S + 1), 2) * G * G)
|
||||
Q = np.sqrt(1 + 2 * esq * esq * P)
|
||||
r_0 = -(P * esq * r) / (1 + Q) + np.sqrt(0.5 * a * a*(1 + 1.0 / Q) - \
|
||||
P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r)
|
||||
U = np.sqrt(pow((r - esq * r_0), 2) + z * z)
|
||||
V = np.sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z)
|
||||
Z_0 = b * b * z / (a * V)
|
||||
h = U * (1 - b * b / (a * V))
|
||||
lat = ratio*np.arctan((z + e1sq * Z_0) / r)
|
||||
lon = ratio*np.arctan2(y, x)
|
||||
|
||||
# stack the new columns and return to the original shape
|
||||
geodetic = np.column_stack((lat, lon, h))
|
||||
return geodetic.reshape(input_shape)
|
||||
|
||||
class LocalCoord():
|
||||
"""
|
||||
Allows conversions to local frames. In this case NED.
|
||||
That is: North East Down from the start position in
|
||||
meters.
|
||||
"""
|
||||
def __init__(self, init_geodetic, init_ecef):
|
||||
self.init_ecef = init_ecef
|
||||
lat, lon, _ = (np.pi/180)*np.array(init_geodetic)
|
||||
self.ned2ecef_matrix = np.array([[-np.sin(lat)*np.cos(lon), -np.sin(lon), -np.cos(lat)*np.cos(lon)],
|
||||
[-np.sin(lat)*np.sin(lon), np.cos(lon), -np.cos(lat)*np.sin(lon)],
|
||||
[np.cos(lat), 0, -np.sin(lat)]])
|
||||
self.ecef2ned_matrix = self.ned2ecef_matrix.T
|
||||
|
||||
@classmethod
|
||||
def from_geodetic(cls, init_geodetic):
|
||||
init_ecef = geodetic2ecef(init_geodetic)
|
||||
return LocalCoord(init_geodetic, init_ecef)
|
||||
|
||||
@classmethod
|
||||
def from_ecef(cls, init_ecef):
|
||||
init_geodetic = ecef2geodetic(init_ecef)
|
||||
return LocalCoord(init_geodetic, init_ecef)
|
||||
|
||||
|
||||
def ecef2ned(self, ecef):
|
||||
ecef = np.array(ecef)
|
||||
return np.dot(self.ecef2ned_matrix, (ecef - self.init_ecef).T).T
|
||||
|
||||
def ned2ecef(self, ned):
|
||||
ned = np.array(ned)
|
||||
# Transpose so that init_ecef will broadcast correctly for 1d or 2d ned.
|
||||
return (np.dot(self.ned2ecef_matrix, ned.T).T + self.init_ecef)
|
||||
|
||||
def geodetic2ned(self, geodetic):
|
||||
ecef = geodetic2ecef(geodetic)
|
||||
return self.ecef2ned(ecef)
|
||||
|
||||
def ned2geodetic(self, ned):
|
||||
ecef = self.ned2ecef(ned)
|
||||
return ecef2geodetic(ecef)
|
||||
geodetic_from_ecef = ecef2geodetic
|
||||
ecef_from_geodetic = geodetic2ecef
|
||||
|
||||
@@ -41,6 +41,17 @@ medmodel_intrinsics = np.array(
|
||||
[ 0. , eon_focal_length / medmodel_zoom, MEDMODEL_CY],
|
||||
[ 0. , 0. , 1.]])
|
||||
|
||||
# CAL model
|
||||
CALMODEL_INPUT_SIZE = (512, 256)
|
||||
CALMODEL_YUV_SIZE = (CALMODEL_INPUT_SIZE[0], CALMODEL_INPUT_SIZE[1] * 3 // 2)
|
||||
CALMODEL_CY = 47.6
|
||||
|
||||
calmodel_zoom = 1.5
|
||||
calmodel_intrinsics = np.array(
|
||||
[[ eon_focal_length / calmodel_zoom, 0. , 0.5 * CALMODEL_INPUT_SIZE[0]],
|
||||
[ 0. , eon_focal_length / calmodel_zoom, CALMODEL_CY],
|
||||
[ 0. , 0. , 1.]])
|
||||
|
||||
|
||||
# BIG model
|
||||
|
||||
@@ -100,7 +111,7 @@ def get_camera_frame_from_model_frame(camera_frame_from_road_frame, height=model
|
||||
|
||||
# This function is super slow, so skip it if height is very close to canonical
|
||||
# TODO: speed it up!
|
||||
if abs(height - model_height) > 0.001: #
|
||||
if abs(height - model_height) > 0.001:
|
||||
camera_from_model_camera = get_model_height_transform(camera_frame_from_road_frame, height)
|
||||
else:
|
||||
camera_from_model_camera = np.eye(3)
|
||||
@@ -130,9 +141,9 @@ def get_camera_frame_from_bigmodel_frame(camera_frame_from_road_frame):
|
||||
|
||||
def get_model_frame(snu_full, camera_frame_from_model_frame, size):
|
||||
idxs = camera_frame_from_model_frame.dot(np.column_stack([np.tile(np.arange(size[0]), size[1]),
|
||||
np.tile(np.arange(size[1]), (size[0],1)).T.flatten(),
|
||||
np.tile(np.arange(size[1]), (size[0], 1)).T.flatten(),
|
||||
np.ones(size[0] * size[1])]).T).T.astype(int)
|
||||
calib_flat = snu_full[idxs[:,1], idxs[:,0]]
|
||||
calib_flat = snu_full[idxs[:, 1], idxs[:, 0]]
|
||||
if len(snu_full.shape) == 3:
|
||||
calib = calib_flat.reshape((size[1], size[0], 3))
|
||||
elif len(snu_full.shape) == 2:
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <eigen3/Eigen/Dense>
|
||||
|
||||
#include "orientation.hpp"
|
||||
#include "coordinates.hpp"
|
||||
|
||||
Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat){
|
||||
if (quat.w() > 0){
|
||||
return quat;
|
||||
} else {
|
||||
return Eigen::Quaterniond(-quat.w(), -quat.x(), -quat.y(), -quat.z());
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::Quaterniond euler2quat(Eigen::Vector3d euler){
|
||||
Eigen::Quaterniond q;
|
||||
|
||||
q = Eigen::AngleAxisd(euler(2), Eigen::Vector3d::UnitZ())
|
||||
* Eigen::AngleAxisd(euler(1), Eigen::Vector3d::UnitY())
|
||||
* Eigen::AngleAxisd(euler(0), Eigen::Vector3d::UnitX());
|
||||
return ensure_unique(q);
|
||||
}
|
||||
|
||||
|
||||
Eigen::Vector3d quat2euler(Eigen::Quaterniond quat){
|
||||
// TODO: switch to eigen implementation if the range of the Euler angles doesn't matter anymore
|
||||
// Eigen::Vector3d euler = quat.toRotationMatrix().eulerAngles(2, 1, 0);
|
||||
// return {euler(2), euler(1), euler(0)};
|
||||
double gamma = atan2(2 * (quat.w() * quat.x() + quat.y() * quat.z()), 1 - 2 * (quat.x()*quat.x() + quat.y()*quat.y()));
|
||||
double theta = asin(2 * (quat.w() * quat.y() - quat.z() * quat.x()));
|
||||
double psi = atan2(2 * (quat.w() * quat.z() + quat.x() * quat.y()), 1 - 2 * (quat.y()*quat.y() + quat.z()*quat.z()));
|
||||
return {gamma, theta, psi};
|
||||
}
|
||||
|
||||
Eigen::Matrix3d quat2rot(Eigen::Quaterniond quat){
|
||||
return quat.toRotationMatrix();
|
||||
}
|
||||
|
||||
Eigen::Quaterniond rot2quat(Eigen::Matrix3d rot){
|
||||
return ensure_unique(Eigen::Quaterniond(rot));
|
||||
}
|
||||
|
||||
Eigen::Matrix3d euler2rot(Eigen::Vector3d euler){
|
||||
return quat2rot(euler2quat(euler));
|
||||
}
|
||||
|
||||
Eigen::Vector3d rot2euler(Eigen::Matrix3d rot){
|
||||
return quat2euler(rot2quat(rot));
|
||||
}
|
||||
|
||||
Eigen::Matrix3d rot_matrix(double roll, double pitch, double yaw){
|
||||
return euler2rot({roll, pitch, yaw});
|
||||
}
|
||||
|
||||
Eigen::Matrix3d rot(Eigen::Vector3d axis, double angle){
|
||||
Eigen::Quaterniond q;
|
||||
q = Eigen::AngleAxisd(angle, axis);
|
||||
return q.toRotationMatrix();
|
||||
}
|
||||
|
||||
|
||||
Eigen::Vector3d ecef_euler_from_ned(ECEF ecef_init, Eigen::Vector3d ned_pose) {
|
||||
/*
|
||||
Using Rotations to Build Aerospace Coordinate Systems
|
||||
Don Koks
|
||||
https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
|
||||
*/
|
||||
LocalCoord converter = LocalCoord(ecef_init);
|
||||
Eigen::Vector3d zero = ecef_init.to_vector();
|
||||
|
||||
Eigen::Vector3d x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero;
|
||||
Eigen::Vector3d y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero;
|
||||
Eigen::Vector3d z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero;
|
||||
|
||||
Eigen::Vector3d x1 = rot(z0, ned_pose(2)) * x0;
|
||||
Eigen::Vector3d y1 = rot(z0, ned_pose(2)) * y0;
|
||||
Eigen::Vector3d z1 = rot(z0, ned_pose(2)) * z0;
|
||||
|
||||
Eigen::Vector3d x2 = rot(y1, ned_pose(1)) * x1;
|
||||
Eigen::Vector3d y2 = rot(y1, ned_pose(1)) * y1;
|
||||
Eigen::Vector3d z2 = rot(y1, ned_pose(1)) * z1;
|
||||
|
||||
Eigen::Vector3d x3 = rot(x2, ned_pose(0)) * x2;
|
||||
Eigen::Vector3d y3 = rot(x2, ned_pose(0)) * y2;
|
||||
|
||||
|
||||
x0 = Eigen::Vector3d(1, 0, 0);
|
||||
y0 = Eigen::Vector3d(0, 1, 0);
|
||||
z0 = Eigen::Vector3d(0, 0, 1);
|
||||
|
||||
double psi = atan2(x3.dot(y0), x3.dot(x0));
|
||||
double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2)));
|
||||
|
||||
y2 = rot(z0, psi) * y0;
|
||||
z2 = rot(y2, theta) * z0;
|
||||
|
||||
double phi = atan2(y3.dot(z2), y3.dot(y2));
|
||||
|
||||
return {phi, theta, psi};
|
||||
}
|
||||
|
||||
Eigen::Vector3d ned_euler_from_ecef(ECEF ecef_init, Eigen::Vector3d ecef_pose){
|
||||
/*
|
||||
Using Rotations to Build Aerospace Coordinate Systems
|
||||
Don Koks
|
||||
https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
|
||||
*/
|
||||
LocalCoord converter = LocalCoord(ecef_init);
|
||||
|
||||
Eigen::Vector3d x0 = Eigen::Vector3d(1, 0, 0);
|
||||
Eigen::Vector3d y0 = Eigen::Vector3d(0, 1, 0);
|
||||
Eigen::Vector3d z0 = Eigen::Vector3d(0, 0, 1);
|
||||
|
||||
Eigen::Vector3d x1 = rot(z0, ecef_pose(2)) * x0;
|
||||
Eigen::Vector3d y1 = rot(z0, ecef_pose(2)) * y0;
|
||||
Eigen::Vector3d z1 = rot(z0, ecef_pose(2)) * z0;
|
||||
|
||||
Eigen::Vector3d x2 = rot(y1, ecef_pose(1)) * x1;
|
||||
Eigen::Vector3d y2 = rot(y1, ecef_pose(1)) * y1;
|
||||
Eigen::Vector3d z2 = rot(y1, ecef_pose(1)) * z1;
|
||||
|
||||
Eigen::Vector3d x3 = rot(x2, ecef_pose(0)) * x2;
|
||||
Eigen::Vector3d y3 = rot(x2, ecef_pose(0)) * y2;
|
||||
|
||||
Eigen::Vector3d zero = ecef_init.to_vector();
|
||||
x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero;
|
||||
y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero;
|
||||
z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero;
|
||||
|
||||
double psi = atan2(x3.dot(y0), x3.dot(x0));
|
||||
double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2)));
|
||||
|
||||
y2 = rot(z0, psi) * y0;
|
||||
z2 = rot(y2, theta) * z0;
|
||||
|
||||
double phi = atan2(y3.dot(z2), y3.dot(y2));
|
||||
|
||||
return {phi, theta, psi};
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(void){
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include <eigen3/Eigen/Dense>
|
||||
#include "coordinates.hpp"
|
||||
|
||||
|
||||
Eigen::Quaterniond ensure_unique(Eigen::Quaterniond quat);
|
||||
|
||||
Eigen::Quaterniond euler2quat(Eigen::Vector3d euler);
|
||||
Eigen::Vector3d quat2euler(Eigen::Quaterniond quat);
|
||||
Eigen::Matrix3d quat2rot(Eigen::Quaterniond quat);
|
||||
Eigen::Quaterniond rot2quat(Eigen::Matrix3d rot);
|
||||
Eigen::Matrix3d euler2rot(Eigen::Vector3d euler);
|
||||
Eigen::Vector3d rot2euler(Eigen::Matrix3d rot);
|
||||
Eigen::Matrix3d rot_matrix(double roll, double pitch, double yaw);
|
||||
Eigen::Matrix3d rot(Eigen::Vector3d axis, double angle);
|
||||
Eigen::Vector3d ecef_euler_from_ned(ECEF ecef_init, Eigen::Vector3d ned_pose);
|
||||
Eigen::Vector3d ned_euler_from_ecef(ECEF ecef_init, Eigen::Vector3d ecef_pose);
|
||||
@@ -1,295 +1,53 @@
|
||||
# pylint: skip-file
|
||||
import numpy as np
|
||||
from numpy import dot, inner, array, linalg
|
||||
from common.transformations.coordinates import LocalCoord
|
||||
|
||||
from common.transformations.transformations import (ecef_euler_from_ned_single,
|
||||
euler2quat_single,
|
||||
euler2rot_single,
|
||||
ned_euler_from_ecef_single,
|
||||
quat2euler_single,
|
||||
quat2rot_single,
|
||||
rot2euler_single,
|
||||
rot2quat_single)
|
||||
|
||||
|
||||
'''
|
||||
Vectorized functions that transform between
|
||||
rotation matrices, euler angles and quaternions.
|
||||
All support lists, array or array of arrays as inputs.
|
||||
Supports both x2y and y_from_x format (y_from_x preferred!).
|
||||
'''
|
||||
def numpy_wrap(function, input_shape, output_shape):
|
||||
"""Wrap a function to take either an input or list of inputs and return the correct shape"""
|
||||
def f(*inps):
|
||||
*args, inp = inps
|
||||
inp = np.array(inp)
|
||||
shape = inp.shape
|
||||
|
||||
def euler2quat(eulers):
|
||||
eulers = array(eulers)
|
||||
if len(eulers.shape) > 1:
|
||||
output_shape = (-1,4)
|
||||
else:
|
||||
output_shape = (4,)
|
||||
eulers = np.atleast_2d(eulers)
|
||||
gamma, theta, psi = eulers[:,0], eulers[:,1], eulers[:,2]
|
||||
if len(shape) == len(input_shape):
|
||||
out_shape = output_shape
|
||||
else:
|
||||
out_shape = (shape[0],) + output_shape
|
||||
|
||||
q0 = np.cos(gamma / 2) * np.cos(theta / 2) * np.cos(psi / 2) + \
|
||||
np.sin(gamma / 2) * np.sin(theta / 2) * np.sin(psi / 2)
|
||||
q1 = np.sin(gamma / 2) * np.cos(theta / 2) * np.cos(psi / 2) - \
|
||||
np.cos(gamma / 2) * np.sin(theta / 2) * np.sin(psi / 2)
|
||||
q2 = np.cos(gamma / 2) * np.sin(theta / 2) * np.cos(psi / 2) + \
|
||||
np.sin(gamma / 2) * np.cos(theta / 2) * np.sin(psi / 2)
|
||||
q3 = np.cos(gamma / 2) * np.cos(theta / 2) * np.sin(psi / 2) - \
|
||||
np.sin(gamma / 2) * np.sin(theta / 2) * np.cos(psi / 2)
|
||||
# Add empty dimension if inputs is not a list
|
||||
if len(shape) == len(input_shape):
|
||||
inp.shape = (1, ) + inp.shape
|
||||
|
||||
quats = array([q0, q1, q2, q3]).T
|
||||
for i in range(len(quats)):
|
||||
if quats[i,0] < 0:
|
||||
quats[i] = -quats[i]
|
||||
return quats.reshape(output_shape)
|
||||
result = np.asarray([function(*args, i) for i in inp])
|
||||
result.shape = out_shape
|
||||
return result
|
||||
return f
|
||||
|
||||
|
||||
def quat2euler(quats):
|
||||
quats = array(quats)
|
||||
if len(quats.shape) > 1:
|
||||
output_shape = (-1,3)
|
||||
else:
|
||||
output_shape = (3,)
|
||||
quats = np.atleast_2d(quats)
|
||||
q0, q1, q2, q3 = quats[:,0], quats[:,1], quats[:,2], quats[:,3]
|
||||
|
||||
gamma = np.arctan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1**2 + q2**2))
|
||||
theta = np.arcsin(2 * (q0 * q2 - q3 * q1))
|
||||
psi = np.arctan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2**2 + q3**2))
|
||||
|
||||
eulers = array([gamma, theta, psi]).T
|
||||
return eulers.reshape(output_shape)
|
||||
|
||||
|
||||
def quat2rot(quats):
|
||||
quats = array(quats)
|
||||
input_shape = quats.shape
|
||||
quats = np.atleast_2d(quats)
|
||||
Rs = np.zeros((quats.shape[0], 3, 3))
|
||||
q0 = quats[:, 0]
|
||||
q1 = quats[:, 1]
|
||||
q2 = quats[:, 2]
|
||||
q3 = quats[:, 3]
|
||||
Rs[:, 0, 0] = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3
|
||||
Rs[:, 0, 1] = 2 * (q1 * q2 - q0 * q3)
|
||||
Rs[:, 0, 2] = 2 * (q0 * q2 + q1 * q3)
|
||||
Rs[:, 1, 0] = 2 * (q1 * q2 + q0 * q3)
|
||||
Rs[:, 1, 1] = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3
|
||||
Rs[:, 1, 2] = 2 * (q2 * q3 - q0 * q1)
|
||||
Rs[:, 2, 0] = 2 * (q1 * q3 - q0 * q2)
|
||||
Rs[:, 2, 1] = 2 * (q0 * q1 + q2 * q3)
|
||||
Rs[:, 2, 2] = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3
|
||||
|
||||
if len(input_shape) < 2:
|
||||
return Rs[0]
|
||||
else:
|
||||
return Rs
|
||||
|
||||
|
||||
def rot2quat(rots):
|
||||
input_shape = rots.shape
|
||||
if len(input_shape) < 3:
|
||||
rots = array([rots])
|
||||
K3 = np.empty((len(rots), 4, 4))
|
||||
K3[:, 0, 0] = (rots[:, 0, 0] - rots[:, 1, 1] - rots[:, 2, 2]) / 3.0
|
||||
K3[:, 0, 1] = (rots[:, 1, 0] + rots[:, 0, 1]) / 3.0
|
||||
K3[:, 0, 2] = (rots[:, 2, 0] + rots[:, 0, 2]) / 3.0
|
||||
K3[:, 0, 3] = (rots[:, 1, 2] - rots[:, 2, 1]) / 3.0
|
||||
K3[:, 1, 0] = K3[:, 0, 1]
|
||||
K3[:, 1, 1] = (rots[:, 1, 1] - rots[:, 0, 0] - rots[:, 2, 2]) / 3.0
|
||||
K3[:, 1, 2] = (rots[:, 2, 1] + rots[:, 1, 2]) / 3.0
|
||||
K3[:, 1, 3] = (rots[:, 2, 0] - rots[:, 0, 2]) / 3.0
|
||||
K3[:, 2, 0] = K3[:, 0, 2]
|
||||
K3[:, 2, 1] = K3[:, 1, 2]
|
||||
K3[:, 2, 2] = (rots[:, 2, 2] - rots[:, 0, 0] - rots[:, 1, 1]) / 3.0
|
||||
K3[:, 2, 3] = (rots[:, 0, 1] - rots[:, 1, 0]) / 3.0
|
||||
K3[:, 3, 0] = K3[:, 0, 3]
|
||||
K3[:, 3, 1] = K3[:, 1, 3]
|
||||
K3[:, 3, 2] = K3[:, 2, 3]
|
||||
K3[:, 3, 3] = (rots[:, 0, 0] + rots[:, 1, 1] + rots[:, 2, 2]) / 3.0
|
||||
q = np.empty((len(rots), 4))
|
||||
for i in range(len(rots)):
|
||||
_, eigvecs = linalg.eigh(K3[i].T)
|
||||
eigvecs = eigvecs[:,3:]
|
||||
q[i, 0] = eigvecs[-1]
|
||||
q[i, 1:] = -eigvecs[:-1].flatten()
|
||||
if q[i, 0] < 0:
|
||||
q[i] = -q[i]
|
||||
|
||||
if len(input_shape) < 3:
|
||||
return q[0]
|
||||
else:
|
||||
return q
|
||||
|
||||
|
||||
def euler2rot(eulers):
|
||||
return rotations_from_quats(euler2quat(eulers))
|
||||
|
||||
|
||||
def rot2euler(rots):
|
||||
return quat2euler(quats_from_rotations(rots))
|
||||
|
||||
euler2quat = numpy_wrap(euler2quat_single, (3,), (4,))
|
||||
quat2euler = numpy_wrap(quat2euler_single, (4,), (3,))
|
||||
quat2rot = numpy_wrap(quat2rot_single, (4,), (3, 3))
|
||||
rot2quat = numpy_wrap(rot2quat_single, (3, 3), (4,))
|
||||
euler2rot = numpy_wrap(euler2rot_single, (3,), (3, 3))
|
||||
rot2euler = numpy_wrap(rot2euler_single, (3, 3), (3,))
|
||||
ecef_euler_from_ned = numpy_wrap(ecef_euler_from_ned_single, (3,), (3,))
|
||||
ned_euler_from_ecef = numpy_wrap(ned_euler_from_ecef_single, (3,), (3,))
|
||||
|
||||
quats_from_rotations = rot2quat
|
||||
quat_from_rot = rot2quat
|
||||
rotations_from_quats = quat2rot
|
||||
rot_from_quat= quat2rot
|
||||
rot_from_quat= quat2rot
|
||||
rot_from_quat = quat2rot
|
||||
rot_from_quat = quat2rot
|
||||
euler_from_rot = rot2euler
|
||||
euler_from_quat = quat2euler
|
||||
rot_from_euler = euler2rot
|
||||
quat_from_euler = euler2quat
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'''
|
||||
Random helpers below
|
||||
'''
|
||||
|
||||
|
||||
def quat_product(q, r):
|
||||
t = np.zeros(4)
|
||||
t[0] = r[0] * q[0] - r[1] * q[1] - r[2] * q[2] - r[3] * q[3]
|
||||
t[1] = r[0] * q[1] + r[1] * q[0] - r[2] * q[3] + r[3] * q[2]
|
||||
t[2] = r[0] * q[2] + r[1] * q[3] + r[2] * q[0] - r[3] * q[1]
|
||||
t[3] = r[0] * q[3] - r[1] * q[2] + r[2] * q[1] + r[3] * q[0]
|
||||
return t
|
||||
|
||||
|
||||
def rot_matrix(roll, pitch, yaw):
|
||||
cr, sr = np.cos(roll), np.sin(roll)
|
||||
cp, sp = np.cos(pitch), np.sin(pitch)
|
||||
cy, sy = np.cos(yaw), np.sin(yaw)
|
||||
rr = array([[1,0,0],[0, cr,-sr],[0, sr, cr]])
|
||||
rp = array([[cp,0,sp],[0, 1,0],[-sp, 0, cp]])
|
||||
ry = array([[cy,-sy,0],[sy, cy,0],[0, 0, 1]])
|
||||
return ry.dot(rp.dot(rr))
|
||||
|
||||
|
||||
def rot(axis, angle):
|
||||
# Rotates around an arbitrary axis
|
||||
ret_1 = (1 - np.cos(angle)) * array([[axis[0]**2, axis[0] * axis[1], axis[0] * axis[2]], [
|
||||
axis[1] * axis[0], axis[1]**2, axis[1] * axis[2]
|
||||
], [axis[2] * axis[0], axis[2] * axis[1], axis[2]**2]])
|
||||
ret_2 = np.cos(angle) * np.eye(3)
|
||||
ret_3 = np.sin(angle) * array([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]],
|
||||
[-axis[1], axis[0], 0]])
|
||||
return ret_1 + ret_2 + ret_3
|
||||
|
||||
|
||||
def ecef_euler_from_ned(ned_ecef_init, ned_pose):
|
||||
'''
|
||||
Got it from here:
|
||||
Using Rotations to Build Aerospace Coordinate Systems
|
||||
-Don Koks
|
||||
'''
|
||||
converter = LocalCoord.from_ecef(ned_ecef_init)
|
||||
x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0])
|
||||
y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0])
|
||||
z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0])
|
||||
|
||||
x1 = rot(z0, ned_pose[2]).dot(x0)
|
||||
y1 = rot(z0, ned_pose[2]).dot(y0)
|
||||
z1 = rot(z0, ned_pose[2]).dot(z0)
|
||||
|
||||
x2 = rot(y1, ned_pose[1]).dot(x1)
|
||||
y2 = rot(y1, ned_pose[1]).dot(y1)
|
||||
z2 = rot(y1, ned_pose[1]).dot(z1)
|
||||
|
||||
x3 = rot(x2, ned_pose[0]).dot(x2)
|
||||
y3 = rot(x2, ned_pose[0]).dot(y2)
|
||||
#z3 = rot(x2, ned_pose[0]).dot(z2)
|
||||
|
||||
x0 = array([1, 0, 0])
|
||||
y0 = array([0, 1, 0])
|
||||
z0 = array([0, 0, 1])
|
||||
|
||||
psi = np.arctan2(inner(x3, y0), inner(x3, x0))
|
||||
theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2))
|
||||
y2 = rot(z0, psi).dot(y0)
|
||||
z2 = rot(y2, theta).dot(z0)
|
||||
phi = np.arctan2(inner(y3, z2), inner(y3, y2))
|
||||
|
||||
ret = array([phi, theta, psi])
|
||||
return ret
|
||||
|
||||
|
||||
def ned_euler_from_ecef(ned_ecef_init, ecef_poses):
|
||||
'''
|
||||
Got the math from here:
|
||||
Using Rotations to Build Aerospace Coordinate Systems
|
||||
-Don Koks
|
||||
|
||||
Also accepts array of ecef_poses and array of ned_ecef_inits.
|
||||
Where each row is a pose and an ecef_init.
|
||||
'''
|
||||
ned_ecef_init = array(ned_ecef_init)
|
||||
ecef_poses = array(ecef_poses)
|
||||
output_shape = ecef_poses.shape
|
||||
ned_ecef_init = np.atleast_2d(ned_ecef_init)
|
||||
if ned_ecef_init.shape[0] == 1:
|
||||
ned_ecef_init = np.tile(ned_ecef_init[0], (output_shape[0], 1))
|
||||
ecef_poses = np.atleast_2d(ecef_poses)
|
||||
|
||||
ned_poses = np.zeros(ecef_poses.shape)
|
||||
for i, ecef_pose in enumerate(ecef_poses):
|
||||
converter = LocalCoord.from_ecef(ned_ecef_init[i])
|
||||
x0 = array([1, 0, 0])
|
||||
y0 = array([0, 1, 0])
|
||||
z0 = array([0, 0, 1])
|
||||
|
||||
x1 = rot(z0, ecef_pose[2]).dot(x0)
|
||||
y1 = rot(z0, ecef_pose[2]).dot(y0)
|
||||
z1 = rot(z0, ecef_pose[2]).dot(z0)
|
||||
|
||||
x2 = rot(y1, ecef_pose[1]).dot(x1)
|
||||
y2 = rot(y1, ecef_pose[1]).dot(y1)
|
||||
z2 = rot(y1, ecef_pose[1]).dot(z1)
|
||||
|
||||
x3 = rot(x2, ecef_pose[0]).dot(x2)
|
||||
y3 = rot(x2, ecef_pose[0]).dot(y2)
|
||||
#z3 = rot(x2, ecef_pose[0]).dot(z2)
|
||||
|
||||
x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0])
|
||||
y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0])
|
||||
z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0])
|
||||
|
||||
psi = np.arctan2(inner(x3, y0), inner(x3, x0))
|
||||
theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2))
|
||||
y2 = rot(z0, psi).dot(y0)
|
||||
z2 = rot(y2, theta).dot(z0)
|
||||
phi = np.arctan2(inner(y3, z2), inner(y3, y2))
|
||||
ned_poses[i] = array([phi, theta, psi])
|
||||
|
||||
return ned_poses.reshape(output_shape)
|
||||
|
||||
|
||||
def ecef2car(car_ecef, psi, theta, points_ecef, ned_converter):
|
||||
"""
|
||||
TODO: add roll rotation
|
||||
Converts an array of points in ecef coordinates into
|
||||
x-forward, y-left, z-up coordinates
|
||||
Parameters
|
||||
----------
|
||||
psi: yaw, radian
|
||||
theta: pitch, radian
|
||||
Returns
|
||||
-------
|
||||
[x, y, z] coordinates in car frame
|
||||
"""
|
||||
|
||||
# input is an array of points in ecef cocrdinates
|
||||
# output is an array of points in car's coordinate (x-front, y-left, z-up)
|
||||
|
||||
# convert points to NED
|
||||
points_ned = []
|
||||
for p in points_ecef:
|
||||
points_ned.append(ned_converter.ecef2ned_matrix.dot(array(p) - car_ecef))
|
||||
|
||||
points_ned = np.vstack(points_ned).T
|
||||
|
||||
# n, e, d -> x, y, z
|
||||
# Calculate relative postions and rotate wrt to heading and pitch of car
|
||||
invert_R = array([[1., 0., 0.], [0., -1., 0.], [0., 0., -1.]])
|
||||
|
||||
c, s = np.cos(psi), np.sin(psi)
|
||||
yaw_R = array([[c, s, 0.], [-s, c, 0.], [0., 0., 1.]])
|
||||
|
||||
c, s = np.cos(theta), np.sin(theta)
|
||||
pitch_R = array([[c, 0., -s], [0., 1., 0.], [s, 0., c]])
|
||||
|
||||
return dot(pitch_R, dot(yaw_R, dot(invert_R, points_ned)))
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import os
|
||||
import numpy
|
||||
import sysconfig
|
||||
|
||||
from Cython.Build import cythonize
|
||||
from Cython.Distutils import build_ext
|
||||
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
|
||||
|
||||
def get_ext_filename_without_platform_suffix(filename):
|
||||
name, ext = os.path.splitext(filename)
|
||||
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
|
||||
|
||||
if ext_suffix == ext:
|
||||
return filename
|
||||
|
||||
ext_suffix = ext_suffix.replace(ext, '')
|
||||
idx = name.find(ext_suffix)
|
||||
|
||||
if idx == -1:
|
||||
return filename
|
||||
else:
|
||||
return name[:idx] + ext
|
||||
|
||||
|
||||
class BuildExtWithoutPlatformSuffix(build_ext):
|
||||
def get_ext_filename(self, ext_name):
|
||||
filename = super().get_ext_filename(ext_name)
|
||||
return get_ext_filename_without_platform_suffix(filename)
|
||||
|
||||
|
||||
setup(
|
||||
name='Cython transformations wrapper',
|
||||
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
|
||||
ext_modules=cythonize(
|
||||
Extension(
|
||||
"transformations",
|
||||
sources=["transformations.pyx"],
|
||||
language="c++",
|
||||
extra_compile_args=["-std=c++14"],
|
||||
include_dirs=[numpy.get_include()],
|
||||
)
|
||||
))
|
||||
@@ -0,0 +1,71 @@
|
||||
from libcpp cimport bool
|
||||
|
||||
cdef extern from "orientation.cc":
|
||||
pass
|
||||
|
||||
cdef extern from "orientation.hpp":
|
||||
cdef cppclass Quaternion "Eigen::Quaterniond":
|
||||
Quaternion()
|
||||
Quaternion(double, double, double, double)
|
||||
double w()
|
||||
double x()
|
||||
double y()
|
||||
double z()
|
||||
|
||||
cdef cppclass Vector3 "Eigen::Vector3d":
|
||||
Vector3()
|
||||
Vector3(double, double, double)
|
||||
double operator()(int)
|
||||
|
||||
cdef cppclass Matrix3 "Eigen::Matrix3d":
|
||||
Matrix3()
|
||||
Matrix3(double*)
|
||||
|
||||
double operator()(int, int)
|
||||
|
||||
Quaternion euler2quat(Vector3)
|
||||
Vector3 quat2euler(Quaternion)
|
||||
Matrix3 quat2rot(Quaternion)
|
||||
Quaternion rot2quat(Matrix3)
|
||||
Vector3 rot2euler(Matrix3)
|
||||
Matrix3 euler2rot(Vector3)
|
||||
Matrix3 rot_matrix(double, double, double)
|
||||
Vector3 ecef_euler_from_ned(ECEF, Vector3)
|
||||
Vector3 ned_euler_from_ecef(ECEF, Vector3)
|
||||
|
||||
|
||||
cdef extern from "coordinates.cc":
|
||||
cdef struct ECEF:
|
||||
double x
|
||||
double y
|
||||
double z
|
||||
|
||||
cdef struct NED:
|
||||
double n
|
||||
double e
|
||||
double d
|
||||
|
||||
cdef struct Geodetic:
|
||||
double lat
|
||||
double lon
|
||||
double alt
|
||||
bool radians
|
||||
|
||||
ECEF geodetic2ecef(Geodetic)
|
||||
Geodetic ecef2geodetic(ECEF)
|
||||
|
||||
cdef cppclass LocalCoord_c "LocalCoord":
|
||||
Matrix3 ned2ecef_matrix
|
||||
Matrix3 ecef2ned_matrix
|
||||
|
||||
LocalCoord_c(Geodetic, ECEF)
|
||||
LocalCoord_c(Geodetic)
|
||||
LocalCoord_c(ECEF)
|
||||
|
||||
NED ecef2ned(ECEF)
|
||||
ECEF ned2ecef(NED)
|
||||
NED geodetic2ned(Geodetic)
|
||||
Geodetic ned2geodetic(NED)
|
||||
|
||||
cdef extern from "coordinates.hpp":
|
||||
pass
|
||||
@@ -0,0 +1,172 @@
|
||||
from transformations cimport Matrix3, Vector3, Quaternion
|
||||
from transformations cimport ECEF, NED, Geodetic
|
||||
|
||||
from transformations cimport euler2quat as euler2quat_c
|
||||
from transformations cimport quat2euler as quat2euler_c
|
||||
from transformations cimport quat2rot as quat2rot_c
|
||||
from transformations cimport rot2quat as rot2quat_c
|
||||
from transformations cimport euler2rot as euler2rot_c
|
||||
from transformations cimport rot2euler as rot2euler_c
|
||||
from transformations cimport rot_matrix as rot_matrix_c
|
||||
from transformations cimport ecef_euler_from_ned as ecef_euler_from_ned_c
|
||||
from transformations cimport ned_euler_from_ecef as ned_euler_from_ecef_c
|
||||
from transformations cimport geodetic2ecef as geodetic2ecef_c
|
||||
from transformations cimport ecef2geodetic as ecef2geodetic_c
|
||||
from transformations cimport LocalCoord_c
|
||||
|
||||
|
||||
import cython
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
|
||||
cdef np.ndarray[double, ndim=2] matrix2numpy(Matrix3 m):
|
||||
return np.array([
|
||||
[m(0, 0), m(0, 1), m(0, 2)],
|
||||
[m(1, 0), m(1, 1), m(1, 2)],
|
||||
[m(2, 0), m(2, 1), m(2, 2)],
|
||||
])
|
||||
|
||||
cdef Matrix3 numpy2matrix (np.ndarray[double, ndim=2, mode="fortran"] m):
|
||||
assert m.shape[0] == 3
|
||||
assert m.shape[1] == 3
|
||||
return Matrix3(<double*>m.data)
|
||||
|
||||
cdef ECEF list2ecef(ecef):
|
||||
cdef ECEF e;
|
||||
e.x = ecef[0]
|
||||
e.y = ecef[1]
|
||||
e.z = ecef[2]
|
||||
return e
|
||||
|
||||
cdef NED list2ned(ned):
|
||||
cdef NED n;
|
||||
n.n = ned[0]
|
||||
n.e = ned[1]
|
||||
n.d = ned[2]
|
||||
return n
|
||||
|
||||
cdef Geodetic list2geodetic(geodetic):
|
||||
cdef Geodetic g
|
||||
g.lat = geodetic[0]
|
||||
g.lon = geodetic[1]
|
||||
g.alt = geodetic[2]
|
||||
return g
|
||||
|
||||
def euler2quat_single(euler):
|
||||
cdef Vector3 e = Vector3(euler[0], euler[1], euler[2])
|
||||
cdef Quaternion q = euler2quat_c(e)
|
||||
return [q.w(), q.x(), q.y(), q.z()]
|
||||
|
||||
def quat2euler_single(quat):
|
||||
cdef Quaternion q = Quaternion(quat[0], quat[1], quat[2], quat[3])
|
||||
cdef Vector3 e = quat2euler_c(q);
|
||||
return [e(0), e(1), e(2)]
|
||||
|
||||
def quat2rot_single(quat):
|
||||
cdef Quaternion q = Quaternion(quat[0], quat[1], quat[2], quat[3])
|
||||
cdef Matrix3 r = quat2rot_c(q)
|
||||
return matrix2numpy(r)
|
||||
|
||||
def rot2quat_single(rot):
|
||||
cdef Matrix3 r = numpy2matrix(np.asfortranarray(rot, dtype=np.double))
|
||||
cdef Quaternion q = rot2quat_c(r)
|
||||
return [q.w(), q.x(), q.y(), q.z()]
|
||||
|
||||
def euler2rot_single(euler):
|
||||
cdef Vector3 e = Vector3(euler[0], euler[1], euler[2])
|
||||
cdef Matrix3 r = euler2rot_c(e)
|
||||
return matrix2numpy(r)
|
||||
|
||||
def rot2euler_single(rot):
|
||||
cdef Matrix3 r = numpy2matrix(np.asfortranarray(rot, dtype=np.double))
|
||||
cdef Vector3 e = rot2euler_c(r)
|
||||
return [e(0), e(1), e(2)]
|
||||
|
||||
def rot_matrix(roll, pitch, yaw):
|
||||
return matrix2numpy(rot_matrix_c(roll, pitch, yaw))
|
||||
|
||||
def ecef_euler_from_ned_single(ecef_init, ned_pose):
|
||||
cdef ECEF init = list2ecef(ecef_init)
|
||||
cdef Vector3 pose = Vector3(ned_pose[0], ned_pose[1], ned_pose[2])
|
||||
|
||||
cdef Vector3 e = ecef_euler_from_ned_c(init, pose)
|
||||
return [e(0), e(1), e(2)]
|
||||
|
||||
def ned_euler_from_ecef_single(ecef_init, ecef_pose):
|
||||
cdef ECEF init = list2ecef(ecef_init)
|
||||
cdef Vector3 pose = Vector3(ecef_pose[0], ecef_pose[1], ecef_pose[2])
|
||||
|
||||
cdef Vector3 e = ned_euler_from_ecef_c(init, pose)
|
||||
return [e(0), e(1), e(2)]
|
||||
|
||||
def geodetic2ecef_single(geodetic):
|
||||
cdef Geodetic g = list2geodetic(geodetic)
|
||||
cdef ECEF e = geodetic2ecef_c(g)
|
||||
return [e.x, e.y, e.z]
|
||||
|
||||
def ecef2geodetic_single(ecef):
|
||||
cdef ECEF e = list2ecef(ecef)
|
||||
cdef Geodetic g = ecef2geodetic_c(e)
|
||||
return [g.lat, g.lon, g.alt]
|
||||
|
||||
|
||||
cdef class LocalCoord:
|
||||
cdef LocalCoord_c * lc
|
||||
|
||||
def __init__(self, geodetic=None, ecef=None):
|
||||
assert (geodetic is not None) or (ecef is not None)
|
||||
if geodetic is not None:
|
||||
self.lc = new LocalCoord_c(list2geodetic(geodetic))
|
||||
elif ecef is not None:
|
||||
self.lc = new LocalCoord_c(list2ecef(ecef))
|
||||
|
||||
@property
|
||||
def ned2ecef_matrix(self):
|
||||
return matrix2numpy(self.lc.ned2ecef_matrix)
|
||||
|
||||
@property
|
||||
def ecef2ned_matrix(self):
|
||||
return matrix2numpy(self.lc.ecef2ned_matrix)
|
||||
|
||||
@property
|
||||
def ned_from_ecef_matrix(self):
|
||||
return self.ecef2ned_matrix
|
||||
|
||||
@property
|
||||
def ecef_from_ned_matrix(self):
|
||||
return self.ned2ecef_matrix
|
||||
|
||||
@classmethod
|
||||
def from_geodetic(cls, geodetic):
|
||||
return cls(geodetic=geodetic)
|
||||
|
||||
@classmethod
|
||||
def from_ecef(cls, ecef):
|
||||
return cls(ecef=ecef)
|
||||
|
||||
def ecef2ned_single(self, ecef):
|
||||
assert self.lc
|
||||
cdef ECEF e = list2ecef(ecef)
|
||||
cdef NED n = self.lc.ecef2ned(e)
|
||||
return [n.n, n.e, n.d]
|
||||
|
||||
def ned2ecef_single(self, ned):
|
||||
assert self.lc
|
||||
cdef NED n = list2ned(ned)
|
||||
cdef ECEF e = self.lc.ned2ecef(n)
|
||||
return [e.x, e.y, e.z]
|
||||
|
||||
def geodetic2ned_single(self, geodetic):
|
||||
assert self.lc
|
||||
cdef Geodetic g = list2geodetic(geodetic)
|
||||
cdef NED n = self.lc.geodetic2ned(g)
|
||||
return [n.n, n.e, n.d]
|
||||
|
||||
def ned2geodetic_single(self, ned):
|
||||
assert self.lc
|
||||
cdef NED n = list2ned(ned)
|
||||
cdef Geodetic g = self.lc.ned2geodetic(n)
|
||||
return [g.lat, g.lon, g.alt]
|
||||
|
||||
def __dealloc__(self):
|
||||
del self.lc
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-3bd2b3bdd6a501569e00b8f12786d65e0fd2788c0dd238f8c986e3e2e504683a-kernel.zip",
|
||||
"ota_hash": "3bd2b3bdd6a501569e00b8f12786d65e0fd2788c0dd238f8c986e3e2e504683a",
|
||||
"recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-97c27e6ed04ed6bb0608b845a2d4100912093f9380c3f2ba6b56bccd608e5f6e.img",
|
||||
"recovery_len": 15861036,
|
||||
"recovery_hash": "97c27e6ed04ed6bb0608b845a2d4100912093f9380c3f2ba6b56bccd608e5f6e"
|
||||
}
|
||||
+42
-13
@@ -41,9 +41,12 @@ function launch {
|
||||
|
||||
mv $BASEDIR /data/safe_staging/old_openpilot
|
||||
mv "${STAGING_ROOT}/finalized" $BASEDIR
|
||||
cd $BASEDIR
|
||||
|
||||
# The mv changed our working directory to /data/safe_staging/old_openpilot
|
||||
cd "${BASEDIR}"
|
||||
# Partial mitigation for symlink-related filesystem corruption
|
||||
# Ensure all files match the repo versions after update
|
||||
git reset --hard
|
||||
git submodule foreach --recursive git reset --hard
|
||||
|
||||
echo "Restarting launch script ${LAUNCHER_LOCATION}"
|
||||
exec "${LAUNCHER_LOCATION}"
|
||||
@@ -55,18 +58,22 @@ function launch {
|
||||
fi
|
||||
fi
|
||||
|
||||
# no cpu rationing for now
|
||||
echo 0-3 > /dev/cpuset/background/cpus
|
||||
echo 0-3 > /dev/cpuset/system-background/cpus
|
||||
echo 0-3 > /dev/cpuset/foreground/boost/cpus
|
||||
echo 0-3 > /dev/cpuset/foreground/cpus
|
||||
echo 0-3 > /dev/cpuset/android/cpus
|
||||
# Android and other system processes are not permitted to run on CPU 3
|
||||
# NEOS installed app processes can run anywhere
|
||||
echo 0-2 > /dev/cpuset/background/cpus
|
||||
echo 0-2 > /dev/cpuset/system-background/cpus
|
||||
[ -d "/dev/cpuset/foreground/boost/cpus" ] && echo 0-2 > /dev/cpuset/foreground/boost/cpus # Not present in < NEOS 15
|
||||
echo 0-2 > /dev/cpuset/foreground/cpus
|
||||
echo 0-2 > /dev/cpuset/android/cpus
|
||||
echo 0-3 > /dev/cpuset/app/cpus
|
||||
|
||||
# change interrupt affinity
|
||||
echo 3 > /proc/irq/6/smp_affinity_list # MDSS
|
||||
echo 1 > /proc/irq/78/smp_affinity_list # Modem, can potentially lock up
|
||||
echo 2 > /proc/irq/733/smp_affinity_list # USB
|
||||
echo 2 > /proc/irq/736/smp_affinity_list # USB
|
||||
# Collect RIL and other possibly long-running I/O interrupts onto CPU 1
|
||||
echo 1 > /proc/irq/78/smp_affinity_list # qcom,smd-modem (LTE radio)
|
||||
echo 1 > /proc/irq/33/smp_affinity_list # ufshcd (flash storage)
|
||||
echo 1 > /proc/irq/35/smp_affinity_list # wifi (wlan_pci)
|
||||
# USB traffic needs realtime handling on cpu 3
|
||||
[ -d "/proc/irq/733" ] && echo 3 > /proc/irq/733/smp_affinity_list # USB for LeEco
|
||||
[ -d "/proc/irq/736" ] && echo 3 > /proc/irq/736/smp_affinity_list # USB for OP3T
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
|
||||
@@ -82,9 +89,31 @@ function launch {
|
||||
cp "$DIR/scripts/continue.sh" "/data/data/com.termux/files/continue.sh"
|
||||
fi
|
||||
|
||||
if [ ! -f "$BASEDIR/prebuilt" ]; then
|
||||
echo "Clearing build products and resetting scons state prior to NEOS update"
|
||||
cd $BASEDIR && scons --clean
|
||||
rm -rf /tmp/scons_cache
|
||||
rm -r $BASEDIR/.sconsign.dblite
|
||||
fi
|
||||
"$DIR/installer/updater/updater" "file://$DIR/installer/updater/update.json"
|
||||
else
|
||||
if [[ $(uname -v) == "#1 SMP PREEMPT Wed Jun 10 12:40:53 PDT 2020" ]]; then
|
||||
"$DIR/installer/updater/updater" "file://$DIR/installer/updater/update_kernel.json"
|
||||
fi
|
||||
fi
|
||||
|
||||
# One-time fix for a subset of OP3T with gyro orientation offsets.
|
||||
# Remove and regenerate qcom sensor registry. Only done on OP3T mainboards.
|
||||
# Performed exactly once. The old registry is preserved just-in-case, and
|
||||
# doubles as a flag denoting we've already done the reset.
|
||||
# TODO: we should really grow per-platform detect and setup routines
|
||||
if ! $(grep -q "letv" /proc/cmdline) && [ ! -f "/persist/comma/op3t-sns-reg-backup" ]; then
|
||||
echo "Performing OP3T sensor registry reset"
|
||||
mv /persist/sensors/sns.reg /persist/comma/op3t-sns-reg-backup &&
|
||||
rm -f /persist/sensors/sensors_settings /persist/sensors/error_log /persist/sensors/gyro_sensitity_cal &&
|
||||
echo "restart" > /sys/kernel/debug/msm_subsys/slpi &&
|
||||
sleep 5 # Give Android sensor subsystem a moment to recover
|
||||
fi
|
||||
|
||||
# handle pythonpath
|
||||
ln -sfn $(pwd) /data/pythonpath
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
path_classifiers:
|
||||
library:
|
||||
- external
|
||||
- phonelibs
|
||||
- pyextra
|
||||
- tools/lib/mkvparse
|
||||
extraction:
|
||||
cpp:
|
||||
after_prepare:
|
||||
- "pip3 install jinja2 pyyaml cython pycapnp numpy sympy tqdm cffi logentries zmq"
|
||||
- "export PATH=$PWD/external/bin:$PATH"
|
||||
index:
|
||||
build_command: "python3 $(which scons)"
|
||||
|
||||
Vendored
-24
@@ -1,24 +0,0 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-16.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: |
|
||||
set -e
|
||||
docker build -t opendbc .
|
||||
name: "Build"
|
||||
- run: |
|
||||
docker run opendbc bash -c "python -m unittest discover opendbc"
|
||||
name: "Unit tests"
|
||||
- run: |
|
||||
docker run opendbc bash -c "cd opendbc/can/tests/linter_python; PYTHONPATH=/ ./flake8_opendbc.sh"
|
||||
docker run opendbc bash -c "cd opendbc/can/tests/linter_python; PYTHONPATH=/ ./pylint_opendbc.sh"
|
||||
name: "Python linter"
|
||||
- run: |
|
||||
docker run opendbc bash -c "cd opendbc/can/tests/; PYTHONPATH=/ ./test_generator.sh"
|
||||
name: "Generator test"
|
||||
@@ -1,13 +1,17 @@
|
||||
.mypy_cache/
|
||||
*.pyc
|
||||
*.os
|
||||
*.tmp
|
||||
*.dylib
|
||||
.*.swp
|
||||
.DS_Store
|
||||
.sconsign.dblite
|
||||
|
||||
can/*.so
|
||||
can/build/
|
||||
can/obj/
|
||||
can/packer_pyx.cpp
|
||||
can/parser_pyx.cpp
|
||||
can/packer_pyx.html
|
||||
can/parser_pyx.html
|
||||
can/packer_impl.cpp
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
from ubuntu:16.04
|
||||
|
||||
RUN apt-get update && apt-get install -y libzmq3-dev clang wget git autoconf libtool curl make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl
|
||||
|
||||
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.7.3
|
||||
RUN pyenv global 3.7.3
|
||||
RUN pyenv rehash
|
||||
|
||||
COPY requirements.txt /tmp/
|
||||
RUN pip install -r /tmp/requirements.txt
|
||||
|
||||
ENV PYTHONPATH=/project
|
||||
|
||||
# TODO: Add tag to cereal
|
||||
RUN git clone https://github.com/commaai/cereal.git /project/cereal
|
||||
RUN /project/cereal/install_capnp.sh
|
||||
|
||||
WORKDIR /project
|
||||
|
||||
COPY SConstruct .
|
||||
COPY . /project/opendbc
|
||||
|
||||
RUN scons -c && scons -j$(nproc)
|
||||
-1080
File diff suppressed because it is too large
Load Diff
@@ -1,56 +0,0 @@
|
||||
opendbc
|
||||
======
|
||||
|
||||
The project to democratize access to the decoder ring of your car.
|
||||
|
||||
|
||||
|
||||
### DBC file basics
|
||||
|
||||
A DBC file encodes, in a humanly readable way, the information needed to understand a vehicle's CAN bus traffic. A vehicle might have multiple CAN buses and every CAN bus is represented by its own dbc file.
|
||||
Wondering what's the DBC file format? [Here](http://www.socialledge.com/sjsu/index.php?title=DBC_Format) and [Here](https://github.com/stefanhoelzl/CANpy/blob/master/docs/DBC_Specification.md) a couple of good overviews.
|
||||
|
||||
### How to start reverse engineering cars
|
||||
|
||||
[opendbc](https://github.com/commaai/opendbc) is integrated with [cabana](https://community.comma.ai/cabana/).
|
||||
|
||||
Use [panda](https://github.com/commaai/panda) to connect your car to a computer.
|
||||
|
||||
### How to use reverse engineered DBC
|
||||
To create custom CAN simulations or send reverse engineered signals back to the car you can use [CANdevStudio](https://github.com/GENIVI/CANdevStudio) project.
|
||||
|
||||
### DBC file preprocessor
|
||||
|
||||
DBC files for different models of the same brand have a lot of overlap. Therefore, we wrote a preprocessor to create DBC files from a brand DBC file and a model specific DBC file. The source DBC files can be found in the generator folder. After changing one of the files run the generator.py script to regenerate the output files. These output files will be placed in the root of the opendbc repository and are suffixed by _generated.
|
||||
|
||||
### Good practices for contributing to opendbc
|
||||
|
||||
- Comments: the best way to store comments is to add them directly to the DBC files. For example:
|
||||
```
|
||||
CM_ SG_ 490 LONG_ACCEL "wheel speed derivative, noisy and zero snapping";
|
||||
```
|
||||
is a comment that refers to signal `LONG_ACCEL` in message `490`. Using comments is highly recommended, especially for doubts and uncertainties. [cabana](https://community.comma.ai/cabana/) can easily display/add/edit comments to signals and messages.
|
||||
|
||||
- Units: when applicable, it's recommended to convert signals into physical units, by using a proper signal factor. Using a SI unit is preferred, unless a non-SI unit rounds the signal factor much better.
|
||||
For example:
|
||||
```
|
||||
SG_ VEHICLE_SPEED : 7|15@0+ (0.00278,0) [0|70] "m/s" PCM
|
||||
```
|
||||
is better than:
|
||||
```
|
||||
SG_ VEHICLE_SPEED : 7|15@0+ (0.00620,0) [0|115] "mph" PCM
|
||||
```
|
||||
However, the cleanest option is really:
|
||||
```
|
||||
SG_ VEHICLE_SPEED : 7|15@0+ (0.01,0) [0|250] "kph" PCM
|
||||
```
|
||||
|
||||
- Signal size: always use the smallest amount of bits possible. For example, let's say I'm reverse engineering the gas pedal position and I've determined that it's in a 3 bytes message. For 0% pedal position I read a message value of `0x00 0x00 0x00`, while for 100% of pedal position I read `0x64 0x00 0x00`: clearly, the gas pedal position is within the first byte of the message and I might be tempted to define the signal `GAS_POS` as:
|
||||
```
|
||||
SG_ GAS_POS : 7|8@0+ (1,0) [0|100] "%" PCM
|
||||
```
|
||||
However, I can't be sure that the very first bit of the message is referred to the pedal position: I haven't seen it changing! Therefore, a safer way of defining the signal is:
|
||||
```
|
||||
SG_ GAS_POS : 6|7@0+ (1,0) [0|100] "%" PCM
|
||||
```
|
||||
which leaves the first bit unallocated. This prevents from very erroneous reading of the gas pedal position, in case the first bit is indeed used for something else.
|
||||
@@ -1,57 +0,0 @@
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
zmq = 'zmq'
|
||||
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
|
||||
|
||||
cereal_dir = Dir('.')
|
||||
|
||||
cpppath = [
|
||||
'#',
|
||||
'#cereal',
|
||||
"#cereal/messaging",
|
||||
"#opendbc/can",
|
||||
'/usr/lib/include',
|
||||
]
|
||||
|
||||
AddOption('--test',
|
||||
action='store_true',
|
||||
help='build test files')
|
||||
|
||||
AddOption('--asan',
|
||||
action='store_true',
|
||||
help='turn on ASAN')
|
||||
|
||||
ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] if GetOption('asan') else []
|
||||
ldflags_asan = ["-fsanitize=address"] if GetOption('asan') else []
|
||||
|
||||
env = Environment(
|
||||
ENV=os.environ,
|
||||
CC='clang',
|
||||
CXX='clang++',
|
||||
CCFLAGS=[
|
||||
"-g",
|
||||
"-fPIC",
|
||||
"-O2",
|
||||
"-Werror=implicit-function-declaration",
|
||||
"-Werror=incompatible-pointer-types",
|
||||
"-Werror=int-conversion",
|
||||
"-Werror=return-type",
|
||||
"-Werror=format-extra-args",
|
||||
] + ccflags_asan,
|
||||
LDFLAGS=ldflags_asan,
|
||||
LINKFLAGS=ldflags_asan,
|
||||
|
||||
CFLAGS="-std=gnu11",
|
||||
CXXFLAGS="-std=c++14",
|
||||
CPPPATH=cpppath,
|
||||
)
|
||||
|
||||
Export('env', 'zmq', 'arch')
|
||||
|
||||
cereal = [File('#cereal/libcereal.a')]
|
||||
messaging = [File('#cereal/libmessaging.a')]
|
||||
Export('cereal', 'messaging')
|
||||
|
||||
SConscript(['cereal/SConscript'])
|
||||
SConscript(['opendbc/can/SConscript'])
|
||||
@@ -1,291 +0,0 @@
|
||||
VERSION ""
|
||||
|
||||
|
||||
NS_ :
|
||||
NS_DESC_
|
||||
CM_
|
||||
BA_DEF_
|
||||
BA_
|
||||
VAL_
|
||||
CAT_DEF_
|
||||
CAT_
|
||||
FILTER
|
||||
BA_DEF_DEF_
|
||||
EV_DATA_
|
||||
ENVVAR_DATA_
|
||||
SGTYPE_
|
||||
SGTYPE_VAL_
|
||||
BA_DEF_SGTYPE_
|
||||
BA_SGTYPE_
|
||||
SIG_TYPE_REF_
|
||||
VAL_TABLE_
|
||||
SIG_GROUP_
|
||||
SIG_VALTYPE_
|
||||
SIGTYPE_VALTYPE_
|
||||
BO_TX_BU_
|
||||
BA_DEF_REL_
|
||||
BA_REL_
|
||||
BA_DEF_DEF_REL_
|
||||
BU_SG_REL_
|
||||
BU_EV_REL_
|
||||
BU_BO_REL_
|
||||
SG_MUL_VAL_
|
||||
|
||||
BS_:
|
||||
|
||||
BU_: XXX EON Vector__XXX
|
||||
|
||||
|
||||
BO_ 170 AccPedal: 8 XXX
|
||||
SG_ KickDownPressed : 53|1@0+ (1,0) [0|3] "" XXX
|
||||
SG_ CruisePedalActive : 54|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CruisePedalInactive : 55|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ ThrottlelPressed : 50|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ AcceleratorPedalPressed : 52|1@0+ (1,0) [0|7] "" XXX
|
||||
SG_ AcceleratorPedalPercentage : 16|16@1+ (0.01,0) [0|100] "" XXX
|
||||
SG_ Counter1 : 8|4@1+ (1,0) [0|15] "" XXX
|
||||
SG_ EngineSpeed : 32|16@1- (1,0) [0|65535] "" XXX
|
||||
SG_ uknown : 7|8@0- (1,0) [0|65535] "" XXX
|
||||
|
||||
BO_ 404 CruiseControl: 4 XXX
|
||||
SG_ plus1mph_request : 16|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ minus1mph_request : 18|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Cancel_request_up_stalk : 23|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Cancel_request_up_or_down_stalk : 20|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Resume_request : 22|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Counter1 : 3|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ Counter2 : 11|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ notCancel_0xF : 7|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ setMe_0xFC : 31|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ requests_0xF : 15|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ plus5mph_request : 17|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ minus5mph_request : 19|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
|
||||
BO_ 512 CruiseControlStatus: 8 XXX
|
||||
SG_ CruiseControlInactiveFlag : 12|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CruiseCoontrolActiveFlag : 13|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CruiseControlSetpointSpeed : 7|8@0+ (0.25,0) [0|255] "mph" XXX
|
||||
|
||||
BO_ 168 EngineAndBrake: 8 XXX
|
||||
SG_ Brake_active2 : 62|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ BrakePressed : 61|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ EngineTorque : 8|16@1- (1,0) [0|65535] "" XXX
|
||||
SG_ EngineTorqueWoInterv : 24|16@1- (1,0) [0|65535] "" XXX
|
||||
|
||||
BO_ 470 SteeringButtons: 2 XXX
|
||||
SG_ Volume_DOWN : 2|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Volume_UP : 3|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ VoiceControl : 8|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Telephone : 0|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Next_up : 5|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ Previous_down : 4|1@0+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 403 DynamicCruiseControlStatus: 8 XXX
|
||||
SG_ Counter : 7|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ CruiseActive : 43|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CruiseSpeedChangeRequest : 48|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ CruiseControlSetpointSpeed : 15|8@0+ (1,-2) [0|255] "mph" XXX
|
||||
|
||||
BO_ 201 SteeringWheelAngle_DSC: 8 XXX
|
||||
SG_ Counter1 : 23|4@0+ (1,0) [0|15] "" XXX
|
||||
SG_ WeirdCounter : 44|4@1+ (1,0) [0|3] "" XXX
|
||||
SG_ SteeringPositionComplementLow : 24|11@1- (1,0) [0|1] "" XXX
|
||||
SG_ SteeringPosition : 0|16@1- (0.0439453125,0) [-600|600] "deg" XXX
|
||||
|
||||
BO_ 206 WheelSpeeds: 8 XXX
|
||||
SG_ Wheel1 : 0|16@1- (0.0643699,0) [0|255] "kph" XXX
|
||||
SG_ Wheel2 : 16|16@1- (0.0643699,0) [0|255] "kph" XXX
|
||||
SG_ Wheel4 : 48|16@1- (0.0643699,0) [0|255] "kph" XXX
|
||||
SG_ Wheel3 : 32|16@1- (0.0643699,0) [0|255] "kph" XXX
|
||||
|
||||
BO_ 884 WheelToleranceAdjustment: 8 XXX
|
||||
|
||||
BO_ 678 WiperSwitch: 8 XXX
|
||||
SG_ AutoWipersOn : 0|1@1+ (1,0) [0|3] "" XXX
|
||||
|
||||
BO_ 304 TerminalStatus: 8 XXX
|
||||
SG_ AccOn : 23|1@0+ (1,0) [0|255] "" XXX
|
||||
SG_ IgnitionOff : 22|1@0+ (1,0) [0|3] "" XXX
|
||||
|
||||
BO_ 169 Torque2: 8 XXX
|
||||
|
||||
BO_ 184 TorqueTransmisionRequest: 8 XXX
|
||||
|
||||
BO_ 196 SteeringWheelAngle: 7 XXX
|
||||
SG_ SteeringPosition : 0|16@1- (0.0439453125,0) [-600|600] "degree" XXX
|
||||
SG_ SteeringSpeed : 24|16@1- (0.0439453125,0) [0|255] "degree/s" XXX
|
||||
|
||||
BO_ 180 WheelTorqueDriveTrain1: 8 XXX
|
||||
|
||||
BO_ 182 DynamicCruiseControlTorqueDemand: 8 XXX
|
||||
|
||||
BO_ 186 TransmissionData: 8 XXX
|
||||
|
||||
BO_ 191 RequestedWheelTorqueDriveTrainActiveCruiseControl: 8 XXX
|
||||
SG_ Counter : 11|4@0- (1,0) [0|255] "" XXX
|
||||
SG_ TorqueReq : 16|11@1+ (1,0) [0|65535] "" XXX
|
||||
|
||||
BO_ 414 Status_DSC: 8 XXX
|
||||
|
||||
BO_ 416 Speed: 8 XXX
|
||||
SG_ VehicleSpeed : 0|12@1+ (0.103,0) [0|255] "kph" XXX
|
||||
|
||||
BO_ 418 TransimissionData2: 8 XXX
|
||||
|
||||
BO_ 690 WheelPressure: 8 XXX
|
||||
|
||||
BO_ 691 AccelerationData: 8 XXX
|
||||
|
||||
BO_ 408 GearSelectorSwitch: 8 XXX
|
||||
SG_ Gear : 0|8@1+ (1,0) [0|0] "" Vector__XXX
|
||||
|
||||
BO_ 422 Distance: 8 XXX
|
||||
|
||||
BO_ 436 InstrumentClusterStatus_KOMBI: 8 XXX
|
||||
|
||||
BO_ 464 EngineData: 8 XXX
|
||||
|
||||
BO_ 945 TransmissionData3: 8 XXX
|
||||
|
||||
BO_ 200 SteeringWheelAngle_slow: 8 XXX
|
||||
SG_ SteeringPosition : 0|16@1- (0.0439453125,0) [-600|600] "degree" XXX
|
||||
SG_ SteeringSpeed : 24|16@1- (0.0439453125,0) [-65535|65535] "degree/s" XXX
|
||||
|
||||
BO_ 466 TransmissionDataDisplay: 8 XXX
|
||||
|
||||
BO_ 437 HeatFlow_LoadMomentClimate: 8 XXX
|
||||
|
||||
BO_ 1152 NetworkManagment1: 8 XXX
|
||||
|
||||
BO_ 1170 NetworkManagment2: 8 XXX
|
||||
|
||||
BO_ 1175 NetworkManagment3: 8 XXX
|
||||
|
||||
BO_ 1176 NetworkManagment4: 8 XXX
|
||||
|
||||
BO_ 1193 NetworkManagment5: 8 XXX
|
||||
|
||||
BO_ 1246 NetworkManagment6: 8 XXX
|
||||
|
||||
BO_ 438 HeatFlowEngine: 8 XXX
|
||||
|
||||
BO_ 784 AmbientTemperature: 8 XXX
|
||||
|
||||
BO_ 821 ElectricFuelPumpStatus: 8 XXX
|
||||
|
||||
BO_ 1007 EngineOBD_data: 8 XXX
|
||||
|
||||
BO_ 1432 ServicesDKG: 8 XXX
|
||||
|
||||
BO_ 309 CrashDisconnectControl: 8 XXX
|
||||
|
||||
BO_ 502 TurnSignals: 2 XXX
|
||||
SG_ TurnSignalIdle : 9|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ TurnSignalActive : 8|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ RightTurn : 5|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ LeftTurn : 4|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ HoldActivated : 0|1@1+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 514 Dimming: 8 XXX
|
||||
|
||||
BO_ 538 LampsCondition: 8 XXX
|
||||
|
||||
BO_ 550 RainSensorWiperSpeed: 8 XXX
|
||||
|
||||
BO_ 578 ClimateFrontStatus: 8 XXX
|
||||
|
||||
BO_ 704 LCD_lighting: 8 XXX
|
||||
|
||||
BO_ 758 LightControl: 8 XXX
|
||||
|
||||
BO_ 760 Time_Date: 8 XXX
|
||||
|
||||
BO_ 762 SeatBeltContact: 8 XXX
|
||||
|
||||
BO_ 764 TrunkStatus: 8 XXX
|
||||
|
||||
BO_ 797 TirePressureStatus: 8 XXX
|
||||
|
||||
BO_ 816 Range_Mileage: 8 XXX
|
||||
|
||||
BO_ 823 StatusFuelControl: 8 XXX
|
||||
|
||||
BO_ 897 EngineOilLevelStatus: 8 XXX
|
||||
|
||||
BO_ 940 Terminal30Eerror: 8 XXX
|
||||
|
||||
BO_ 947 PowerManagmentConsumptionControl: 8 XXX
|
||||
|
||||
BO_ 948 PowerBatteryVoltage: 8 XXX
|
||||
SG_ BatteryVoltage : 7|24@0+ (0.001,0) [0|65535] "" XXX
|
||||
|
||||
BO_ 958 PowerRunningTime: 8 XXX
|
||||
|
||||
BO_ 1408 ServicesKGM: 8 XXX
|
||||
|
||||
BO_ 1426 ServicesDME: 8 XXX
|
||||
|
||||
BO_ 1449 ServicesDSC: 8 XXX
|
||||
|
||||
BO_ 1504 ServicesKOMBI: 8 XXX
|
||||
|
||||
BO_ 1522 ServicesKBM: 8 XXX
|
||||
|
||||
BO_ 209 Accelerometer: 8 XXX
|
||||
SG_ LateralAcceleration : 0|16@1- (1,0) [0|7] "" XXX
|
||||
SG_ LongitudalAcceleration : 32|16@1- (1,0) [0|65535] "" XXX
|
||||
|
||||
BO_ 172 WheelTorqueDrivetrain2: 8 XXX
|
||||
|
||||
BO_ 128 Unknown80: 5 XXX
|
||||
SG_ State2 : 24|4@1+ (1,0) [0|15] "" XXX
|
||||
SG_ State1 : 23|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ Counter1 : 31|4@0+ (1,0) [0|15] "" XXX
|
||||
|
||||
BO_ 320 Unknown140: 2 XXX
|
||||
SG_ State : 7|8@0+ (1,0) [0|255] "" XXX
|
||||
|
||||
BO_ 212 Unknown_d4: 8 XXX
|
||||
SG_ State1 : 47|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ Counter1 : 55|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ Counter2 : 63|8@0+ (1,0) [0|255] "" XXX
|
||||
|
||||
BO_ 205 Unknown_cd: 8 XXX
|
||||
SG_ NEW_SIGNAL_2 : 15|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_3 : 23|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_4 : 31|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_5 : 39|8@0- (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_6 : 47|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ Counter1 : 55|4@0+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_1 : 7|8@0+ (1,0) [0|255] "" XXX
|
||||
SG_ NEW_SIGNAL_7 : 63|8@0- (1,0) [0|255] "" XXX
|
||||
|
||||
BO_ 1577 NEW_MSG_1: 8 XXX
|
||||
|
||||
|
||||
|
||||
|
||||
CM_ SG_ 170 ThrottlelPressed "Active when accelerator pedal pressed or cruise control drives";
|
||||
CM_ SG_ 170 AcceleratorPedalPressed "Active only when driver actually presses the pedal";
|
||||
CM_ SG_ 170 AcceleratorPedalPercentage "ToDo Factor to be adjusted";
|
||||
CM_ SG_ 170 EngineSpeed "It's hard to say that is even a rate";
|
||||
CM_ SG_ 404 plus1mph_request "Appears when +1mph/kph stalk is depressed";
|
||||
CM_ SG_ 404 minus1mph_request "Appears when -1mph/kph stalk is depressed";
|
||||
CM_ SG_ 404 Cancel_request_up_stalk "Appears when cancel stalk (up) is depressed";
|
||||
CM_ SG_ 404 Cancel_request_up_or_down_stalk "Appears when cancel stalk (up or down) is depressed";
|
||||
CM_ SG_ 404 Resume_request "It appears when resume stalk button is depressed";
|
||||
CM_ SG_ 404 Counter1 "It accelerates when requests are being sent";
|
||||
CM_ SG_ 404 Counter2 "It accelerates when requests are being sent";
|
||||
CM_ SG_ 404 notCancel_0xF "0xF unless cancel is requested then 0x0";
|
||||
CM_ SG_ 168 Brake_active2 "";
|
||||
CM_ SG_ 168 BrakePressed "Brake when driver presses the brake";
|
||||
CM_ SG_ 168 EngineTorque "Engine torque without inertia - combustion torque";
|
||||
CM_ SG_ 168 EngineTorqueWoInterv "Engine torque without inertia and without shift intervention";
|
||||
CM_ SG_ 403 CruiseControlSetpointSpeed "Speed target";
|
||||
CM_ SG_ 408 Gear "This is just provision, needs to be reverse engineered";
|
||||
CM_ SG_ 502 TurnSignalIdle "Turn signal off";
|
||||
CM_ SG_ 502 TurnSignalActive "Turn signal on or transitioning";
|
||||
CM_ SG_ 502 RightTurn "Indicates right blinker or when steering returning right clears left blinker";
|
||||
CM_ SG_ 502 LeftTurn "Indicates left blinker or when steering returning left clears right blinker";
|
||||
CM_ SG_ 502 HoldActivated "Spikes down if blinker cleared with timeout or turn. Stays off if blinker cleared with stalk";
|
||||
VAL_ 408 Gear 1 "D" 2 "S" 3 "N" 4 "R" 5 "P" ;
|
||||
@@ -1,95 +0,0 @@
|
||||
VERSION ""
|
||||
|
||||
|
||||
NS_ :
|
||||
NS_DESC_
|
||||
CM_
|
||||
BA_DEF_
|
||||
BA_
|
||||
VAL_
|
||||
CAT_DEF_
|
||||
CAT_
|
||||
FILTER
|
||||
BA_DEF_DEF_
|
||||
EV_DATA_
|
||||
ENVVAR_DATA_
|
||||
SGTYPE_
|
||||
SGTYPE_VAL_
|
||||
BA_DEF_SGTYPE_
|
||||
BA_SGTYPE_
|
||||
SIG_TYPE_REF_
|
||||
VAL_TABLE_
|
||||
SIG_GROUP_
|
||||
SIG_VALTYPE_
|
||||
SIGTYPE_VALTYPE_
|
||||
BO_TX_BU_
|
||||
BA_DEF_REL_
|
||||
BA_REL_
|
||||
BA_DEF_DEF_REL_
|
||||
BU_SG_REL_
|
||||
BU_EV_REL_
|
||||
BU_BO_REL_
|
||||
SG_MUL_VAL_
|
||||
|
||||
BS_:
|
||||
|
||||
BU_: K182_PACM K43_PSCM K17_EBCM NEO K124_ASCM
|
||||
|
||||
|
||||
|
||||
BO_ 823 PACMParkAssitCmd: 7 NEO
|
||||
SG_ RollingCounter : 35|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ SteeringWheelChecksum : 47|16@0+ (1,0) [0|0] "" NEO
|
||||
SG_ SteeringWheelCmd : 23|16@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 560 EBCMRegen: 6 K17_EBCM
|
||||
SG_ Regen : 1|10@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 338 ASCMLKASteeringCmd: 6 NEO
|
||||
SG_ LKASteeringCmdActive : 7|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASteeringCmd : 5|14@0- (1,0) [0|0] "" NEO
|
||||
SG_ RollingCounter : 23|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ SetMe1 : 21|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASVehicleSpeed : 20|13@0+ (0.22,0) [0|0] "kph" NEO
|
||||
SG_ LKASMode : 36|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASteeringCmdChecksum : 33|10@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 340 ASCMBLKASteeringCmd: 6 NEO
|
||||
SG_ LKASteeringCmdActive : 7|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASteeringCmd : 5|14@0- (1,0) [0|0] "" NEO
|
||||
SG_ RollingCounter : 23|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ SetMe1 : 21|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASVehicleSpeed : 20|13@0+ (0.22,0) [0|0] "kph" NEO
|
||||
SG_ LKASteeringCmdActive2 : 35|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASteeringCmdChecksum : 33|10@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 368 EBCMFrictionBrakeStatus: 8 K17_EBCM
|
||||
SG_ FrictionBrakePressure : 23|16@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 789 EBCMFrictionBrakeCmd: 5 K17_EBCM
|
||||
SG_ RollingCounter : 37|6@0+ (1,0) [0|0] "" NEO
|
||||
SG_ FrictionBrakeMode : 7|4@0+ (1,0) [0|0] "" NEO
|
||||
SG_ FrictionBrakeChecksum : 23|16@0+ (1,0) [0|0] "" NEO
|
||||
SG_ FrictionBrakeCmd : 3|12@0- (1,0) [0|0] "" NEO
|
||||
|
||||
BO_TX_BU_ 823 : K43_PSCM,NEO;
|
||||
BO_TX_BU_ 789 : NEO,K17_EBCM;
|
||||
|
||||
|
||||
CM_ BU_ K182_PACM "Parking Assist Control Module";
|
||||
CM_ BU_ K43_PSCM "Power Steering Control Module";
|
||||
CM_ BU_ K17_EBCM "Electronic Brake Control Module";
|
||||
CM_ BU_ NEO "Comma NEO";
|
||||
CM_ BU_ K124_ASCM "Active Safety Control Module";
|
||||
BA_DEF_ "UseGMParameterIDs" INT 0 0;
|
||||
BA_DEF_ "ProtocolType" STRING ;
|
||||
BA_DEF_ "BusType" STRING ;
|
||||
BA_DEF_DEF_ "UseGMParameterIDs" 1;
|
||||
BA_DEF_DEF_ "ProtocolType" "GMLAN";
|
||||
BA_DEF_DEF_ "BusType" "";
|
||||
BA_ "UseGMParameterIDs" 0;
|
||||
BA_ "BusType" "CAN";
|
||||
BA_ "ProtocolType" "GMLAN";
|
||||
|
||||
VAL_ 338 LKASteeringCmdActive 1 "Active" 0 "Inactive" ;
|
||||
VAL_ 338 LKASMode 2 "supercruise" 1 "lkas" 0 "Inactive" ;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,243 +0,0 @@
|
||||
VERSION ""
|
||||
|
||||
|
||||
NS_ :
|
||||
NS_DESC_
|
||||
CM_
|
||||
BA_DEF_
|
||||
BA_
|
||||
VAL_
|
||||
CAT_DEF_
|
||||
CAT_
|
||||
FILTER
|
||||
BA_DEF_DEF_
|
||||
EV_DATA_
|
||||
ENVVAR_DATA_
|
||||
SGTYPE_
|
||||
SGTYPE_VAL_
|
||||
BA_DEF_SGTYPE_
|
||||
BA_SGTYPE_
|
||||
SIG_TYPE_REF_
|
||||
VAL_TABLE_
|
||||
SIG_GROUP_
|
||||
SIG_VALTYPE_
|
||||
SIGTYPE_VALTYPE_
|
||||
BO_TX_BU_
|
||||
BA_DEF_REL_
|
||||
BA_REL_
|
||||
BA_DEF_DEF_REL_
|
||||
BU_SG_REL_
|
||||
BU_EV_REL_
|
||||
BU_BO_REL_
|
||||
SG_MUL_VAL_
|
||||
|
||||
BS_:
|
||||
|
||||
BU_: K16_BECM K73_TCIC K9_BCM K43_PSCM K17_EBCM K20_ECM K114B_HPCM NEO K124_ASCM
|
||||
VAL_TABLE_ TurnSignals 2 "Right Turn" 1 "Left Turn" 0 "None" ;
|
||||
VAL_TABLE_ ACCLeadCar 1 "Present" 0 "Not Present" ;
|
||||
VAL_TABLE_ ACCCmdActive 1 "Active" 0 "Inactive" ;
|
||||
VAL_TABLE_ BrakePedalPressed 1 "Pressed" 0 "Depressed" ;
|
||||
VAL_TABLE_ DistanceButton 1 "Active" 0 "Inactive" ;
|
||||
VAL_TABLE_ LKAButton 1 "Active" 0 "Inactive" ;
|
||||
VAL_TABLE_ ACCButtons 6 "Cancel" 5 "Main" 3 "Set" 2 "Resume" 1 "None" ;
|
||||
VAL_TABLE_ PRNDL 3 "Reverse" 2 "Drive" 1 "Neutral" 0 "Park" ;
|
||||
VAL_TABLE_ DoorStatus 1 "Opened" 0 "Closed" ;
|
||||
VAL_TABLE_ SeatBeltStatus 1 "Latched" 0 "Unlatched" ;
|
||||
VAL_TABLE_ LKASteeringCmdActive 1 "Active" 0 "Inactive" ;
|
||||
VAL_TABLE_ ACCGapLevel 3 "Far" 2 "Med" 1 "Near" 0 "Inactive" ;
|
||||
VAL_TABLE_ GasRegenCmdActiveInv 1 "Inactive" 0 "Active" ;
|
||||
VAL_TABLE_ GasRegenCmdActive 1 "Active" 0 "Inactive" ;
|
||||
VAL_TABLE_ LKATorqueDeliveredStatus 3 "Failed" 2 "Temp. Limited" 1 "Active" 0 "Inactive" ;
|
||||
VAL_TABLE_ HandsOffSWDetectionStatus 1 "Hands On" 0 "Hands Off" ;
|
||||
VAL_TABLE_ HandsOffSWDetectionMode 2 "Failed" 1 "Enabled" 0 "Disabled" ;
|
||||
|
||||
|
||||
BO_ 717 ASCM_2CD: 5 K124_ASCM
|
||||
|
||||
BO_ 869 ASCM_365: 4 K124_ASCM
|
||||
|
||||
BO_ 1034 ASCM_40A: 7 K124_ASCM
|
||||
|
||||
BO_ 1296 ASCM_510: 4 K124_ASCM
|
||||
|
||||
BO_ 1930 ASCM_78A: 7 K124_ASCM
|
||||
|
||||
BO_ 190 ECMAcceleratorPos: 6 K20_ECM
|
||||
SG_ BrakePedalPos : 15|8@0+ (1,0) [0|0] "sticky" NEO
|
||||
SG_ GasPedalAndAcc : 23|8@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 201 ECMEngineStatus: 8 K20_ECM
|
||||
SG_ EngineTPS : 39|8@0+ (0.392156863,0) [0|100.000000065] "%" NEO
|
||||
SG_ EngineRPM : 15|16@0+ (0.25,0) [0|0] "RPM" NEO
|
||||
|
||||
BO_ 209 EBCMBrakePedalTorque: 7 K17_EBCM
|
||||
SG_ BrakePedalTorque : 3|12@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 241 EBCMBrakePedalPosition: 6 K17_EBCM
|
||||
SG_ BrakePedalPosition : 15|8@0+ (1,0) [0|255] "" NEO
|
||||
|
||||
BO_ 298 BCMDoorBeltStatus: 8 K9_BCM
|
||||
SG_ RearLeftDoor : 8|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ FrontLeftDoor : 9|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ FrontRightDoor : 10|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ RearRightDoor : 23|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LeftSeatBelt : 12|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ RightSeatBelt : 53|1@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 309 ECMPRDNL: 8 K20_ECM
|
||||
SG_ PRNDL : 2|3@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 320 BCMTurnSignals: 3 K9_BCM
|
||||
SG_ TurnSignals : 19|2@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 336 ASCMLKASStatus: 1 NEO
|
||||
SG_ Available : 7|1@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 338 ASCMLKASteeringCmd: 6 NEO
|
||||
SG_ LKASteeringCmdActive : 7|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASteeringCmd : 5|14@0- (1,0) [0|0] "" NEO
|
||||
SG_ RollingCounter : 23|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ SetMe1 : 21|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASVehicleSpeed : 20|13@0+ (0.22,0) [0|0] "kph" NEO
|
||||
SG_ LKASMode : 36|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASteeringCmdChecksum : 33|10@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 340 ASCMBLKASteeringCmd: 6 NEO
|
||||
SG_ LKASteeringCmdActive : 7|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASteeringCmd : 5|14@0- (1,0) [0|0] "" NEO
|
||||
SG_ RollingCounter : 23|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ SetMe1 : 21|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASVehicleSpeed : 20|13@0+ (0.22,0) [0|0] "kph" NEO
|
||||
SG_ LKASMode : 36|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKASteeringCmdChecksum : 33|10@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 381 MSG_17D: 8 K20_ECM
|
||||
SG_ MSG17D_AccPower : 35|12@0- (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 356 PSCMStatus: 8 K43_PSCM
|
||||
SG_ LKATorqueDeliveredStatus : 7|3@0+ (1,0) [0|7] "" NEO
|
||||
SG_ LKADriverAppldTrq : 2|11@0- (0.01,0) [-10.24|10.23] "Nm" NEO
|
||||
SG_ LKATBDTorque : 21|14@0- (-0.005,0) [-10.24|10.23] "Nm" NEO
|
||||
SG_ RollingCounter : 39|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKATotalTorqueDelivered : 37|14@0- (0.01,0) [-10.24|10.23] "Nm" NEO
|
||||
|
||||
BO_ 417 AcceleratorPedal: 7 XXX
|
||||
SG_ AcceleratorPedal : 55|8@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 451 GasAndAcc: 8 XXX
|
||||
SG_ GasPedalAndAcc2 : 55|8@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 452 AcceleratorPedal2: 8 XXX
|
||||
SG_ AcceleratorPedal2 : 47|8@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 481 ASCMSteeringButton: 7 K124_ASCM
|
||||
SG_ DistanceButton : 22|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 485 PSCMSteeringAngle: 8 K43_PSCM
|
||||
SG_ SteeringWheelAngle : 15|16@0- (0.0625,0) [-540|540] "deg" NEO
|
||||
SG_ SteeringWheelRate : 27|12@0- (0.5,0) [-100|100] "deg/s" NEO
|
||||
|
||||
BO_ 489 EBCMVehicleDynamic: 8 K17_EBCM
|
||||
SG_ YawRate : 51|12@0- (0.0625,0) [-2047|2047] "grad/s" NEO
|
||||
SG_ LateralAcceleration : 3|12@0- (0.0161,0) [-2047|2047] "m/s2" NEO
|
||||
SG_ BrakePedalPressed : 6|1@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 711 BECMBatteryVoltageCurrent: 6 K17_EBCM
|
||||
SG_ HVBatteryVoltage : 31|12@0+ (0.125,0) [0|511.875] "V" NEO
|
||||
SG_ HVBatteryCurrent : 12|13@0- (0.15,0) [-614.4|614.25] "A" NEO
|
||||
|
||||
BO_ 715 ASCMGasRegenCmd: 8 K124_ASCM
|
||||
SG_ GasRegenAlwaysOne : 9|1@0+ (1,1) [1|1] "" NEO
|
||||
SG_ GasRegenAlwaysThree : 15|2@0+ (1,1) [1|1] "" NEO
|
||||
SG_ GasRegenChecksum : 47|24@0+ (1,0) [0|0] "" NEO
|
||||
SG_ GasRegenCmdActiveInv : 32|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ GasRegenFullStopActive : 13|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ GasRegenCmdActive : 0|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ RollingCounter : 7|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ RollingCounter2 : 36|4@0+ (1,0) [0|0] "" NEO
|
||||
SG_ GasRegenAlwaysOne2 : 23|1@0+ (1,0) [0|1] "" NEO
|
||||
SG_ GasRegenCmd : 22|15@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 810 TCICOnStarGPSPosition: 8 K73_TCIC
|
||||
SG_ GPSLongitude : 39|32@0+ (1,0) [0|0] "milliarcsecond" NEO
|
||||
SG_ GPSLatitude : 7|32@0+ (1,0) [0|0] "milliarcsecond" NEO
|
||||
|
||||
BO_ 840 EBCMWheelSpdFront: 4 K17_EBCM
|
||||
SG_ FLWheelSpd : 7|16@0+ (0.0311,0) [0|255] "km/h" NEO
|
||||
SG_ FRWheelSpd : 23|16@0+ (0.0311,0) [0|255] "km/h" NEO
|
||||
|
||||
BO_ 842 EBCMWheelSpdRear: 4 K17_EBCM
|
||||
SG_ RLWheelSpd : 7|16@0+ (0.0311,0) [0|255] "km/h" NEO
|
||||
SG_ RRWheelSpd : 23|16@0+ (0.0311,0) [0|255] "km/h" NEO
|
||||
|
||||
BO_ 880 ASCMActiveCruiseControlStatus: 6 K124_ASCM
|
||||
SG_ ACCLeadCar : 44|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ ACCAlwaysOne2 : 32|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ ACCAlwaysOne : 0|1@0+ (1,0) [0|0] "" Vector__XXX
|
||||
SG_ ACCSpeedSetpoint : 19|12@0+ (1,0) [0|0] "km/h" NEO
|
||||
SG_ ACCGapLevel : 21|2@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCResumeButton : 1|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCCmdActive : 23|1@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 1001 ECMVehicleSpeed: 8 K20_ECM
|
||||
SG_ VehicleSpeed : 7|16@0+ (0.01,0) [0|0] "mph" NEO
|
||||
|
||||
BO_ 1033 ASCMKeepAlive: 7 NEO
|
||||
SG_ ASCMKeepAliveAllZero : 7|56@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 1217 ECMEngineCoolantTemp: 8 K20_ECM
|
||||
SG_ EngineCoolantTemp : 23|8@0+ (1,-40) [0|0] "C" NEO
|
||||
|
||||
BO_ 1249 VIN_Part2: 8 K20_ECM
|
||||
SG_ VINPart2 : 7|64@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 1300 VIN_Part1: 8 K20_ECM
|
||||
SG_ VINPart1 : 7|64@0+ (1,0) [0|0] "" NEO
|
||||
|
||||
BO_ 1912 PSCM_778: 8 K43_PSCM
|
||||
|
||||
BO_TX_BU_ 338 : K124_ASCM,NEO;
|
||||
BO_TX_BU_ 880 : NEO,K124_ASCM;
|
||||
BO_TX_BU_ 1033 : K124_ASCM,NEO;
|
||||
BO_TX_BU_ 715 : NEO,K124_ASCM;
|
||||
|
||||
|
||||
CM_ BU_ K16_BECM "Battery Energy Control Module";
|
||||
CM_ BU_ K73_TCIC "Telematics Communication Control Module";
|
||||
CM_ BU_ K9_BCM "Body Control Module";
|
||||
CM_ BU_ K43_PSCM "Power Steering Control Module";
|
||||
CM_ BU_ K17_EBCM "Electronic Brake Control Module";
|
||||
CM_ BU_ K20_ECM "Engine Control Module";
|
||||
CM_ BU_ K114B_HPCM "Hybrid Powertrain Control Module";
|
||||
CM_ BU_ NEO "Comma NEO";
|
||||
CM_ BU_ K124_ASCM "Active Safety Control Module";
|
||||
CM_ SG_ 381 MSG17D_AccPower "Need to investigate";
|
||||
CM_ SG_ 190 GasPedalAndAcc "ACC baseline is 62";
|
||||
CM_ SG_ 451 GasPedalAndAcc2 "ACC baseline is 62";
|
||||
CM_ SG_ 715 RollingCounter2 "Values cycle between 0, 7, 10, 13";
|
||||
BA_DEF_ "UseGMParameterIDs" INT 0 0;
|
||||
BA_DEF_ "ProtocolType" STRING ;
|
||||
BA_DEF_ "BusType" STRING ;
|
||||
BA_DEF_DEF_ "UseGMParameterIDs" 1;
|
||||
BA_DEF_DEF_ "ProtocolType" "GMLAN";
|
||||
BA_DEF_DEF_ "BusType" "";
|
||||
BA_ "BusType" "CAN";
|
||||
BA_ "ProtocolType" "GMLAN";
|
||||
BA_ "UseGMParameterIDs" 0;
|
||||
VAL_ 481 DistanceButton 1 "Active" 0 "Inactive" ;
|
||||
VAL_ 481 LKAButton 1 "Active" 0 "Inactive" ;
|
||||
VAL_ 481 ACCButtons 6 "Cancel" 5 "Main" 3 "Set" 2 "Resume" 1 "None" ;
|
||||
VAL_ 309 PRNDL 3 "Reverse" 2 "Drive" 1 "Neutral" 0 "Park" ;
|
||||
VAL_ 338 LKASteeringCmdActive 1 "Active" 0 "Inactive" ;
|
||||
VAL_ 338 LKASMode 2 "supercruise" 1 "lkas" 0 "Inactive" ;
|
||||
VAL_ 880 ACCLeadCar 1 "Present" 0 "Not Present" ;
|
||||
VAL_ 880 ACCGapLevel 3 "Far" 2 "Med" 1 "Near" 0 "Inactive" ;
|
||||
VAL_ 880 ACCResumeButton 1 "Pressed" 0 "Depressed" ;
|
||||
VAL_ 880 ACCCmdActive 1 "Active" 0 "Inactive" ;
|
||||
VAL_ 356 LKATorqueDeliveredStatus 7 "Override Fault" 6 "LKAS Fault but Responsive" 5 "TBD but Responsive" 4 "TBD but Responsive" 3 "Fault" 1 "Active" 0 "Inactive" ;
|
||||
VAL_ 489 BrakePedalPressed 1 "Pressed" 0 "Depressed" ;
|
||||
VAL_ 715 GasRegenCmdActiveInv 1 "Inactive" 0 "Active" ;
|
||||
VAL_ 715 GasRegenCmdActive 1 "Active" 0 "Inactive" ;
|
||||
@@ -16,12 +16,8 @@ for x in sorted(os.listdir('../')):
|
||||
|
||||
libdbc = env.SharedLibrary('libdbc', ["dbc.cc", "parser.cc", "packer.cc", "common.cc"]+dbcs, LIBS=["capnp", "kj"])
|
||||
|
||||
# packer
|
||||
env.Command(['packer_pyx.so'],
|
||||
[libdbc, 'packer_pyx.pyx', 'packer_pyx_setup.py'],
|
||||
"cd opendbc/can && python3 packer_pyx_setup.py build_ext --inplace")
|
||||
# Build packer and parser
|
||||
|
||||
# parser
|
||||
env.Command(['parser_pyx.so'],
|
||||
[libdbc, cereal, 'parser_pyx_setup.py', 'parser_pyx.pyx', 'common.pxd'],
|
||||
"cd opendbc/can && python3 parser_pyx_setup.py build_ext --inplace")
|
||||
env.Command(['packer_pyx.so', 'parser_pyx.so'],
|
||||
[libdbc, cereal, 'common_pyx_setup.py', 'packer_pyx.pyx', 'parser_pyx.pyx', 'common.pxd'],
|
||||
"cd opendbc/can && python3 common_pyx_setup.py build_ext --inplace")
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
from opendbc.can.parser_pyx import CANDefine # pylint: disable=no-name-in-module, import-error
|
||||
from opendbc.can.parser_pyx import CANDefine # pylint: disable=no-name-in-module, import-error
|
||||
assert CANDefine
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import os
|
||||
import sysconfig
|
||||
import subprocess
|
||||
import sysconfig
|
||||
import platform
|
||||
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
|
||||
|
||||
from Cython.Build import cythonize
|
||||
from Cython.Distutils import build_ext
|
||||
|
||||
|
||||
ANNOTATE = os.getenv('ANNOTATE') is not None
|
||||
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../"))
|
||||
|
||||
|
||||
@@ -32,10 +34,8 @@ class BuildExtWithoutPlatformSuffix(build_ext):
|
||||
return get_ext_filename_without_platform_suffix(filename)
|
||||
|
||||
|
||||
sourcefiles = ['packer_pyx.pyx']
|
||||
extra_compile_args = ["-std=c++11"]
|
||||
extra_compile_args = ["-std=c++14"]
|
||||
ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pylint: disable=unexpected-keyword-arg
|
||||
|
||||
if ARCH == "aarch64":
|
||||
extra_compile_args += ["-Wno-deprecated-register"]
|
||||
|
||||
@@ -44,26 +44,51 @@ if platform.system() == "Darwin":
|
||||
else:
|
||||
libdbc = "libdbc.so"
|
||||
|
||||
extra_link_args = [os.path.join(BASEDIR, 'opendbc', 'can', libdbc)]
|
||||
include_dirs = [
|
||||
BASEDIR,
|
||||
os.path.join(BASEDIR, 'phonelibs'),
|
||||
]
|
||||
|
||||
# Build CAN Parser
|
||||
|
||||
setup(name='CAN parser',
|
||||
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
|
||||
ext_modules=cythonize(
|
||||
Extension(
|
||||
"parser_pyx",
|
||||
language="c++",
|
||||
sources=['parser_pyx.pyx'],
|
||||
extra_compile_args=extra_compile_args,
|
||||
include_dirs=include_dirs,
|
||||
extra_link_args=extra_link_args,
|
||||
),
|
||||
annotate=ANNOTATE
|
||||
),
|
||||
nthreads=4,
|
||||
)
|
||||
|
||||
if platform.system() == "Darwin":
|
||||
os.system("install_name_tool -change opendbc/can/libdbc.dylib " + BASEDIR + "/opendbc/can/libdbc.dylib parser_pyx.so")
|
||||
|
||||
|
||||
# Build CAN Packer
|
||||
|
||||
setup(name='CAN packer',
|
||||
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
|
||||
ext_modules=cythonize(
|
||||
Extension(
|
||||
"packer_pyx",
|
||||
language="c++",
|
||||
sources=sourcefiles,
|
||||
sources=['packer_pyx.pyx'],
|
||||
extra_compile_args=extra_compile_args,
|
||||
include_dirs=[
|
||||
BASEDIR,
|
||||
os.path.join(BASEDIR, 'phonelibs', 'capnp-cpp/include'),
|
||||
],
|
||||
extra_link_args=[
|
||||
os.path.join(BASEDIR, 'opendbc', 'can', libdbc),
|
||||
],
|
||||
)
|
||||
include_dirs=include_dirs,
|
||||
extra_link_args=extra_link_args,
|
||||
),
|
||||
annotate=ANNOTATE
|
||||
),
|
||||
nthreads=4,
|
||||
)
|
||||
|
||||
if platform.system() == "Darwin":
|
||||
os.system("install_name_tool -change opendbc/can/libdbc.dylib "+BASEDIR+"/opendbc/can/libdbc.dylib packer_pyx.so")
|
||||
|
||||
os.system("install_name_tool -change opendbc/can/libdbc.dylib " + BASEDIR + "/opendbc/can/libdbc.dylib packer_pyx.so")
|
||||
+18
-17
@@ -12,6 +12,7 @@ def int_or_float(s):
|
||||
else:
|
||||
return float(s)
|
||||
|
||||
|
||||
DBCSignal = namedtuple(
|
||||
"DBCSignal", ["name", "start_bit", "size", "is_little_endian", "is_signed",
|
||||
"factor", "offset", "tmin", "tmax", "units"])
|
||||
@@ -41,7 +42,7 @@ class dbc():
|
||||
self.def_vals = defaultdict(list)
|
||||
|
||||
# lookup to bit reverse each byte
|
||||
self.bits_index = [(i & ~0b111) + ((-i-1) & 0b111) for i in range(64)]
|
||||
self.bits_index = [(i & ~0b111) + ((-i - 1) & 0b111) for i in range(64)]
|
||||
|
||||
for l in self.txt:
|
||||
l = l.strip()
|
||||
@@ -55,7 +56,7 @@ class dbc():
|
||||
|
||||
name = dat.group(2)
|
||||
size = int(dat.group(3))
|
||||
ids = int(dat.group(1), 0) # could be hex
|
||||
ids = int(dat.group(1), 0) # could be hex
|
||||
if ids in self.msgs:
|
||||
sys.exit("Duplicate address detected %d %s" % (ids, self.name))
|
||||
|
||||
@@ -73,15 +74,15 @@ class dbc():
|
||||
print("bad SG {0}".format(l))
|
||||
|
||||
sgname = dat.group(1)
|
||||
start_bit = int(dat.group(go+2))
|
||||
signal_size = int(dat.group(go+3))
|
||||
is_little_endian = int(dat.group(go+4))==1
|
||||
is_signed = dat.group(go+5)=='-'
|
||||
factor = int_or_float(dat.group(go+6))
|
||||
offset = int_or_float(dat.group(go+7))
|
||||
tmin = int_or_float(dat.group(go+8))
|
||||
tmax = int_or_float(dat.group(go+9))
|
||||
units = dat.group(go+10)
|
||||
start_bit = int(dat.group(go + 2))
|
||||
signal_size = int(dat.group(go + 3))
|
||||
is_little_endian = int(dat.group(go + 4)) == 1
|
||||
is_signed = dat.group(go + 5) == '-'
|
||||
factor = int_or_float(dat.group(go + 6))
|
||||
offset = int_or_float(dat.group(go + 7))
|
||||
tmin = int_or_float(dat.group(go + 8))
|
||||
tmax = int_or_float(dat.group(go + 9))
|
||||
units = dat.group(go + 10)
|
||||
|
||||
self.msgs[ids][1].append(
|
||||
DBCSignal(sgname, start_bit, signal_size, is_little_endian,
|
||||
@@ -94,16 +95,16 @@ class dbc():
|
||||
if dat is None:
|
||||
print("bad VAL {0}".format(l))
|
||||
|
||||
ids = int(dat.group(1), 0) # could be hex
|
||||
ids = int(dat.group(1), 0) # could be hex
|
||||
sgname = dat.group(2)
|
||||
defvals = dat.group(3)
|
||||
|
||||
defvals = defvals.replace("?",r"\?") #escape sequence in C++
|
||||
defvals = defvals.replace("?", r"\?") # escape sequence in C++
|
||||
defvals = defvals.split('"')[:-1]
|
||||
|
||||
# convert strings to UPPER_CASE_WITH_UNDERSCORES
|
||||
defvals[1::2] = [d.strip().upper().replace(" ","_") for d in defvals[1::2]]
|
||||
defvals = '"'+"".join(str(i) for i in defvals)+'"'
|
||||
defvals[1::2] = [d.strip().upper().replace(" ", "_") for d in defvals[1::2]]
|
||||
defvals = '"' + "".join(str(i) for i in defvals) + '"'
|
||||
|
||||
self.def_vals[ids].append((sgname, defvals))
|
||||
|
||||
@@ -193,12 +194,12 @@ class dbc():
|
||||
if arr is None:
|
||||
out = {}
|
||||
else:
|
||||
out = [None]*len(arr)
|
||||
out = [None] * len(arr)
|
||||
|
||||
msg = self.msgs.get(x[0])
|
||||
if msg is None:
|
||||
if x[0] not in self._warned_addresses:
|
||||
#print("WARNING: Unknown message address {}".format(x[0]))
|
||||
# print("WARNING: Unknown message address {}".format(x[0]))
|
||||
self._warned_addresses.add(x[0])
|
||||
return None, None
|
||||
|
||||
|
||||
@@ -171,7 +171,6 @@ CANParser::CANParser(int abus, const std::string& dbc_name,
|
||||
|
||||
void CANParser::UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Reader& cans) {
|
||||
int msg_count = cans.size();
|
||||
uint64_t p;
|
||||
|
||||
DEBUG("got %d messages\n", msg_count);
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
from opendbc.can.parser_pyx import CANParser # pylint: disable=no-name-in-module, import-error
|
||||
from opendbc.can.parser_pyx import CANParser # pylint: disable=no-name-in-module, import-error
|
||||
assert CANParser
|
||||
|
||||
@@ -49,7 +49,8 @@ cdef class CANParser:
|
||||
|
||||
self.can_invalid_cnt = CAN_INVALID_CNT
|
||||
|
||||
num_msgs = self.dbc[0].num_msgs
|
||||
cdef int i
|
||||
cdef int num_msgs = self.dbc[0].num_msgs
|
||||
for i in range(num_msgs):
|
||||
msg = self.dbc[0].msgs[i]
|
||||
name = msg.name.decode('utf8')
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sysconfig
|
||||
import platform
|
||||
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
|
||||
|
||||
from Cython.Build import cythonize
|
||||
from Cython.Distutils import build_ext
|
||||
|
||||
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../"))
|
||||
|
||||
|
||||
def get_ext_filename_without_platform_suffix(filename):
|
||||
name, ext = os.path.splitext(filename)
|
||||
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
|
||||
|
||||
if ext_suffix == ext:
|
||||
return filename
|
||||
|
||||
ext_suffix = ext_suffix.replace(ext, '')
|
||||
idx = name.find(ext_suffix)
|
||||
|
||||
if idx == -1:
|
||||
return filename
|
||||
else:
|
||||
return name[:idx] + ext
|
||||
|
||||
|
||||
class BuildExtWithoutPlatformSuffix(build_ext):
|
||||
def get_ext_filename(self, ext_name):
|
||||
filename = super().get_ext_filename(ext_name)
|
||||
return get_ext_filename_without_platform_suffix(filename)
|
||||
|
||||
|
||||
sourcefiles = ['parser_pyx.pyx']
|
||||
extra_compile_args = ["-std=c++11"]
|
||||
ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pylint: disable=unexpected-keyword-arg
|
||||
|
||||
if ARCH == "aarch64":
|
||||
extra_compile_args += ["-Wno-deprecated-register"]
|
||||
|
||||
if platform.system() == "Darwin":
|
||||
libdbc = "libdbc.dylib"
|
||||
else:
|
||||
libdbc = "libdbc.so"
|
||||
|
||||
setup(name='CAN parser',
|
||||
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
|
||||
ext_modules=cythonize(
|
||||
Extension(
|
||||
"parser_pyx",
|
||||
language="c++",
|
||||
sources=sourcefiles,
|
||||
extra_compile_args=extra_compile_args,
|
||||
include_dirs=[
|
||||
BASEDIR,
|
||||
os.path.join(BASEDIR, 'phonelibs', 'capnp-cpp/include'),
|
||||
],
|
||||
extra_link_args=[
|
||||
os.path.join(BASEDIR, 'opendbc', 'can', libdbc),
|
||||
],
|
||||
)
|
||||
),
|
||||
nthreads=4,
|
||||
)
|
||||
|
||||
if platform.system() == "Darwin":
|
||||
os.system("install_name_tool -change opendbc/can/libdbc.dylib "+BASEDIR+"/opendbc/can/libdbc.dylib parser_pyx.so")
|
||||
|
||||
@@ -10,7 +10,7 @@ from opendbc.can.dbc import dbc
|
||||
|
||||
def process(in_fn, out_fn):
|
||||
dbc_name = os.path.split(out_fn)[-1].replace('.cc', '')
|
||||
#print("processing %s: %s -> %s" % (dbc_name, in_fn, out_fn))
|
||||
# print("processing %s: %s -> %s" % (dbc_name, in_fn, out_fn))
|
||||
|
||||
template_fn = os.path.join(os.path.dirname(__file__), "dbc_template.cc")
|
||||
|
||||
@@ -19,10 +19,11 @@ def process(in_fn, out_fn):
|
||||
|
||||
can_dbc = dbc(in_fn)
|
||||
|
||||
msgs = [(address, msg_name, msg_size, sorted(msg_sigs, key=lambda s: s.name not in ("COUNTER", "CHECKSUM"))) # process counter and checksums first
|
||||
# process counter and checksums first
|
||||
msgs = [(address, msg_name, msg_size, sorted(msg_sigs, key=lambda s: s.name not in ("COUNTER", "CHECKSUM")))
|
||||
for address, ((msg_name, msg_size), msg_sigs) in sorted(can_dbc.msgs.items()) if msg_sigs]
|
||||
|
||||
def_vals = {a: sorted(set(b)) for a, b in can_dbc.def_vals.items()} # remove duplicates
|
||||
def_vals = {a: sorted(set(b)) for a, b in can_dbc.def_vals.items()} # remove duplicates
|
||||
def_vals = sorted(def_vals.items())
|
||||
|
||||
if can_dbc.name.startswith(("honda_", "acura_")):
|
||||
@@ -46,7 +47,7 @@ def process(in_fn, out_fn):
|
||||
checksum_start_bit = 0
|
||||
counter_start_bit = 0
|
||||
little_endian = True
|
||||
elif can_dbc.name.startswith(("subaru_")):
|
||||
elif can_dbc.name.startswith(("subaru_global_")):
|
||||
checksum_type = "subaru"
|
||||
checksum_size = 8
|
||||
counter_size = None
|
||||
@@ -69,7 +70,7 @@ def process(in_fn, out_fn):
|
||||
little_endian = None
|
||||
|
||||
# sanity checks on expected COUNTER and CHECKSUM rules, as packer and parser auto-compute those signals
|
||||
for address, msg_name, msg_size, sigs in msgs:
|
||||
for address, msg_name, _, sigs in msgs:
|
||||
dbc_msg_name = dbc_name + " " + msg_name
|
||||
for sig in sigs:
|
||||
if checksum_type is not None:
|
||||
@@ -121,6 +122,6 @@ def main():
|
||||
|
||||
process(in_fn, out_fn)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
*.bz2
|
||||
@@ -1,585 +0,0 @@
|
||||
[MASTER]
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code
|
||||
extension-pkg-whitelist=scipy
|
||||
|
||||
# Add files or directories to the blacklist. They should be base names, not
|
||||
# paths.
|
||||
ignore=CVS
|
||||
|
||||
# Add files or directories matching the regex patterns to the blacklist. The
|
||||
# regex matches against base names, not paths.
|
||||
ignore-patterns=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Use multiple processes to speed up Pylint.
|
||||
jobs=4
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||
# user-friendly hints instead of false-positive error messages
|
||||
suggestion-mode=yes
|
||||
|
||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||
# active Python interpreter and may run arbitrary code.
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
|
||||
confidence=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once).You can also use "--disable=all" to
|
||||
# disable everything first and then reenable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||
# --disable=W"
|
||||
disable=print-statement,
|
||||
parameter-unpacking,
|
||||
unpacking-in-except,
|
||||
old-raise-syntax,
|
||||
backtick,
|
||||
long-suffix,
|
||||
old-ne-operator,
|
||||
old-octal-literal,
|
||||
import-star-module-level,
|
||||
non-ascii-bytes-literal,
|
||||
raw-checker-failed,
|
||||
bad-inline-option,
|
||||
locally-disabled,
|
||||
locally-enabled,
|
||||
file-ignored,
|
||||
suppressed-message,
|
||||
useless-suppression,
|
||||
deprecated-pragma,
|
||||
apply-builtin,
|
||||
basestring-builtin,
|
||||
buffer-builtin,
|
||||
cmp-builtin,
|
||||
coerce-builtin,
|
||||
execfile-builtin,
|
||||
file-builtin,
|
||||
long-builtin,
|
||||
raw_input-builtin,
|
||||
reduce-builtin,
|
||||
standarderror-builtin,
|
||||
unicode-builtin,
|
||||
xrange-builtin,
|
||||
coerce-method,
|
||||
delslice-method,
|
||||
getslice-method,
|
||||
setslice-method,
|
||||
no-absolute-import,
|
||||
old-division,
|
||||
dict-iter-method,
|
||||
dict-view-method,
|
||||
next-method-called,
|
||||
metaclass-assignment,
|
||||
indexing-exception,
|
||||
raising-string,
|
||||
reload-builtin,
|
||||
oct-method,
|
||||
hex-method,
|
||||
nonzero-method,
|
||||
cmp-method,
|
||||
input-builtin,
|
||||
round-builtin,
|
||||
intern-builtin,
|
||||
unichr-builtin,
|
||||
map-builtin-not-iterating,
|
||||
zip-builtin-not-iterating,
|
||||
range-builtin-not-iterating,
|
||||
filter-builtin-not-iterating,
|
||||
using-cmp-argument,
|
||||
eq-without-hash,
|
||||
div-method,
|
||||
idiv-method,
|
||||
rdiv-method,
|
||||
exception-message-attribute,
|
||||
invalid-str-codec,
|
||||
sys-max-int,
|
||||
bad-python3-import,
|
||||
deprecated-string-function,
|
||||
deprecated-str-translate-call,
|
||||
deprecated-itertools-function,
|
||||
deprecated-types-field,
|
||||
next-method-defined,
|
||||
dict-items-not-iterating,
|
||||
dict-keys-not-iterating,
|
||||
dict-values-not-iterating,
|
||||
bad-indentation,
|
||||
line-too-long,
|
||||
missing-docstring,
|
||||
multiple-statements,
|
||||
bad-continuation,
|
||||
invalid-name,
|
||||
too-many-arguments,
|
||||
too-many-locals,
|
||||
superfluous-parens,
|
||||
bad-whitespace,
|
||||
too-many-instance-attributes,
|
||||
wrong-import-position,
|
||||
ungrouped-imports,
|
||||
wrong-import-order,
|
||||
protected-access,
|
||||
trailing-whitespace,
|
||||
too-many-branches,
|
||||
too-few-public-methods,
|
||||
too-many-statements,
|
||||
trailing-newlines,
|
||||
attribute-defined-outside-init,
|
||||
too-many-return-statements,
|
||||
too-many-public-methods,
|
||||
unused-argument,
|
||||
old-style-class,
|
||||
no-init,
|
||||
len-as-condition,
|
||||
unneeded-not,
|
||||
no-self-use,
|
||||
multiple-imports,
|
||||
no-else-return,
|
||||
logging-not-lazy,
|
||||
fixme,
|
||||
redefined-outer-name,
|
||||
unused-variable,
|
||||
unsubscriptable-object,
|
||||
expression-not-assigned,
|
||||
too-many-boolean-expressions,
|
||||
consider-using-ternary,
|
||||
invalid-unary-operand-type,
|
||||
relative-import,
|
||||
deprecated-lambda
|
||||
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once). See also the "--disable" option for examples.
|
||||
enable=c-extension-no-member
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (RP0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details
|
||||
#msg-template=
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, json
|
||||
# and msvs (visual studio).You can also give a reporter class, eg
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
output-format=text
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=no
|
||||
|
||||
# Activate the evaluation score.
|
||||
score=yes
|
||||
|
||||
|
||||
[REFACTORING]
|
||||
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=5
|
||||
|
||||
# Complete name of functions that never returns. When checking for
|
||||
# inconsistent-return-statements if a never returning function is called then
|
||||
# it will be considered as an explicit return statement and no message will be
|
||||
# printed.
|
||||
never-returning-functions=optparse.Values,sys.exit
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format
|
||||
logging-modules=logging
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Limits count of emitted suggestions for spelling mistakes
|
||||
max-spelling-suggestions=4
|
||||
|
||||
# Spelling dictionary name. Available dictionaries: none. To make it working
|
||||
# install python-enchant package.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to indicated private dictionary in
|
||||
# --spelling-private-dict-file option instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,
|
||||
XXX,
|
||||
TODO
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Ignore imports when computing similarities.
|
||||
ignore-imports=no
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# List of decorators that produce context managers, such as
|
||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||
# produce valid context managers.
|
||||
contextmanager-decorators=contextlib.contextmanager
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=capnp.* cereal.* pygame.* zmq.* setproctitle.* smbus2.* usb1.* serial.* cv2.*
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# This flag controls whether pylint should warn about no-member and similar
|
||||
# checks whenever an opaque object is returned when inferring. The inference
|
||||
# can return multiple potential results while evaluating a Python object, but
|
||||
# some branches might not be evaluated, which results in partial inference. In
|
||||
# that case, it might be useful to still emit no-member and other checks for
|
||||
# the rest of the inferred objects.
|
||||
ignore-on-opaque-inference=yes
|
||||
|
||||
# List of class names for which member attributes should not be checked (useful
|
||||
# for classes with dynamically set attributes). This supports the use of
|
||||
# qualified names.
|
||||
ignored-classes=optparse.Values,thread._local,_thread._local
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis. It
|
||||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=flask setproctitle usb1 flask.ext.socketio smbus2 usb1.*
|
||||
|
||||
# Show a hint with possible names when a member name was not found. The aspect
|
||||
# of finding the hint is based on edit distance.
|
||||
missing-member-hint=yes
|
||||
|
||||
# The minimum edit distance a name should have in order to be considered a
|
||||
# similar match for a missing member name.
|
||||
missing-member-hint-distance=1
|
||||
|
||||
# The total number of similar names that should be taken in consideration when
|
||||
# showing a hint for a missing member.
|
||||
missing-member-max-choices=1
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# Tells whether unused global variables should be treated as a violation.
|
||||
allow-global-unused-variables=yes
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,
|
||||
_cb
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expectedly
|
||||
# not used).
|
||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*|^ignored_|^unused_
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# List of qualified module names which can have objects that can redefine
|
||||
# builtins.
|
||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=100
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# List of optional constructs for which whitespace checking is disabled. `dict-
|
||||
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
|
||||
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
|
||||
# `empty-line` allows space-only lines.
|
||||
no-space-check=trailing-comma,
|
||||
dict-separator
|
||||
|
||||
# Allow the body of a class to be on the same line as the declaration if body
|
||||
# contains single statement.
|
||||
single-line-class-stmt=no
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=no
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Naming style matching correct argument names
|
||||
argument-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct argument names. Overrides argument-
|
||||
# naming-style
|
||||
#argument-rgx=
|
||||
|
||||
# Naming style matching correct attribute names
|
||||
attr-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||
# style
|
||||
#attr-rgx=
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,
|
||||
bar,
|
||||
baz,
|
||||
toto,
|
||||
tutu,
|
||||
tata
|
||||
|
||||
# Naming style matching correct class attribute names
|
||||
class-attribute-naming-style=any
|
||||
|
||||
# Regular expression matching correct class attribute names. Overrides class-
|
||||
# attribute-naming-style
|
||||
#class-attribute-rgx=
|
||||
|
||||
# Naming style matching correct class names
|
||||
class-naming-style=PascalCase
|
||||
|
||||
# Regular expression matching correct class names. Overrides class-naming-style
|
||||
#class-rgx=
|
||||
|
||||
# Naming style matching correct constant names
|
||||
const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct constant names. Overrides const-naming-
|
||||
# style
|
||||
#const-rgx=
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=-1
|
||||
|
||||
# Naming style matching correct function names
|
||||
function-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct function names. Overrides function-
|
||||
# naming-style
|
||||
#function-rgx=
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,
|
||||
j,
|
||||
k,
|
||||
ex,
|
||||
Run,
|
||||
_
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name
|
||||
include-naming-hint=no
|
||||
|
||||
# Naming style matching correct inline iteration names
|
||||
inlinevar-naming-style=any
|
||||
|
||||
# Regular expression matching correct inline iteration names. Overrides
|
||||
# inlinevar-naming-style
|
||||
#inlinevar-rgx=
|
||||
|
||||
# Naming style matching correct method names
|
||||
method-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct method names. Overrides method-naming-
|
||||
# style
|
||||
#method-rgx=
|
||||
|
||||
# Naming style matching correct module names
|
||||
module-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct module names. Overrides module-naming-
|
||||
# style
|
||||
#module-rgx=
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=^_
|
||||
|
||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||
# to this list to register other decorators that produce valid properties.
|
||||
property-classes=abc.abstractproperty
|
||||
|
||||
# Naming style matching correct variable names
|
||||
variable-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct variable names. Overrides variable-
|
||||
# naming-style
|
||||
#variable-rgx=
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=5
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Maximum number of boolean expressions in a if statement
|
||||
max-bool-expr=5
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,
|
||||
__new__,
|
||||
setUp
|
||||
|
||||
# List of member names, which should be excluded from the protected access
|
||||
# warning.
|
||||
exclude-protected=_asdict,
|
||||
_fields,
|
||||
_replace,
|
||||
_source,
|
||||
_make
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
# List of valid names for the first argument in a metaclass class method.
|
||||
valid-metaclass-classmethod-first-arg=mcs
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Allow wildcard imports from modules that define __all__.
|
||||
allow-wildcard-with-all=no
|
||||
|
||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||
# 3 compatible code, which means that the block might have code that exists
|
||||
# only in one or another interpreter, leading to false positives when analysed.
|
||||
analyse-fallback-blocks=no
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=regsub,
|
||||
TERMIOS,
|
||||
Bastion,
|
||||
rexec
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
# Force import order to recognize a module as part of the standard
|
||||
# compatibility libraries.
|
||||
known-standard-library=
|
||||
|
||||
# Force import order to recognize a module as part of a third party library.
|
||||
known-third-party=enchant
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "Exception"
|
||||
overgeneral-exceptions=Exception
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
RESULT=$(python3 -m flake8 --select=F $(find ../../../ -type f | grep "\.py$"))
|
||||
if [[ $RESULT ]]; then
|
||||
echo "Pyflakes found errors in the code. Please fix and try again"
|
||||
echo "$RESULT"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
python3 -m pylint --disable=R,C,W $(find ../../../ -type f | grep "\.py$")
|
||||
|
||||
exit_status=$?
|
||||
(( res = exit_status & 3 ))
|
||||
|
||||
if [[ $res != 0 ]]; then
|
||||
echo "Pylint found errors in the code. Please fix and try again"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import unittest
|
||||
|
||||
from opendbc.can.can_define import CANDefine
|
||||
|
||||
|
||||
class TestCADNDefine(unittest.TestCase):
|
||||
def test_civic(self):
|
||||
|
||||
dbc_file = "honda_civic_touring_2016_can_generated"
|
||||
defs = CANDefine(dbc_file)
|
||||
|
||||
self.assertDictEqual(defs.dv[399], defs.dv['STEER_STATUS'])
|
||||
self.assertDictEqual(defs.dv[399],
|
||||
{'STEER_STATUS':
|
||||
{6: 'TMP_FAULT',
|
||||
5: 'FAULT_1',
|
||||
4: 'NO_TORQUE_ALERT_2',
|
||||
3: 'LOW_SPEED_LOCKOUT',
|
||||
2: 'NO_TORQUE_ALERT_1',
|
||||
0: 'NORMAL'}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
cd ../../generator/
|
||||
|
||||
# run generator
|
||||
./generator.py
|
||||
|
||||
if [ -n "$(git status --untracked-files=no --porcelain)" ]; then
|
||||
echo "Unexpected changes after running generator.py";
|
||||
exit 1
|
||||
else
|
||||
echo "Success";
|
||||
fi
|
||||
@@ -1,105 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import unittest
|
||||
|
||||
from opendbc.can.parser import CANParser
|
||||
from opendbc.can.packer import CANPacker
|
||||
import cereal.messaging as messaging
|
||||
|
||||
|
||||
# Python implementation so we don't have to depend on boardd
|
||||
def can_list_to_can_capnp(can_msgs, msgtype='can'):
|
||||
dat = messaging.new_message()
|
||||
dat.init(msgtype, len(can_msgs))
|
||||
|
||||
for i, can_msg in enumerate(can_msgs):
|
||||
if msgtype == 'sendcan':
|
||||
cc = dat.sendcan[i]
|
||||
else:
|
||||
cc = dat.can[i]
|
||||
|
||||
cc.address = can_msg[0]
|
||||
cc.busTime = can_msg[1]
|
||||
cc.dat = bytes(can_msg[2])
|
||||
cc.src = can_msg[3]
|
||||
|
||||
return dat.to_bytes()
|
||||
|
||||
|
||||
class TestCanParserPacker(unittest.TestCase):
|
||||
def test_civic(self):
|
||||
|
||||
dbc_file = "honda_civic_touring_2016_can_generated"
|
||||
|
||||
signals = [
|
||||
("STEER_TORQUE", "STEERING_CONTROL", 0),
|
||||
("STEER_TORQUE_REQUEST", "STEERING_CONTROL", 0),
|
||||
]
|
||||
checks = []
|
||||
|
||||
parser = CANParser(dbc_file, signals, checks, 0)
|
||||
packer = CANPacker(dbc_file)
|
||||
|
||||
idx = 0
|
||||
|
||||
for steer in range(-256, 255):
|
||||
for active in [1, 0]:
|
||||
values = {
|
||||
"STEER_TORQUE": steer,
|
||||
"STEER_TORQUE_REQUEST": active,
|
||||
}
|
||||
|
||||
msgs = packer.make_can_msg("STEERING_CONTROL", 0, values, idx)
|
||||
bts = can_list_to_can_capnp([msgs])
|
||||
|
||||
parser.update_string(bts)
|
||||
|
||||
self.assertAlmostEqual(parser.vl["STEERING_CONTROL"]["STEER_TORQUE"], steer)
|
||||
self.assertAlmostEqual(parser.vl["STEERING_CONTROL"]["STEER_TORQUE_REQUEST"], active)
|
||||
self.assertAlmostEqual(parser.vl["STEERING_CONTROL"]["COUNTER"], idx % 4)
|
||||
|
||||
idx += 1
|
||||
|
||||
def test_subaru(self):
|
||||
# Subuaru is little endian
|
||||
|
||||
dbc_file = "subaru_global_2017"
|
||||
|
||||
signals = [
|
||||
("Counter", "ES_LKAS", 0),
|
||||
("LKAS_Output", "ES_LKAS", 0),
|
||||
("LKAS_Request", "ES_LKAS", 0),
|
||||
("SET_1", "ES_LKAS", 0),
|
||||
|
||||
]
|
||||
|
||||
checks = []
|
||||
|
||||
parser = CANParser(dbc_file, signals, checks, 0)
|
||||
packer = CANPacker(dbc_file)
|
||||
|
||||
idx = 0
|
||||
|
||||
for steer in range(-256, 255):
|
||||
for active in [1, 0]:
|
||||
values = {
|
||||
"Counter": idx,
|
||||
"LKAS_Output": steer,
|
||||
"LKAS_Request": active,
|
||||
"SET_1": 1
|
||||
}
|
||||
|
||||
msgs = packer.make_can_msg("ES_LKAS", 0, values)
|
||||
bts = can_list_to_can_capnp([msgs])
|
||||
parser.update_string(bts)
|
||||
|
||||
self.assertAlmostEqual(parser.vl["ES_LKAS"]["LKAS_Output"], steer)
|
||||
self.assertAlmostEqual(parser.vl["ES_LKAS"]["LKAS_Request"], active)
|
||||
self.assertAlmostEqual(parser.vl["ES_LKAS"]["SET_1"], 1)
|
||||
self.assertAlmostEqual(parser.vl["ES_LKAS"]["Counter"], idx % 16)
|
||||
|
||||
idx += 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user