Merge remote-tracking branch 'upstream/master' into toyota-lta

pull/27494/head
Shane Smiskol 3 years ago
commit dcf9d4b3e5
  1. 15
      .github/ISSUE_TEMPLATE/bug_report.yml
  2. 14
      .github/ISSUE_TEMPLATE/car_bug_report.yml
  3. 5
      .github/ISSUE_TEMPLATE/config.yml
  4. 2
      .github/PULL_REQUEST_TEMPLATE/car_bugfix.md
  5. 2
      .github/PULL_REQUEST_TEMPLATE/car_port.md
  6. 4
      .github/pull_request_template.md
  7. 33
      .github/workflows/badges.yaml
  8. 15
      .github/workflows/prebuilt.yaml
  9. 29
      .github/workflows/release.yaml
  10. 408
      .github/workflows/selfdrive_tests.yaml
  11. 37
      .github/workflows/setup/action.yaml
  12. 76
      .github/workflows/tools_tests.yaml
  13. 15
      .gitignore
  14. 6
      .gitmodules
  15. 42
      .pre-commit-config.yaml
  16. 11
      .pylintrc
  17. 8
      Dockerfile.openpilot
  18. 11
      Dockerfile.openpilot_base
  19. 37
      Dockerfile.openpilot_base_cl
  20. 179
      Jenkinsfile
  21. 83
      Pipfile
  22. 2252
      Pipfile.lock
  23. 49
      README.md
  24. 119
      RELEASES.md
  25. 178
      SConstruct
  26. 5
      SECURITY.md
  27. 1
      body
  28. 2
      cereal
  29. 33
      common/SConscript
  30. 6
      common/api/__init__.py
  31. 2
      common/basedir.py
  32. 9
      common/clutil.cc
  33. 0
      common/clutil.h
  34. 19
      common/conversions.py
  35. 14
      common/file_helpers.py
  36. 65
      common/gpio.cc
  37. 12
      common/gpio.h
  38. 17
      common/gpio.py
  39. 8
      common/i2c.cc
  40. 0
      common/i2c.h
  41. 12
      common/logging_extra.py
  42. 48
      common/markdown.py
  43. 0
      common/mat.h
  44. 25
      common/modeldata.h
  45. 73
      common/params.cc
  46. 9
      common/params.h
  47. 3
      common/params.py
  48. 32
      common/params_pyx.pyx
  49. 0
      common/queue.h
  50. 42
      common/realtime.py
  51. 7
      common/statlog.cc
  52. 0
      common/statlog.h
  53. 6
      common/string_helpers.py
  54. 92
      common/swaglog.cc
  55. 19
      common/swaglog.h
  56. 0
      common/tests/.gitignore
  57. 26
      common/tests/test_markdown.py
  58. 25
      common/tests/test_params.py
  59. 15
      common/tests/test_swaglog.cc
  60. 21
      common/tests/test_util.cc
  61. 47
      common/tests/test_xattr.py
  62. 0
      common/timing.h
  63. 2
      common/transformations/README.md
  64. 21
      common/transformations/camera.py
  65. 159
      common/transformations/model.py
  66. 3
      common/transformations/orientation.py
  67. 27
      common/util.cc
  68. 20
      common/util.h
  69. 1
      common/version.h
  70. 9
      common/watchdog.cc
  71. 5
      common/watchdog.h
  72. 4
      common/window.py
  73. 7
      common/xattr.py
  74. 461
      docs/CARS.md
  75. 2
      docs/INTEGRATION.md
  76. 2
      docs/Makefile
  77. 2
      docs/SAFETY.md
  78. 56
      docs/assets/icon-star-empty.svg
  79. 56
      docs/assets/icon-star-full.svg
  80. 66
      docs/assets/icon-star-half.svg
  81. 18
      docs/c_docs.rst
  82. 6
      docs/conf.py
  83. 8
      docs/docker/Dockerfile
  84. 2
      installer/updater/updater
  85. 2
      laika_repo
  86. 112
      launch_chffrplus.sh
  87. 6
      launch_env.sh
  88. 109
      models/README.md
  89. 3
      models/big_supercombo.dlc
  90. 3
      models/big_supercombo.onnx
  91. 2
      models/dmonitoring_model.current
  92. 3
      models/dmonitoring_model.onnx
  93. 3
      models/dmonitoring_model_q.dlc
  94. 3
      models/supercombo.dlc
  95. 3
      models/supercombo.onnx
  96. 12
      mypy.ini
  97. 2
      opendbc
  98. 2
      panda
  99. 8030
      poetry.lock
  100. 26
      pyextra/acados_template/acados_layout.json
  101. Some files were not shown because too many files have changed in this diff Show More

@ -8,6 +8,7 @@ body:
value: > value: >
Before creating a **bug report**, please check the following: Before creating a **bug report**, please check the following:
* If the issue likely only affects your car model or make, go back and open a **car bug report** instead. * If the issue likely only affects your car model or make, go back and open a **car bug report** instead.
* If the issue is related to the driving or driver monitoring models, you should open a [discussion](https://github.com/commaai/openpilot/discussions/categories/model-feedback) instead.
* Ensure you're running the latest openpilot release. * Ensure you're running the latest openpilot release.
* Ensure you're using officially supported hardware. Issues running on PCs have a different issue template. * Ensure you're using officially supported hardware. Issues running on PCs have a different issue template.
* Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue. * Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue.
@ -22,23 +23,11 @@ body:
validations: validations:
required: true required: true
- type: dropdown
id: hw
attributes:
label: What hardware does this issue affect?
multiple: true
options:
- comma three
- comma two
- EON Gold
validations:
required: true
- type: input - type: input
id: route id: route
attributes: attributes:
label: Provide a route where the issue occurs label: Provide a route where the issue occurs
description: Ensure the route is fully uploaded at https://useradmin.comma.ai description: Ensure the route is fully uploaded at https://useradmin.comma.ai. We cannot look into issues without routes, or at least a Dongle ID.
placeholder: 77611a1fac303767|2020-05-11--16-37-07 placeholder: 77611a1fac303767|2020-05-11--16-37-07
validations: validations:
required: true required: true

@ -1,6 +1,6 @@
name: Car bug report name: Car bug report
description: For issues with a particular car make or model description: For issues with a particular car make or model
labels: ["car bug"] labels: ["car", "bug"]
body: body:
- type: markdown - type: markdown
@ -21,18 +21,6 @@ body:
validations: validations:
required: true required: true
- type: dropdown
id: hw
attributes:
label: What hardware does this issue affect?
multiple: true
options:
- comma three
- comma two
- EON Gold
validations:
required: true
- type: input - type: input
id: car id: car
attributes: attributes:

@ -1,8 +1,11 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: Report model bugs
url: https://github.com/commaai/openpilot/discussions/categories/model-feedback
about: Provide feedback for the driving or driver monitoring models
- name: Discussions - name: Discussions
url: https://github.com/commaai/openpilot/discussions url: https://github.com/commaai/openpilot/discussions
about: For questions and discussion about openpilot about: For questions and general discussion about openpilot
- name: Community Wiki - name: Community Wiki
url: https://github.com/commaai/openpilot/wiki url: https://github.com/commaai/openpilot/wiki
about: Check out our community wiki about: Check out our community wiki

@ -1,6 +1,6 @@
--- ---
name: Car Bug fix name: Car Bug fix
about: For vehicle/brand specifc bug fixes about: For vehicle/brand specific bug fixes
title: '' title: ''
labels: 'car bug fix' labels: 'car bug fix'
assignees: '' assignees: ''

@ -9,7 +9,7 @@ assignees: ''
**Checklist** **Checklist**
- [ ] added to README - [ ] added to README
- [ ] test route added to [test_routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/test/test_models.py) - [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
- [ ] route with openpilot: - [ ] route with openpilot:
- [ ] route with stock system: - [ ] route with stock system:
- [ ] car harness used (if comma doesn't sell it, put N/A): - [ ] car harness used (if comma doesn't sell it, put N/A):

@ -22,8 +22,8 @@ Route: [a route with the bug fix]
<!--- ***** Template: Car port ***** <!--- ***** Template: Car port *****
**Checklist** **Checklist**
- [ ] added to README - [ ] added entry to CarInfo in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs
- [ ] test route added to [test_routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/test/test_routes.py) - [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
- [ ] route with openpilot: - [ ] route with openpilot:
- [ ] route with stock system: - [ ] route with stock system:

@ -0,0 +1,33 @@
name: badges
on:
schedule:
- cron: '0 * * * *'
workflow_dispatch:
env:
BASE_IMAGE: openpilot-base
DOCKER_REGISTRY: ghcr.io/commaai
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $DOCKER_REGISTRY/$BASE_IMAGE:latest /bin/sh -c
jobs:
badges:
name: create badges
runs-on: ubuntu-20.04
if: github.repository == 'commaai/openpilot'
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: ./.github/workflows/setup
- name: Push badges
run: |
${{ env.RUN }} "scons -j$(nproc) && python selfdrive/ui/translations/create_badges.py"
git checkout --orphan badges
git rm -rf --cached .
git config user.email "badge-researcher@comma.ai"
git config user.name "Badge Researcher"
git add translation_badge.svg
git commit -m "Add/Update badges"
git push -f origin HEAD

@ -2,16 +2,15 @@ name: prebuilt
on: on:
schedule: schedule:
- cron: '0 * * * *' - cron: '0 * * * *'
workflow_dispatch:
env: env:
BASE_IMAGE: openpilot-base BASE_IMAGE: openpilot-base
DOCKER_REGISTRY: ghcr.io/commaai DOCKER_REGISTRY: ghcr.io/commaai
DOCKER_LOGIN: docker login ghcr.io -u adeebshihadeh -p ${{ secrets.CONTAINER_TOKEN }} DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
BUILD: | BUILD: |
docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base .
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true
docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base .
jobs: jobs:
build_prebuilt: build_prebuilt:
@ -23,19 +22,19 @@ jobs:
IMAGE_NAME: openpilot-prebuilt IMAGE_NAME: openpilot-prebuilt
steps: steps:
- name: Wait for green check mark - name: Wait for green check mark
uses: lewagon/wait-on-check-action@v0.2 uses: lewagon/wait-on-check-action@e2558238c09778af25867eb5de5a3ce4bbae3dcd
with: with:
ref: master ref: master
wait-interval: 30 wait-interval: 30
running-workflow-name: 'build prebuilt' running-workflow-name: 'build prebuilt'
- uses: actions/checkout@v2 check-regexp: ^((?!.*(build master-ci).*).)*$
- uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Build Docker image - name: Build Docker image
run: | run: |
eval "$BUILD" eval "$BUILD"
docker pull $DOCKER_REGISTRY/$IMAGE_NAME:latest || true DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f Dockerfile.openpilot .
docker build --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f Dockerfile.openpilot .
- name: Push to container registry - name: Push to container registry
run: | run: |
$DOCKER_LOGIN $DOCKER_LOGIN

@ -0,0 +1,29 @@
name: release
on:
schedule:
- cron: '0 * * * *'
workflow_dispatch:
jobs:
build_masterci:
name: build master-ci
runs-on: ubuntu-20.04
timeout-minutes: 60
if: github.repository == 'commaai/openpilot'
steps:
- name: Wait for green check mark
uses: lewagon/wait-on-check-action@e2558238c09778af25867eb5de5a3ce4bbae3dcd
with:
ref: master
wait-interval: 30
running-workflow-name: 'build master-ci'
check-regexp: ^((?!.*(build prebuilt).*).)*$
- uses: actions/checkout@v3
with:
submodules: true
fetch-depth: 0
- name: Pull LFS
run: git lfs pull
- name: Build master-ci
run: |
BRANCH=master-ci release/build_devel.sh

@ -1,72 +1,84 @@
name: selfdrive name: selfdrive
on: on:
push: push:
branches-ignore: branches-ignore:
- 'testing-closet*' - 'testing-closet*'
pull_request: pull_request:
concurrency:
group: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
cancel-in-progress: true
env: env:
BASE_IMAGE: openpilot-base BASE_IMAGE: openpilot-base
CL_BASE_IMAGE: openpilot-base-cl
DOCKER_REGISTRY: ghcr.io/commaai DOCKER_REGISTRY: ghcr.io/commaai
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }}
DOCKER_LOGIN: docker login ghcr.io -u adeebshihadeh -p ${{ secrets.CONTAINER_TOKEN }} DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
BUILD: | BUILD: |
docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base .
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true
docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base . RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/sh -c
BUILD_CL: |
DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $CL_BASE_IMAGE:latest -f Dockerfile.openpilot_base_cl .
RUN_CL: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/sh -c
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache $BASE_IMAGE /bin/sh -c
UNIT_TEST: coverage run --append -m unittest discover UNIT_TEST: coverage run --append -m unittest discover
jobs: jobs:
# TODO: once actions/cache supports read only mode, use the cache for all jobs
build_release: build_release:
name: build release name: build release
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 30
env: env:
STRIPPED_DIR: tmppilot STRIPPED_DIR: /tmp/releasepilot
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Build devel
run: TARGET_DIR=$STRIPPED_DIR release/build_devel.sh
- uses: ./.github/workflows/setup
- name: Check submodules - name: Check submodules
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
run: release/check-submodules.sh run: release/check-submodules.sh
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Strip non-release files
run: |
mkdir $STRIPPED_DIR
cp -pR --parents $(cat release/files_common) $STRIPPED_DIR
cp -pR --parents $(cat release/files_tici) $STRIPPED_DIR
cp -pR --parents $(cat release/files_pc) $STRIPPED_DIR
cp Dockerfile.openpilot_base $STRIPPED_DIR
# need this to build on x86
cp -pR --parents third_party/libyuv third_party/snpe selfdrive/modeld/runners $STRIPPED_DIR
- name: Build Docker image
run: eval "$BUILD"
- name: Build openpilot and run checks - name: Build openpilot and run checks
run: | run: |
cd $STRIPPED_DIR cd $STRIPPED_DIR
${{ env.RUN }} "CI=1 python selfdrive/manager/build.py && \ ${{ env.RUN }} "CI=1 python selfdrive/manager/build.py"
- name: Run tests
run: |
cd $STRIPPED_DIR
${{ env.RUN }} "release/check-dirty.sh && \
python -m unittest discover selfdrive/car" python -m unittest discover selfdrive/car"
- name: Cleanup scons cache - name: pre-commit
run: | run: |
cd $GITHUB_WORKSPACE
cp .pre-commit-config.yaml $STRIPPED_DIR
cp .pylintrc $STRIPPED_DIR
cp mypy.ini $STRIPPED_DIR
cd $STRIPPED_DIR cd $STRIPPED_DIR
${{ env.RUN }} "scons -j$(nproc) && \ ${{ env.RUN }} "SKIP=test_translations pre-commit run --all"
rm -rf /tmp/scons_cache/* && \
build_all:
name: build all
runs-on: ubuntu-20.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: ./.github/workflows/setup
with:
save-cache: true
- name: Build openpilot with all flags
run: ${{ env.RUN }} "scons -j$(nproc) --extras && release/check-dirty.sh"
- name: Cleanup scons cache
run: |
${{ env.RUN }} "rm -rf /tmp/scons_cache/* && \
scons -j$(nproc) --cache-populate" scons -j$(nproc) --cache-populate"
#build_mac: #build_mac:
@ -74,7 +86,7 @@ jobs:
# runs-on: macos-latest # runs-on: macos-latest
# timeout-minutes: 60 # timeout-minutes: 60
# steps: # steps:
# - uses: actions/checkout@v2 # - uses: actions/checkout@v3
# with: # with:
# submodules: true # submodules: true
# - name: Determine pre-existing Homebrew packages # - name: Determine pre-existing Homebrew packages
@ -93,7 +105,7 @@ jobs:
# /usr/local/Cellar # /usr/local/Cellar
# ~/github_brew_cache_entries.txt # ~/github_brew_cache_entries.txt
# /tmp/scons_cache # /tmp/scons_cache
# key: macos-${{ hashFiles('tools/mac_setup.sh', 'update_requirements.sh', 'Pipfile*') }} # key: macos-${{ hashFiles('tools/mac_setup.sh', 'update_requirements.sh', 'poetry.lock') }}
# restore-keys: macos- # restore-keys: macos-
# - name: Brew link restored dependencies # - name: Brew link restored dependencies
# run: | # run: |
@ -109,11 +121,11 @@ jobs:
# - name: Build openpilot # - name: Build openpilot
# run: | # run: |
# source tools/openpilot_env.sh # source tools/openpilot_env.sh
# pipenv run selfdrive/manager/build.py # poetry run selfdrive/manager/build.py
# #
# # cleanup scons cache # # cleanup scons cache
# rm -rf /tmp/scons_cache/ # rm -rf /tmp/scons_cache/
# pipenv run scons -j$(nproc) --cache-populate # poetry run scons -j$(nproc) --cache-populate
# - name: Remove pre-existing Homebrew packages for caching # - name: Remove pre-existing Homebrew packages for caching
# if: steps.dependency-cache.outputs.cache-hit != 'true' # if: steps.dependency-cache.outputs.cache-hit != 'true'
# run: | # run: |
@ -126,91 +138,59 @@ jobs:
# done # done
# comm -13 <(echo "$EXISTING_CELLAR") <(echo "$new_cellar") | tee ~/github_brew_cache_entries.txt # comm -13 <(echo "$EXISTING_CELLAR") <(echo "$new_cellar") | tee ~/github_brew_cache_entries.txt
build_webcam:
name: build webcam
runs-on: ubuntu-20.04
timeout-minutes: 90
env:
IMAGE_NAME: openpilotwebcamci
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Build Docker image
run: |
eval "$BUILD"
docker pull $DOCKER_REGISTRY/$IMAGE_NAME:latest || true
docker build --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f tools/webcam/Dockerfile .
- name: Build openpilot
run: docker run --shm-size 1G --rm -v $PWD:/tmp/openpilot -e PYTHONPATH=/tmp/openpilot $DOCKER_REGISTRY/$IMAGE_NAME /bin/sh -c "cd /tmp/openpilot && USE_WEBCAM=1 scons -j$(nproc)"
- name: Push to container registry
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
run: |
$DOCKER_LOGIN
docker push $DOCKER_REGISTRY/$IMAGE_NAME:latest
docker_push: docker_push:
name: docker push name: docker push
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 22
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
needs: static_analysis # hack to ensure slow tests run first since this and static_analysis are fast needs: static_analysis # hack to ensure slow tests run first since this and static_analysis are fast
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Build Docker image - name: Build Docker image
run: eval "$BUILD" run: eval "$BUILD"
timeout-minutes: 13
- name: Push to container registry - name: Push to container registry
run: | run: |
$DOCKER_LOGIN $DOCKER_LOGIN
docker push $DOCKER_REGISTRY/$BASE_IMAGE:latest docker push $DOCKER_REGISTRY/$BASE_IMAGE:latest
- name: Build CL Docker image
run: eval "$BUILD_CL"
timeout-minutes: 4
- name: Push to container registry
run: |
$DOCKER_LOGIN
docker push $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest
static_analysis: static_analysis:
name: static analysis name: static analysis
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Build Docker image - name: Build Docker image
run: eval "$BUILD" run: eval "$BUILD"
- name: pre-commit - name: pre-commit
run: ${{ env.RUN }} "git init && git add -A && pre-commit run --all" timeout-minutes: 5
run: ${{ env.RUN }} "pre-commit run --all"
valgrind: valgrind:
name: valgrind name: valgrind
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache dependencies - uses: ./.github/workflows/setup
id: dependency-cache - name: Build openpilot
uses: actions/cache@v2 run: ${{ env.RUN }} "scons -j$(nproc)"
with:
path: /tmp/comma_download_cache
key: ${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/test_valgrind_replay.py') }}
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Run valgrind - name: Run valgrind
run: | run: |
${{ env.RUN }} "scons -j$(nproc) && \ ${{ env.RUN }} "python selfdrive/test/test_valgrind_replay.py"
FILEREADER_CACHE=1 python selfdrive/test/test_valgrind_replay.py"
- name: Print logs - name: Print logs
if: always() if: always()
run: cat selfdrive/test/valgrind_logs.txt run: cat selfdrive/test/valgrind_logs.txt
@ -218,34 +198,18 @@ jobs:
unit_tests: unit_tests:
name: unit tests name: unit tests
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 30
steps: steps:
- name: Get current date - uses: actions/checkout@v3
id: date
run: echo "::set-output name=time::$(date +'%s')"
- name: Output timestamp
run: echo $TIMESTAMP
env:
TIMESTAMP: ${{ steps.date.outputs.time }}
- uses: actions/checkout@v2
with: with:
submodules: true submodules: true
- name: Cache scons - uses: ./.github/workflows/setup
id: scons-cache - name: Build openpilot
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged. run: ${{ env.RUN }} "scons -j$(nproc)"
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: ${{ github.ref != 'refs/heads/master' || github.repository != 'commaai/openpilot' }}
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-${{ steps.date.outputs.time }}
restore-keys: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
- name: Build Docker image
run: eval "$BUILD"
- name: Run unit tests - name: Run unit tests
timeout-minutes: 15
run: | run: |
${{ env.RUN }} "scons -j$(nproc) --test && \ ${{ env.RUN }} "export SKIP_LONG_TESTS=1 && \
coverage run selfdrive/test/test_fingerprints.py && \
$UNIT_TEST common && \ $UNIT_TEST common && \
$UNIT_TEST opendbc/can && \ $UNIT_TEST opendbc/can && \
$UNIT_TEST selfdrive/boardd && \ $UNIT_TEST selfdrive/boardd && \
@ -254,17 +218,22 @@ jobs:
$UNIT_TEST selfdrive/loggerd && \ $UNIT_TEST selfdrive/loggerd && \
$UNIT_TEST selfdrive/car && \ $UNIT_TEST selfdrive/car && \
$UNIT_TEST selfdrive/locationd && \ $UNIT_TEST selfdrive/locationd && \
selfdrive/locationd/test/_test_locationd_lib.py && \
$UNIT_TEST selfdrive/athena && \ $UNIT_TEST selfdrive/athena && \
$UNIT_TEST selfdrive/thermald && \ $UNIT_TEST selfdrive/thermald && \
$UNIT_TEST selfdrive/hardware/tici && \ $UNIT_TEST system/hardware/tici && \
$UNIT_TEST tools/lib/tests && \ $UNIT_TEST tools/lib/tests && \
./selfdrive/ui/tests/create_test_translations.sh && \
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
./selfdrive/ui/tests/test_translations.py && \
./common/tests/test_util && \
./common/tests/test_swaglog && \
./selfdrive/boardd/tests/test_boardd_usbprotocol && \ ./selfdrive/boardd/tests/test_boardd_usbprotocol && \
./selfdrive/common/tests/test_util && \
./selfdrive/common/tests/test_swaglog && \
./selfdrive/loggerd/tests/test_logger &&\ ./selfdrive/loggerd/tests/test_logger &&\
./selfdrive/proclogd/tests/test_proclog && \ ./system/proclogd/tests/test_proclog && \
./selfdrive/ui/replay/tests/test_replay && \ ./tools/replay/tests/test_replay && \
./selfdrive/camerad/test/ae_gray_test && \ ./tools/cabana/tests/test_cabana && \
./system/camerad/test/ae_gray_test && \
coverage xml" coverage xml"
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v2
@ -272,38 +241,25 @@ jobs:
process_replay: process_replay:
name: process replay name: process replay
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 25
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache dependencies - uses: ./.github/workflows/setup
- name: Cache test routes
id: dependency-cache id: dependency-cache
uses: actions/cache@v2 uses: actions/cache@v3
with: with:
path: /tmp/comma_download_cache path: /tmp/comma_download_cache
key: ${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/test_processes.py') }} key: proc-replay-${{ hashFiles('.github/workflows/selfdrive_tests.yaml', 'selfdrive/test/process_replay/ref_commit') }}
- name: Cache scons - name: Build openpilot
id: scons-cache run: |
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged. ${{ env.RUN }} "scons -j$(nproc)"
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Run replay - name: Run replay
run: | run: |
${{ env.RUN }} "scons -j$(nproc) && \ ${{ env.RUN }} "CI=1 coverage run selfdrive/test/process_replay/test_processes.py -j$(nproc) && \
FILEREADER_CACHE=1 CI=1 coverage run selfdrive/test/process_replay/test_processes.py && \
coverage xml" coverage xml"
- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v2
- name: Print diff - name: Print diff
if: always() if: always()
run: cat selfdrive/test/process_replay/diff.txt run: cat selfdrive/test/process_replay/diff.txt
@ -313,51 +269,60 @@ jobs:
with: with:
name: process_replay_diff.txt name: process_replay_diff.txt
path: selfdrive/test/process_replay/diff.txt path: selfdrive/test/process_replay/diff.txt
- name: Upload reference logs
if: ${{ failure() && github.event_name == 'pull_request' && github.repository == 'commaai/openpilot' && env.AZURE_TOKEN != '' }}
run: |
${{ env.RUN }} "CI=1 AZURE_TOKEN='$AZURE_TOKEN' python selfdrive/test/process_replay/test_processes.py -j$(nproc) --upload-only"
- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v2
#model_replay: test_modeld:
# name: model replay name: model tests
# runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
# timeout-minutes: 50 timeout-minutes: 20
# steps: steps:
# - uses: actions/checkout@v2 - uses: actions/checkout@v3
# with: with:
# submodules: true submodules: true
# - name: Build Docker image - uses: ./.github/workflows/setup
# run: eval "$BUILD" - name: Build Docker image
# - name: Run replay # Sim docker is needed to get the OpenCL drivers
# run: | run: eval "$BUILD_CL"
# ${{ env.RUN }} "scons -j$(nproc) && \ - name: Build openpilot
# selfdrive/test/process_replay/model_replay.py" run: |
${{ env.RUN }} "scons -j$(nproc)"
- name: Run model replay with ONNX
timeout-minutes: 2
run: |
${{ env.RUN_CL }} "ONNXCPU=1 CI=1 coverage run selfdrive/test/process_replay/model_replay.py && \
coverage xml"
- name: Run unit tests
timeout-minutes: 5
run: |
${{ env.RUN_CL }} "$UNIT_TEST selfdrive/modeld && \
coverage xml"
- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v2
test_longitudinal: test_longitudinal:
name: longitudinal name: longitudinal
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache scons - uses: ./.github/workflows/setup
id: scons-cache - name: Build openpilot
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged. run: |
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b ${{ env.RUN }} "scons -j$(nproc)"
env:
CACHE_SKIP_SAVE: true
with:
path: /tmp/scons_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
restore-keys: |
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}-
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Test longitudinal - name: Test longitudinal
run: | run: |
${{ env.RUN }} "mkdir -p selfdrive/test/out && \ ${{ env.RUN }} "mkdir -p selfdrive/test/out && \
scons -j$(nproc) && \
cd selfdrive/test/longitudinal_maneuvers && \ cd selfdrive/test/longitudinal_maneuvers && \
coverage run ./test_longitudinal.py && \ coverage run ./test_longitudinal.py && \
coverage xml" coverage xml"
timeout-minutes: 2
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v2
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
@ -370,62 +335,83 @@ jobs:
test_cars: test_cars:
name: cars name: cars
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 20
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
job: [0, 1, 2, 3] job: [0, 1, 2, 3, 4]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Cache dependencies - uses: ./.github/workflows/setup
- name: Cache test routes
id: dependency-cache id: dependency-cache
uses: actions/cache@v2
with:
path: /tmp/comma_download_cache
key: car_models-${{ hashFiles('selfdrive/test/test_models.py', 'selfdrive/test/test_routes.py') }}-${{ matrix.job }}
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
env:
CACHE_SKIP_SAVE: true
with: with:
path: /tmp/scons_cache path: /tmp/comma_download_cache
key: scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}- key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/car/tests/routes.py') }}-${{ matrix.job }}
restore-keys: | - name: Build openpilot
scons-${{ hashFiles('.github/workflows/selfdrive_tests.yaml') }}- run: ${{ env.RUN }} "scons -j$(nproc)"
scons-
- name: Build Docker image
run: eval "$BUILD"
- name: Test car models - name: Test car models
timeout-minutes: 12
run: | run: |
${{ env.RUN }} "scons -j$(nproc) --test && \ ${{ env.RUN }} "coverage run -m pytest selfdrive/car/tests/test_models.py && \
FILEREADER_CACHE=1 coverage run -m pytest selfdrive/test/test_models.py && \
coverage xml && \ coverage xml && \
chmod -R 777 /tmp/comma_download_cache" chmod -R 777 /tmp/comma_download_cache"
env: env:
NUM_JOBS: 4 NUM_JOBS: 5
JOB_ID: ${{ matrix.job }} JOB_ID: ${{ matrix.job }}
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v2
docs: car_docs_diff:
name: build docs name: PR comments
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 20
if: github.event_name == 'pull_request'
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Build docker container ref: ${{ github.event.pull_request.base.ref }}
- uses: ./.github/workflows/setup
- name: Get base car info
run: | run: |
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true ${{ env.RUN }} "scons -j$(nproc) && python selfdrive/debug/dump_car_info.py --path /tmp/openpilot_cache/base_car_info"
docker pull $DOCKER_REGISTRY/openpilot-docs:latest || true sudo chown -R $USER:$USER ${{ github.workspace }}
DOCKER_BUILDKIT=1 docker build --cache-from $DOCKER_REGISTRY/openpilot-docs:latest -t $DOCKER_REGISTRY/openpilot-docs:latest -f docs/docker/Dockerfile . - uses: actions/checkout@v3
- name: Push docker container with:
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot' submodules: true
- name: Save car docs diff
id: save_diff
run: | run: |
$DOCKER_LOGIN ${{ env.RUN }} "scons -j$(nproc)"
docker push $DOCKER_REGISTRY/openpilot-docs:latest output=$(${{ env.RUN }} "python selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_info") || true
output="${output//$'\n'/'%0A'}"
echo "::set-output name=diff::$output"
- name: Find comment
if: ${{ env.AZURE_TOKEN != '' }}
uses: peter-evans/find-comment@1769778a0c5bd330272d749d12c036d65e70d39d
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
body-includes: This PR makes changes to
- name: Update comment
if: ${{ steps.save_diff.outputs.diff != '' && env.AZURE_TOKEN != '' }}
uses: peter-evans/create-or-update-comment@b95e16d2859ad843a14218d1028da5b2c4cbc4b4
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: "${{ steps.save_diff.outputs.diff }}"
edit-mode: replace
- name: Delete comment
if: ${{ steps.fc.outputs.comment-id != '' && steps.save_diff.outputs.diff == '' && env.AZURE_TOKEN != '' }}
uses: actions/github-script@v6
with:
script: |
github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: ${{ steps.fc.outputs.comment-id }}
})

@ -0,0 +1,37 @@
name: 'openpilot env setup'
inputs:
save-cache:
default: false
required: false
runs:
using: "composite"
steps:
# do this after checkout to ensure our custom LFS config is used to pull from GitLab
- shell: bash
run: git lfs pull
# build cache
- id: date
shell: bash
run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
- shell: bash
run: echo "$CACHE_COMMIT_DATE"
- shell: bash
run: echo "CACHE_SKIP_SAVE=true" >> $GITHUB_ENV
if: github.ref != 'refs/heads/master' || inputs.save-cache == 'false'
- id: scons-cache
# TODO: change the version to the released version
# when https://github.com/actions/cache/pull/489 (or 571) is merged.
uses: actions/cache@03e00da99d75a2204924908e1cca7902cafce66b
with:
path: /tmp/scons_cache
key: scons-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
restore-keys: |
scons-${{ env.CACHE_COMMIT_DATE }}-
scons-
# build our docker image
- shell: bash
run: eval ${{ env.BUILD }}

@ -1,32 +1,44 @@
name: tools name: tools
on: on:
push: push:
branches-ignore:
- 'testing-closet*'
pull_request: pull_request:
concurrency:
group: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.run_id || github.head_ref || github.ref }}-${{ github.workflow }}-${{ github.event_name }}
cancel-in-progress: true
env: env:
BASE_IMAGE: openpilot-base BASE_IMAGE: openpilot-base
CL_BASE_IMAGE: openpilot-base-cl
DOCKER_REGISTRY: ghcr.io/commaai DOCKER_REGISTRY: ghcr.io/commaai
DOCKER_LOGIN: docker login ghcr.io -u adeebshihadeh -p ${{ secrets.CONTAINER_TOKEN }} DOCKER_LOGIN: docker login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
BUILD: | BUILD: |
docker pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base .
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true
docker build --cache-from $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $DOCKER_REGISTRY/$BASE_IMAGE:latest -t $BASE_IMAGE:latest -f Dockerfile.openpilot_base . RUN: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e FILEREADER_CACHE=1 -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $BASE_IMAGE /bin/sh -c
RUN: docker run --shm-size 1G -v $PWD:/tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e \
GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/comma_download_cache:/tmp/comma_download_cache $BASE_IMAGE /bin/sh -c BUILD_CL: |
DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $DOCKER_REGISTRY/$CL_BASE_IMAGE:latest -t $CL_BASE_IMAGE:latest -f Dockerfile.openpilot_base_cl .
RUN_CL: docker run --shm-size 1G -v $GITHUB_WORKSPACE:/tmp/openpilot -w /tmp/openpilot -e PYTHONPATH=/tmp/openpilot -e NUM_JOBS -e JOB_ID -e GITHUB_ACTION -e GITHUB_REF -e GITHUB_HEAD_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_RUN_ID -v /tmp/scons_cache:/tmp/scons_cache -v /tmp/comma_download_cache:/tmp/comma_download_cache -v /tmp/openpilot_cache:/tmp/openpilot_cache $CL_BASE_IMAGE /bin/sh -c
jobs: jobs:
plotjuggler: plotjuggler:
name: plotjuggler name: plotjuggler
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 30 timeout-minutes: 20
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Build Docker image - name: Build Docker image
run: eval "$BUILD" run: eval "$BUILD"
- name: Unit test - name: Unit test
timeout-minutes: 2
run: | run: |
${{ env.RUN }} "scons -j$(nproc) --directory=/tmp/openpilot/cereal && \ ${{ env.RUN }} "scons -j$(nproc) --directory=/tmp/openpilot/cereal && \
apt-get update && \ apt-get update && \
@ -37,35 +49,43 @@ jobs:
simulator: simulator:
name: simulator name: simulator
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
timeout-minutes: 50 timeout-minutes: 30
env: env:
IMAGE_NAME: openpilot-sim IMAGE_NAME: openpilot-sim
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
submodules: true submodules: true
- name: Pull LFS
# HACK: cache LFS objects since they count against our quota
# https://github.com/actions/checkout/issues/165#issuecomment-657673315
- name: Create LFS file list
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- name: Restore LFS cache
uses: actions/cache@v2
id: lfs-cache
with:
path: .git/lfs
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}
- name: Git LFS Pull
run: git lfs pull run: git lfs pull
- name: Build base image
- name: Build Docker image run: eval "$BUILD"
run: | - name: Build base cl image
eval "$BUILD" run: eval "$BUILD_CL"
docker pull $DOCKER_REGISTRY/$IMAGE_NAME:latest || true - name: Build simulator image
docker build --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f tools/sim/Dockerfile.sim . run: DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/$IMAGE_NAME:latest -t $DOCKER_REGISTRY/$IMAGE_NAME:latest -f tools/sim/Dockerfile.sim .
- name: Push to container registry - name: Push to container registry
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot' if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
run: | run: |
$DOCKER_LOGIN $DOCKER_LOGIN
docker push $DOCKER_REGISTRY/$IMAGE_NAME:latest docker push $DOCKER_REGISTRY/$IMAGE_NAME:latest
docs:
name: build docs
runs-on: ubuntu-20.04
timeout-minutes: 25
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Build docker container
run: |
DOCKER_BUILDKIT=1 docker build --pull --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_REGISTRY/openpilot-docs:latest -t $DOCKER_REGISTRY/openpilot-docs:latest -f docs/docker/Dockerfile .
- name: Push docker container
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
run: |
$DOCKER_LOGIN
docker push $DOCKER_REGISTRY/openpilot-docs:latest

15
.gitignore vendored

@ -32,26 +32,27 @@ a.out
*.class *.class
*.pyxbldc *.pyxbldc
*.vcd *.vcd
*.qm
config.json config.json
clcache clcache
compile_commands.json compile_commands.json
compare_runtime*.html
persist persist
board/obj/ board/obj/
selfdrive/boardd/boardd selfdrive/boardd/boardd
selfdrive/logcatd/logcatd selfdrive/logcatd/logcatd
selfdrive/mapd/default_speeds_by_region.json selfdrive/mapd/default_speeds_by_region.json
selfdrive/proclogd/proclogd system/proclogd/proclogd
selfdrive/ui/_ui selfdrive/ui/_ui
selfdrive/test/longitudinal_maneuvers/out selfdrive/test/longitudinal_maneuvers/out
selfdrive/visiond/visiond selfdrive/visiond/visiond
selfdrive/loggerd/loggerd
selfdrive/loggerd/bootlog
selfdrive/sensord/_gpsd selfdrive/sensord/_gpsd
selfdrive/sensord/_sensord selfdrive/sensord/_sensord
selfdrive/camerad/camerad system/camerad/camerad
selfdrive/camerad/test/ae_gray_test system/camerad/test/ae_gray_test
selfdrive/modeld/_modeld selfdrive/modeld/_modeld
selfdrive/modeld/_navmodeld
selfdrive/modeld/_dmonitoringmodeld selfdrive/modeld/_dmonitoringmodeld
/src/ /src/
@ -76,10 +77,12 @@ cppcheck_report.txt
comma*.sh comma*.sh
selfdrive/modeld/thneed/compile selfdrive/modeld/thneed/compile
models/*.thneed selfdrive/modeld/models/*.thneed
*.bz2 *.bz2
build/ build/
!**/.gitkeep !**/.gitkeep
poetry.toml

6
.gitmodules vendored

@ -13,3 +13,9 @@
[submodule "rednose_repo"] [submodule "rednose_repo"]
path = rednose_repo path = rednose_repo
url = ../../commaai/rednose.git url = ../../commaai/rednose.git
[submodule "body"]
path = body
url = ../../commaai/body.git
[submodule "tinygrad"]
path = tinygrad_repo
url = https://github.com/geohot/tinygrad.git

@ -15,18 +15,28 @@ repos:
- id: check-symlinks - id: check-symlinks
- id: check-added-large-files - id: check-added-large-files
args: ['--maxkb=100'] args: ['--maxkb=100']
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/codespell-project/codespell
rev: v0.931 rev: v2.2.1
hooks:
- id: codespell
exclude: '^(pyextra/)|(third_party/)|(body/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(include/)|(selfdrive/ui/translations/.*.ts)|(selfdrive/controls/lib/cluster)'
args:
# if you've got a short variable name that's getting flagged, add it here
- -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup
- --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US
- repo: local
hooks: hooks:
- id: mypy - id: mypy
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)/' name: mypy
additional_dependencies: ['git+https://github.com/numpy/numpy-stubs', 'types-requests', 'types-atomicwrites', entry: mypy
'types-pycurl'] language: system
types: [python]
exclude: '^(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)'
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 4.0.1 rev: 4.0.1
hooks: hooks:
- id: flake8 - id: flake8
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(selfdrive/debug/)/' exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(opendbc/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(selfdrive/debug/)/'
additional_dependencies: ['flake8-no-implicit-concat'] additional_dependencies: ['flake8-no-implicit-concat']
args: args:
- --indent-size=2 - --indent-size=2
@ -41,7 +51,12 @@ repos:
entry: pylint entry: pylint
language: system language: system
types: [python] types: [python]
exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)' exclude: '^(pyextra/)|(cereal/)|(rednose/)|(panda/)|(laika/)|(laika_repo/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)'
args:
- -j0
- -rn
- -sn
- --rcfile=.pylintrc
- repo: local - repo: local
hooks: hooks:
- id: cppcheck - id: cppcheck
@ -49,10 +64,21 @@ repos:
entry: cppcheck entry: cppcheck
language: system language: system
types: [c++] types: [c++]
exclude: '^(third_party/)|(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)/|(installer/)' exclude: '^(third_party/)|(pyextra/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)'
args: args:
- --error-exitcode=1 - --error-exitcode=1
- --language=c++ - --language=c++
- --quiet - --quiet
- --force - --force
- -j8 - -j8
- repo: local
hooks:
- id: test_translations
name: test translations
entry: selfdrive/ui/tests/test_translations.py
language: script
pass_filenames: false
- repo: https://github.com/python-poetry/poetry
rev: '1.2.2'
hooks:
- id: poetry-check

@ -3,7 +3,7 @@
# A comma-separated list of package or module names from where C extensions may # 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 # be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code # run arbitrary code
extension-pkg-whitelist=scipy cereal.messaging.messaging_pyx extension-pkg-whitelist=scipy,cereal.messaging.messaging_pyx,PyQt5,av
# Add files or directories to the blacklist. They should be base names, not # Add files or directories to the blacklist. They should be base names, not
# paths. # paths.
@ -54,7 +54,7 @@ confidence=
# --enable=similarities". If you want to run only the classes checker, but have # --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes # no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W" # --disable=W"
disable=C,R,W0613,W0511,W0212,W0201,W0311,W0106,W0603,W0621,W0703,W1201,W1203,E1136,W1514 disable=C,R,W0613,W0511,W0212,W0201,W0106,W0603,W0621,W0703,W1201,W1203,E1136,W1514
# Enable the message, report, category or checker with the given id(s). You can # Enable the message, report, category or checker with the given id(s). You can
@ -250,13 +250,6 @@ max-line-length=100
# Maximum number of lines in a module # Maximum number of lines in a module
max-module-lines=1000 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 # Allow the body of a class to be on the same line as the declaration if body
# contains single statement. # contains single statement.
single-line-class-stmt=no single-line-class-stmt=no

@ -8,11 +8,6 @@ ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH}
RUN mkdir -p ${OPENPILOT_PATH} RUN mkdir -p ${OPENPILOT_PATH}
WORKDIR ${OPENPILOT_PATH} WORKDIR ${OPENPILOT_PATH}
COPY Pipfile Pipfile.lock $OPENPILOT_PATH
RUN pip install --no-cache-dir pipenv==2021.5.29 pip==21.3.1 && \
pipenv install --system --deploy --dev --clear && \
pip uninstall -y pipenv
COPY SConstruct ${OPENPILOT_PATH} COPY SConstruct ${OPENPILOT_PATH}
COPY ./pyextra ${OPENPILOT_PATH}/pyextra COPY ./pyextra ${OPENPILOT_PATH}/pyextra
@ -28,5 +23,6 @@ COPY ./opendbc ${OPENPILOT_PATH}/opendbc
COPY ./cereal ${OPENPILOT_PATH}/cereal COPY ./cereal ${OPENPILOT_PATH}/cereal
COPY ./panda ${OPENPILOT_PATH}/panda COPY ./panda ${OPENPILOT_PATH}/panda
COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive
COPY ./system ${OPENPILOT_PATH}/system
RUN scons -j$(nproc) RUN scons --cache-readonly -j$(nproc)

@ -4,7 +4,7 @@ ENV PYTHONUNBUFFERED 1
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y --no-install-recommends sudo tzdata locales && \ apt-get install -y --no-install-recommends sudo tzdata locales ssh && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
@ -12,21 +12,22 @@ ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8 ENV LC_ALL en_US.UTF-8
ENV PIPENV_SYSTEM=1 ENV POETRY_VIRTUALENVS_CREATE=false
ENV PYENV_VERSION=3.8.10 ENV PYENV_VERSION=3.8.10
ENV PYENV_ROOT="/root/.pyenv" ENV PYENV_ROOT="/root/.pyenv"
ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH"
COPY Pipfile Pipfile.lock .python-version update_requirements.sh /tmp/ COPY pyproject.toml poetry.lock .python-version update_requirements.sh /tmp/
COPY tools/ubuntu_setup.sh /tmp/tools/ COPY tools/ubuntu_setup.sh /tmp/tools/
RUN cd /tmp && \ RUN cd /tmp && \
tools/ubuntu_setup.sh && \ tools/ubuntu_setup.sh && \
rm -rf /var/lib/apt/lists/* && \ rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/* && \ rm -rf /tmp/* && \
rm -rf /root/.cache && \ rm -rf /root/.cache && \
pip uninstall -y pipenv && \ pip uninstall -y poetry && \
# remove unused architectures from gcc for panda # remove unused architectures from gcc for panda
cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \ cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \
rm -rf arm/ && \ rm -rf arm/ && \
rm -rf thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp rm -rf thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp
RUN sudo git config --global --add safe.directory /tmp/openpilot

@ -0,0 +1,37 @@
FROM ghcr.io/commaai/openpilot-base:latest
RUN apt-get update && apt-get install -y --no-install-recommends\
apt-utils \
alien \
unzip \
tar \
curl \
xz-utils \
dbus \
gcc-arm-none-eabi \
tmux \
vim \
lsb-core \
libx11-6 \
&& rm -rf /var/lib/apt/lists/*
# Intel OpenCL driver
ARG INTEL_DRIVER=l_opencl_p_18.1.0.015.tgz
ARG INTEL_DRIVER_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532
RUN mkdir -p /tmp/opencl-driver-intel
WORKDIR /tmp/opencl-driver-intel
RUN echo INTEL_DRIVER is $INTEL_DRIVER && \
curl -O $INTEL_DRIVER_URL/$INTEL_DRIVER && \
tar -xzf $INTEL_DRIVER && \
for i in $(basename $INTEL_DRIVER .tgz)/rpm/*.rpm; do alien --to-deb $i; done && \
dpkg -i *.deb && \
rm -rf $INTEL_DRIVER $(basename $INTEL_DRIVER .tgz) *.deb && \
mkdir -p /etc/OpenCL/vendors && \
echo /opt/intel/opencl_compilers_and_libraries_18.1.0.015/linux/compiler/lib/intel64_lin/libintelocl.so > /etc/OpenCL/vendors/intel.icd && \
rm -rf /tmp/opencl-driver-intel
ENV NVIDIA_VISIBLE_DEVICES all
ENV NVIDIA_DRIVER_CAPABILITIES graphics,utility,compute
ENV QTWEBENGINE_DISABLE_SANDBOX 1
RUN dbus-uuidgen > /etc/machine-id

179
Jenkinsfile vendored

@ -10,6 +10,7 @@ export TEST_DIR=${env.TEST_DIR}
export SOURCE_DIR=${env.SOURCE_DIR} export SOURCE_DIR=${env.SOURCE_DIR}
export GIT_BRANCH=${env.GIT_BRANCH} export GIT_BRANCH=${env.GIT_BRANCH}
export GIT_COMMIT=${env.GIT_COMMIT} export GIT_COMMIT=${env.GIT_COMMIT}
export AZURE_TOKEN='${env.AZURE_TOKEN}'
source ~/.bash_profile source ~/.bash_profile
if [ -f /TICI ]; then if [ -f /TICI ]; then
@ -18,13 +19,6 @@ fi
ln -snf ${env.TEST_DIR} /data/pythonpath ln -snf ${env.TEST_DIR} /data/pythonpath
if [ -f /EON ]; then
echo \$\$ > /dev/cpuset/app/tasks || true
echo \$PPID > /dev/cpuset/app/tasks || true
mkdir -p /dev/shm
chmod 777 /dev/shm
fi
cd ${env.TEST_DIR} || true cd ${env.TEST_DIR} || true
${cmd} ${cmd}
exit 0 exit 0
@ -37,7 +31,7 @@ END"""
def phone_steps(String device_type, steps) { def phone_steps(String device_type, steps) {
lock(resource: "", label: device_type, inversePrecedence: true, variable: 'device_ip', quantity: 1) { lock(resource: "", label: device_type, inversePrecedence: true, variable: 'device_ip', quantity: 1) {
timeout(time: 60, unit: 'MINUTES') { timeout(time: 20, unit: 'MINUTES') {
phone(device_ip, "git checkout", readFile("selfdrive/test/setup_device_ci.sh"),) phone(device_ip, "git checkout", readFile("selfdrive/test/setup_device_ci.sh"),)
steps.each { item -> steps.each { item ->
phone(device_ip, item[0], item[1]) phone(device_ip, item[0], item[1])
@ -49,195 +43,156 @@ def phone_steps(String device_type, steps) {
pipeline { pipeline {
agent none agent none
environment { environment {
CI = "1"
TEST_DIR = "/data/openpilot" TEST_DIR = "/data/openpilot"
SOURCE_DIR = "/data/openpilot_source/" SOURCE_DIR = "/data/openpilot_source/"
AZURE_TOKEN = credentials('azure_token')
} }
options { options {
timeout(time: 4, unit: 'HOURS') timeout(time: 4, unit: 'HOURS')
} }
stages { stages {
stage('build releases') { stage('build release3') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
when { when {
branch 'devel-staging' branch 'devel-staging'
} }
parallel {
stage('release2') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps { steps {
phone_steps("eon-build", [ phone_steps("tici-needs-can", [
["build release2-staging & dashcam-staging", "PUSH=1 $SOURCE_DIR/release/build_release.sh"],
])
}
}
stage('release3') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps {
phone_steps("tici", [
["build release3-staging & dashcam3-staging", "PUSH=1 $SOURCE_DIR/release/build_release.sh"], ["build release3-staging & dashcam3-staging", "PUSH=1 $SOURCE_DIR/release/build_release.sh"],
]) ])
} }
} }
}
}
stage('openpilot tests') { stage('openpilot tests') {
when { when {
not { not {
anyOf { anyOf {
branch 'master-ci'; branch 'devel'; branch 'devel-staging'; branch 'master-ci'; branch 'devel'; branch 'devel-staging';
branch 'release2'; branch 'release2-staging'; branch 'dashcam'; branch 'dashcam-staging';
branch 'release3'; branch 'release3-staging'; branch 'dashcam3'; branch 'dashcam3-staging'; branch 'release3'; branch 'release3-staging'; branch 'dashcam3'; branch 'dashcam3-staging';
branch 'testing-closet*'; branch 'hotfix-*' branch 'testing-closet*'; branch 'hotfix-*'
} }
} }
} }
stages {
stage('On-device Tests') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
stages {
stage('parallel tests') {
parallel { parallel {
stage('C2: build') {
steps {
phone_steps("eon-build", [
["build master-ci", "cd $SOURCE_DIR/release && EXTRA_FILES='tools/' ./build_devel.sh"],
["build openpilot", "cd selfdrive/manager && ./build.py"],
["test manager", "python selfdrive/manager/test/test_manager.py"],
["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"],
["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"],
])
}
}
stage('C2: replay') { stage('simulator') {
steps { agent {
phone_steps("eon2", [ dockerfile {
["build", "cd selfdrive/manager && ./build.py"], filename 'Dockerfile.sim_nvidia'
["model replay", "cd selfdrive/test/process_replay && ./model_replay.py"], dir 'tools/sim'
]) args '--user=root'
} }
} }
stage('C2: HW + Unit Tests') {
steps { steps {
phone_steps("eon", [ sh "git config --global --add safe.directory ${WORKSPACE}"
["build", "cd selfdrive/manager && ./build.py"], sh "git lfs pull"
["test sounds", "python selfdrive/ui/tests/test_soundd.py"], lock(resource: "", label: "simulator", inversePrecedence: true, quantity: 1) {
["test boardd loopback", "python selfdrive/boardd/tests/test_boardd_loopback.py"], sh "${WORKSPACE}/tools/sim/build_container.sh"
["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], sh "DETACH=1 ${WORKSPACE}/tools/sim/start_carla.sh"
["test encoder", "python selfdrive/loggerd/tests/test_encoder.py"], sh "${WORKSPACE}/tools/sim/start_openpilot_docker.sh"
["test logcatd", "python selfdrive/logcatd/tests/test_logcatd_android.py"],
["test updater", "python selfdrive/hardware/eon/test_neos_updater.py"],
])
} }
} }
/* post {
stage('Power Consumption Tests') { always {
steps { sh "docker kill carla_sim || true"
lock(resource: "", label: "c2-zookeeper", inversePrecedence: true, variable: 'device_ip', quantity: 1) { sh "rm -rf ${WORKSPACE}/* || true"
timeout(time: 90, unit: 'MINUTES') { sh "rm -rf .* || true"
sh script: "/home/batman/tools/zookeeper/enable_and_wait.py $device_ip 120", label: "turn on device"
phone(device_ip, "git checkout", readFile("selfdrive/test/setup_device_ci.sh"),)
phone(device_ip, "build", "scons -j4 && sync")
sh script: "/home/batman/tools/zookeeper/disable.py $device_ip", label: "turn off device"
sh script: "/home/batman/tools/zookeeper/enable_and_wait.py $device_ip 120", label: "turn on device"
sh script: "/home/batman/tools/zookeeper/check_consumption.py 60 3", label: "idle power consumption after boot"
sh script: "/home/batman/tools/zookeeper/ignition.py 1", label: "go onroad"
sh script: "/home/batman/tools/zookeeper/check_consumption.py 60 10", label: "onroad power consumption"
sh script: "/home/batman/tools/zookeeper/ignition.py 0", label: "go offroad"
sh script: "/home/batman/tools/zookeeper/check_consumption.py 60 2", label: "idle power consumption offroad"
}
} }
} }
} }
*/
stage('C3: build') { stage('build') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
environment { environment {
R3_PUSH = "${env.BRANCH_NAME == 'master' ? '1' : ' '}" R3_PUSH = "${env.BRANCH_NAME == 'master' ? '1' : ' '}"
} }
steps { steps {
phone_steps("tici", [ phone_steps("tici-needs-can", [
["build master-ci", "cd $SOURCE_DIR/release && EXTRA_FILES='tools/' ./build_devel.sh"], ["build master-ci", "cd $SOURCE_DIR/release && TARGET_DIR=$TEST_DIR EXTRA_FILES='tools/' ./build_devel.sh"],
["build openpilot", "cd selfdrive/manager && ./build.py"], ["build openpilot", "cd selfdrive/manager && ./build.py"],
["test manager", "python selfdrive/manager/test/test_manager.py"], ["check dirty", "release/check-dirty.sh"],
["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"], ["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"],
["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"], ["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"],
]) ])
} }
} }
stage('C3: HW + Unit Tests') { stage('loopback-tests') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps { steps {
phone_steps("tici2", [ phone_steps("tici-loopback", [
["build", "cd selfdrive/manager && ./build.py"], ["build openpilot", "cd selfdrive/manager && ./build.py"],
["test boardd loopback", "python selfdrive/boardd/tests/test_boardd_loopback.py"], ["test boardd loopback", "python selfdrive/boardd/tests/test_boardd_loopback.py"],
["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"],
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"],
]) ])
} }
} }
stage('C2: camerad') { stage('HW + Unit Tests') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps { steps {
phone_steps("eon-party", [ phone_steps("tici-common", [
["build", "cd selfdrive/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test camerad", "python selfdrive/camerad/test/test_camerad.py"], ["test power draw", "python system/hardware/tici/test_power_draw.py"],
["test exposure", "python selfdrive/camerad/test/test_exposure.py"], ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"],
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"],
["test pigeond", "python selfdrive/sensord/tests/test_pigeond.py"],
["test manager", "python selfdrive/manager/test/test_manager.py"],
]) ])
} }
} }
stage('C3: camerad') { stage('camerad-ar') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps { steps {
phone_steps("tici-party", [ phone_steps("tici-ar0321", [
["build", "cd selfdrive/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test camerad", "python selfdrive/camerad/test/test_camerad.py"], ["test camerad", "python system/camerad/test/test_camerad.py"],
["test exposure", "python selfdrive/camerad/test/test_exposure.py"], ["test exposure", "python system/camerad/test/test_exposure.py"],
]) ])
} }
} }
stage('C3: replay') { stage('camerad-ox') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps { steps {
phone_steps("tici-party", [ phone_steps("tici-ox03c10", [
["build", "cd selfdrive/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["model replay", "cd selfdrive/test/process_replay && ./model_replay.py"], ["test camerad", "python system/camerad/test/test_camerad.py"],
["test exposure", "python system/camerad/test/test_exposure.py"],
]) ])
} }
} }
stage('sensord') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps {
phone_steps("tici-lsmc", [
["build", "cd selfdrive/manager && ./build.py"],
["test sensord", "cd selfdrive/sensord/tests && python -m unittest test_sensord.py"],
])
phone_steps("tici-bmx-lsm", [
["build", "cd selfdrive/manager && ./build.py"],
["test sensord", "cd selfdrive/sensord/tests && python -m unittest test_sensord.py"],
])
} }
} }
stage('Push master-ci') { stage('replay') {
when { agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
branch 'master'
}
steps { steps {
phone_steps("eon-build", [ phone_steps("tici-common", [
["push devel", "cd $SOURCE_DIR/release && PUSH='master-ci' ./build_devel.sh"], ["build", "cd selfdrive/manager && ./build.py"],
["model replay", "cd selfdrive/test/process_replay && ./model_replay.py"],
]) ])
} }
} }
} }
post {
always {
cleanWs()
}
} }
} }
} }
}
}
}

@ -1,83 +0,0 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
control = "*"
coverage = "*"
dictdiffer = "*"
fastcluster = "*"
hexdump = "*"
hypothesis = "*"
inputs = "*"
lru-dict = "*"
markdown-it-py = "*"
matplotlib = "*"
mypy = "*"
myst-parser = "*"
numpy = "*"
opencv-python-headless = "*"
parameterized = "*"
paramiko = "*"
pprofile = "*"
pre-commit = "*"
pycurl = "*"
pygame = "*"
pyprof2calltree = "*"
pytest = "*"
pytest-xdist = "*"
reverse_geocoder = "*"
scipy = "*"
sphinx = "*"
sphinx-sitemap = "*"
sphinx-rtd-theme = "*"
breathe = "*"
subprocess32 = "*"
tenacity = "*"
[packages]
atomicwrites = "*"
casadi = {version = "*", markers="platform_system != 'Darwin'"}
cffi = "*"
crcmod = "*"
cryptography = "*"
Cython = "*"
flake8 = "*"
Flask = "*"
future-fstrings = "*" # for acados
gunicorn = "*"
hexdump = "*"
Jinja2 = "*"
json-rpc = "*"
libusb1 = "*"
nose = "*"
numpy = "*"
onnx = "*"
onnxruntime-gpu = {version = "*", markers="platform_system != 'Darwin'"}
pillow = "*"
psutil = "*"
pycapnp = "==1.1.0"
pycryptodome = "*"
PyJWT = "*"
pylint = "*"
pyopencl = "*"
pyserial = "*"
python-dateutil = "*"
PyYAML = "*"
pyzmq = "*"
requests = "*"
scons = "*"
sentry-sdk = "*"
setproctitle = "*"
six = "*"
smbus2 = "*"
sympy = "!=1.6.1"
timezonefinder = "*"
tqdm = "*"
urllib3 = "*"
utm = "*"
websocket_client = "*"
[requires]
python_version = "3.8"

2252
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

@ -4,7 +4,7 @@ Table of Contents
======================= =======================
* [What is openpilot?](#what-is-openpilot) * [What is openpilot?](#what-is-openpilot)
* [Running in a car](#running-in-a-car) * [Running in a car](#running-on-a-dedicated-device-in-a-car)
* [Running on PC](#running-on-pc) * [Running on PC](#running-on-pc)
* [Community and Contributing](#community-and-contributing) * [Community and Contributing](#community-and-contributing)
* [User Data and comma Account](#user-data-and-comma-account) * [User Data and comma Account](#user-data-and-comma-account)
@ -17,7 +17,7 @@ Table of Contents
What is openpilot? What is openpilot?
------ ------
[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW) and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md). [openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW), and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models, and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera-based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md).
<table> <table>
<tr> <tr>
@ -35,26 +35,28 @@ What is openpilot?
</table> </table>
Running in a car Running on a dedicated device in a car
------ ------
To use openpilot in a car, you need four things To use openpilot in a car, you need four things
* This software. It's free and available right here. * A supported device to run this software: a [comma three](https://comma.ai/shop/products/three).
* One of [the 150+ supported cars](docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, and more. If your car is not supported, but has adaptive cruise control and lane keeping assist, it's likely able to run openpilot. * This software. The setup procedure of the comma three allows the user to enter a URL for custom software.
* A supported device to run this software. This can be a [comma two](https://comma.ai/shop/products/two), [comma three](https://comma.ai/shop/products/three), or if you like to experiment, a [Ubuntu computer with webcams](https://github.com/commaai/openpilot/tree/master/tools/webcam). The URL, openpilot.comma.ai will install the release version of openpilot. To install openpilot master, you can use installer.comma.ai/commaai/master, and replacing commaai with another GitHub username can install a fork.
* A way to connect to your car. With a comma two or three, you need only a [car harness](https://comma.ai/shop/products/car-harness). With an EON Gold or PC, you also need a [black panda](https://comma.ai/shop/products/panda). * One of [the 200+ supported cars](docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run openpilot.
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car.
We have detailed instructions for [how to install the device in a car](https://comma.ai/setup). We have detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
Running on PC Running on PC
------ ------
All of openpilot's services can run as normal on a PC, even without special hardware or a car. To develop or experiment with openpilot you can run openpilot on recorded or simulated data. All openpilot services can run as usual on a PC without requiring special hardware or a car. You can also run openpilot on recorded or simulated data to develop or experiment with openpilot.
With openpilot's tools you can plot logs, replay drives and watch the full-res camera streams. See [the tools README](tools/README.md) for more information. With openpilot's tools, you can plot logs, replay drives, and watch the full-res camera streams. See [the tools README](tools/README.md) for more information.
You can also run openpilot in simulation [with the CARLA simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine. The whole setup should only take a few minutes, but does require a decent GPU. You can also run openpilot in simulation [with the CARLA simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine. The whole setup should only take a few minutes but does require a decent GPU.
A PC running openpilot can also control your vehicle if it is connected to a [webcam](https://github.com/commaai/openpilot/tree/master/tools/webcam), a [black panda](https://comma.ai/shop/products/panda), and a [harness](https://comma.ai/shop/products/car-harness).
Community and Contributing Community and Contributing
------ ------
@ -76,8 +78,8 @@ By default, openpilot uploads the driving data to our servers. You can also acce
openpilot is open source software: the user is free to disable data collection if they wish to do so. openpilot is open source software: the user is free to disable data collection if they wish to do so.
openpilot logs the road facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs. openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
The driver facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded. The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data. By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
@ -85,11 +87,11 @@ Safety and Testing
---- ----
* openpilot observes ISO26262 guidelines, see [SAFETY.md](docs/SAFETY.md) for more details. * openpilot observes ISO26262 guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
* openpilot has software in the loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit. * openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details. * The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
* panda has software in the loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety). * panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
* Internally, we have a hardware in the loop Jenkins test suite that builds and unit tests the various processes. * Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
* panda has additional hardware in the loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile). * panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes. * We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
Directory Structure Directory Structure
@ -102,20 +104,25 @@ Directory Structure
├── panda # Code used to communicate on CAN ├── panda # Code used to communicate on CAN
├── third_party # External libraries ├── third_party # External libraries
├── pyextra # Extra python packages ├── pyextra # Extra python packages
└── system # Generic services
├── camerad # Driver to capture images from the camera sensors
├── clocksd # Broadcasts current time
├── hardware # Hardware abstraction classes
├── logcatd # systemd journal as a service
└── proclogd # Logs information from /proc
└── selfdrive # Code needed to drive the car └── selfdrive # Code needed to drive the car
├── assets # Fonts, images, and sounds for UI ├── assets # Fonts, images, and sounds for UI
├── athena # Allows communication with the app ├── athena # Allows communication with the app
├── boardd # Daemon to talk to the board ├── boardd # Daemon to talk to the board
├── camerad # Driver to capture images from the camera sensors
├── car # Car specific code to read states and control actuators ├── car # Car specific code to read states and control actuators
├── common # Shared C/C++ code for the daemons
├── controls # Planning and controls ├── controls # Planning and controls
├── debug # Tools to help you debug and do car ports ├── debug # Tools to help you debug and do car ports
├── locationd # Precise localization and vehicle parameter estimation ├── locationd # Precise localization and vehicle parameter estimation
├── logcatd # Android logcat as a service
├── loggerd # Logger and uploader of car data ├── loggerd # Logger and uploader of car data
├── manager # Daemon that starts/stops all other daemons as needed
├── modeld # Driving and monitoring model runners ├── modeld # Driving and monitoring model runners
├── proclogd # Logs information from proc ├── monitoring # Daemon to determine driver attention
├── navd # Turn-by-turn navigation
├── sensord # IMU interface code ├── sensord # IMU interface code
├── test # Unit tests, system tests, and a car simulator ├── test # Unit tests, system tests, and a car simulator
└── ui # The UI └── ui # The UI

@ -1,11 +1,120 @@
Version 0.8.14 (2022-0X-XX) Version 0.9.1 (2022-12-XX)
======================== ========================
* bigmodel! * Adjust alert volume using ambient noise level
* Removed driver monitoring timer resetting on interaction if face detected and distracted
* Chevrolet Bolt EV 2022-23 support thanks to JasonJShuler!
* Hyundai Tucson 2022-23 support
* Kia Sorento Plug-in Hybrid 2022 support thanks to sunnyhaibin!
Version 0.9.0 (2022-11-21)
========================
* New driving model
* Internal feature space information content increased tenfold during training to ~700 bits, which makes the model dramatically more accurate
* Less reliance on previous frames makes model more reactive and snappy
* Trained in new reprojective simulator
* Trained in 36 hours from scratch, compared to one week for previous releases
* Training now simulates both lateral and longitudinal behavior, which allows openpilot to slow down for turns, stop at traffic lights, and more in experimental mode
* Experimental driving mode
* End-to-end longitudinal control
* Stops for traffic lights and stop signs
* Slows down for turns
* openpilot defaults to chill mode, enable experimental mode in settings
* Driver monitoring updates
* New bigger model with added end-to-end distracted trigger
* Reduced false positives during driver calibration
* Self-tuning torque controller: learns parameters live for each car
* Torque controller used on all Toyota, Lexus, Hyundai, Kia, and Genesis models
* UI updates
* Matched speeds shown on car's dash
* Multi-language in navigation
* Improved update experience
* Border turns grey while overriding steering
* Bookmark events while driving; view them in comma connect
* New onroad visualization for experimental mode
* tools: new and improved cabana thanks to deanlee!
* Experimental longitudinal support for Volkswagen, CAN-FD Hyundai, and new GM models
* Genesis GV70 2022-23 support thanks to zunichky and sunnyhaibin!
* Hyundai Santa Cruz 2021-22 support thanks to sunnyhaibin!
* Kia Sportage 2023 support thanks to sunnyhaibin!
* Kia Sportage Hybrid 2023 support thanks to sunnyhaibin!
* Kia Stinger 2022 support thanks to sunnyhaibin!
Version 0.8.16 (2022-08-26)
========================
* New driving model
* Reduced turn cutting
* Auto-detect right hand drive setting with driver monitoring model
* Improved fan controller for comma three
* New translations
* Japanese thanks to cydia2020!
* Brazilian Portuguese thanks to AlexandreSato!
* Chevrolet Bolt EUV 2022-23 support thanks to JasonJShuler!
* Chevrolet Silverado 1500 2020-21 support thanks to JasonJShuler!
* GMC Sierra 1500 2020-21 support thanks to JasonJShuler!
* Hyundai Ioniq 5 2022 support thanks to sunnyhaibin!
* Hyundai Kona Electric 2022 support thanks to sunnyhaibin!
* Hyundai Tucson Hybrid 2022 support thanks to sunnyhaibin!
* Subaru Legacy 2020-22 support thanks to martinl!
* Subaru Outback 2020-22 support
Version 0.8.15 (2022-07-20)
========================
* New driving model
* Path planning uses end-to-end output instead of lane lines at all times
* Reduced ping pong
* Improved lane centering
* New lateral controller based on physical wheel torque model
* Much smoother control that's consistent across the speed range
* Effective feedforward that uses road roll
* Simplified tuning, all car-specific parameters can be derived from data
* Used on select Toyota and Hyundai models at first
* Significantly improved control on TSS-P Prius
* New driver monitoring model
* Bigger model, covering full interior view from driver camera
* Works with a wider variety of mounting angles
* 3x more unique comma three training data than previous
* Navigation improvements
* Speed limits shown while navigating
* Faster position fix by using raw GPS measurements
* UI updates
* Multilanguage support for settings and home screen
* New font
* Refreshed max speed design
* More consistent camera view perspective across cars
* Reduced power usage: device runs cooler and fan spins less
* AGNOS 5
* Support VSCode remote SSH target
* Support for delta updates to reduce data usage on future OS updates
* Chrysler ECU firmware fingerprinting thanks to realfast!
* Honda Civic 2022 support
* Hyundai Tucson 2021 support thanks to bluesforte!
* Kia EV6 2022 support
* Lexus NX Hybrid 2020 support thanks to AlexandreSato!
* Ram 1500 2019-21 support thanks to realfast!
Version 0.8.14 (2022-06-01)
========================
* New driving model
* Bigger model, using both of comma three's road-facing cameras
* Better at cut-in detection and tight turns
* New driver monitoring model
* Tweaked network structure to improve output resolution for DSP
* Fixed bug in quantization aware training to reduce quantizing errors
* Resulted in 7x less MSE and no more random biases at runtime
* Added toggle to disable disengaging on the accelerator pedal
* comma body support
* Audi RS3 support thanks to jyoung8607!
* Hyundai Ioniq Plug-in Hybrid 2019 support thanks to sunnyhaibin!
* Hyundai Tucson Diesel 2019 support thanks to sunnyhaibin!
* Toyota Alphard Hybrid 2021 support
* Toyota Avalon Hybrid 2022 support
* Toyota RAV4 2022 support
* Toyota RAV4 Hybrid 2022 support
Version 0.8.13 (2022-02-18) Version 0.8.13 (2022-02-18)
======================== ========================
* Improved driver monitoring * Improved driver monitoring
* Retuned driver pose learner for relaxed driving positions * Re-tuned driver pose learner for relaxed driving positions
* Added reliance on driving model to be more scene adaptive * Added reliance on driving model to be more scene adaptive
* Matched strictness between comma two and comma three * Matched strictness between comma two and comma three
* Improved performance in turns by compensating for the road bank angle * Improved performance in turns by compensating for the road bank angle
@ -151,7 +260,7 @@ Version 0.8.4 (2021-05-17)
* Delay controls start until system is ready * Delay controls start until system is ready
* Fuzzy car identification, enabled with Community Features toggle * Fuzzy car identification, enabled with Community Features toggle
* Localizer optimized for increased precision and less CPU usage * Localizer optimized for increased precision and less CPU usage
* Retuned lateral control to be more aggressive when model is confident * Re-tuned lateral control to be more aggressive when model is confident
* Toyota Mirai 2021 support * Toyota Mirai 2021 support
* Lexus NX 300 2020 support thanks to goesreallyfast! * Lexus NX 300 2020 support thanks to goesreallyfast!
* Volkswagen Atlas 2018-19 support thanks to jyoung8607! * Volkswagen Atlas 2018-19 support thanks to jyoung8607!
@ -316,7 +425,7 @@ Version 0.7 (2019-12-13)
* Improve GM longitudinal control: proper computations for 15Hz radar * Improve GM longitudinal control: proper computations for 15Hz radar
* Move GM port, Toyota with DSU removed, comma pedal in community features; toggle switch required * Move GM port, Toyota with DSU removed, comma pedal in community features; toggle switch required
* Remove upload over cellular toggle: only upload qlog and qcamera files if not on wifi * Remove upload over cellular toggle: only upload qlog and qcamera files if not on wifi
* Refactor Panda code towards ISO26262 and SIL2 compliancy * Refactor Panda code towards ISO26262 and SIL2 compliance
* Forward stock FCW for Honda Nidec * Forward stock FCW for Honda Nidec
* Volkswagen port now standard: comma Harness intercepts stock camera * Volkswagen port now standard: comma Harness intercepts stock camera

@ -1,5 +1,4 @@
import os import os
import shutil
import subprocess import subprocess
import sys import sys
import sysconfig import sysconfig
@ -7,11 +6,9 @@ import platform
import numpy as np import numpy as np
TICI = os.path.isfile('/TICI') TICI = os.path.isfile('/TICI')
Decider('MD5-timestamp') AGNOS = TICI
AddOption('--test', Decider('MD5-timestamp')
action='store_true',
help='build test files')
AddOption('--extras', AddOption('--extras',
action='store_true', action='store_true',
@ -52,14 +49,24 @@ AddOption('--no-thneed',
dest='no_thneed', dest='no_thneed',
help='avoid using thneed') help='avoid using thneed')
AddOption('--pc-thneed',
action='store_true',
dest='pc_thneed',
help='use thneed on pc')
AddOption('--no-test',
action='store_false',
dest='test',
default=os.path.islink(Dir('#laika/').abspath),
help='skip building test files')
real_arch = arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() real_arch = arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
if platform.system() == "Darwin": if platform.system() == "Darwin":
arch = "Darwin" arch = "Darwin"
if arch == "aarch64" and TICI: if arch == "aarch64" and AGNOS:
arch = "larch64" arch = "larch64"
USE_WEBCAM = os.getenv("USE_WEBCAM") is not None
lenv = { lenv = {
"PATH": os.environ['PATH'], "PATH": os.environ['PATH'],
@ -68,19 +75,14 @@ lenv = {
"ACADOS_SOURCE_DIR": Dir("#third_party/acados/include/acados").abspath, "ACADOS_SOURCE_DIR": Dir("#third_party/acados/include/acados").abspath,
"ACADOS_PYTHON_INTERFACE_PATH": Dir("#pyextra/acados_template").abspath, "ACADOS_PYTHON_INTERFACE_PATH": Dir("#pyextra/acados_template").abspath,
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer", "TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer"
} }
rpath = lenv["LD_LIBRARY_PATH"].copy() rpath = lenv["LD_LIBRARY_PATH"].copy()
if arch == "aarch64" or arch == "larch64": if arch == "larch64":
lenv["LD_LIBRARY_PATH"] += ['/data/data/com.termux/files/usr/lib'] lenv["LD_LIBRARY_PATH"] += ['/data/data/com.termux/files/usr/lib']
if arch == "aarch64":
# android
lenv["ANDROID_DATA"] = os.environ['ANDROID_DATA']
lenv["ANDROID_ROOT"] = os.environ['ANDROID_ROOT']
cpppath = [ cpppath = [
"#third_party/opencl/include", "#third_party/opencl/include",
] ]
@ -89,57 +91,49 @@ if arch == "aarch64" or arch == "larch64":
"/usr/local/lib", "/usr/local/lib",
"/usr/lib", "/usr/lib",
"/system/vendor/lib64", "/system/vendor/lib64",
"/system/comma/usr/lib",
f"#third_party/acados/{arch}/lib", f"#third_party/acados/{arch}/lib",
] ]
if arch == "larch64":
libpath += [ libpath += [
"#third_party/snpe/larch64", "#third_party/snpe/larch64",
"#third_party/libyuv/larch64/lib", "#third_party/libyuv/larch64/lib",
"/usr/lib/aarch64-linux-gnu" "/usr/lib/aarch64-linux-gnu"
] ]
cpppath += [
"#selfdrive/camerad/include",
]
cflags = ["-DQCOM2", "-mcpu=cortex-a57"] cflags = ["-DQCOM2", "-mcpu=cortex-a57"]
cxxflags = ["-DQCOM2", "-mcpu=cortex-a57"] cxxflags = ["-DQCOM2", "-mcpu=cortex-a57"]
rpath += ["/usr/local/lib"] rpath += ["/usr/local/lib"]
else:
rpath = []
libpath += [
"#third_party/snpe/aarch64",
"#third_party/libyuv/lib",
"/system/vendor/lib64"
]
cflags = ["-DQCOM", "-D_USING_LIBCXX", "-mcpu=cortex-a57"]
cxxflags = ["-DQCOM", "-D_USING_LIBCXX", "-mcpu=cortex-a57"]
else: else:
cflags = [] cflags = []
cxxflags = [] cxxflags = []
cpppath = [] cpppath = []
# MacOS
if arch == "Darwin": if arch == "Darwin":
if real_arch == "x86_64":
lenv["TERA_PATH"] = Dir("#").abspath + f"/third_party/acados/Darwin_x86_64/t_renderer"
brew_prefix = subprocess.check_output(['brew', '--prefix'], encoding='utf8').strip()
yuv_dir = "mac" if real_arch != "arm64" else "mac_arm64" yuv_dir = "mac" if real_arch != "arm64" else "mac_arm64"
libpath = [ libpath = [
f"#third_party/libyuv/{yuv_dir}/lib", f"#third_party/libyuv/{yuv_dir}/lib",
"/usr/local/lib", f"{brew_prefix}/lib",
"/opt/homebrew/lib", f"{brew_prefix}/Library",
"/usr/local/Homebrew/Library", f"{brew_prefix}/opt/openssl/lib",
"/usr/local/opt/openssl/lib", f"{brew_prefix}/Cellar",
"/opt/homebrew/opt/openssl/lib",
"/usr/local/Cellar",
f"#third_party/acados/{arch}/lib",
"/System/Library/Frameworks/OpenGL.framework/Libraries", "/System/Library/Frameworks/OpenGL.framework/Libraries",
] ]
if real_arch == "x86_64":
libpath.append(f"#third_party/acados/Darwin_x86_64/lib")
else:
libpath.append(f"#third_party/acados/{arch}/lib")
cflags += ["-DGL_SILENCE_DEPRECATION"] cflags += ["-DGL_SILENCE_DEPRECATION"]
cxxflags += ["-DGL_SILENCE_DEPRECATION"] cxxflags += ["-DGL_SILENCE_DEPRECATION"]
cpppath += [ cpppath += [
"/opt/homebrew/include", f"{brew_prefix}/include",
"/usr/local/include", f"{brew_prefix}/opt/openssl/include",
"/usr/local/opt/openssl/include",
"/opt/homebrew/opt/openssl/include"
] ]
# Linux 86_64
else: else:
libpath = [ libpath = [
"#third_party/acados/x86_64/lib", "#third_party/acados/x86_64/lib",
@ -147,7 +141,7 @@ else:
"#third_party/libyuv/x64/lib", "#third_party/libyuv/x64/lib",
"#third_party/mapbox-gl-native-qt/x86_64", "#third_party/mapbox-gl-native-qt/x86_64",
"#cereal", "#cereal",
"#selfdrive/common", "#common",
"/usr/lib", "/usr/lib",
"/usr/local/lib", "/usr/local/lib",
] ]
@ -155,7 +149,7 @@ else:
rpath += [ rpath += [
Dir("#third_party/snpe/x86_64-linux-clang").abspath, Dir("#third_party/snpe/x86_64-linux-clang").abspath,
Dir("#cereal").abspath, Dir("#cereal").abspath,
Dir("#selfdrive/common").abspath Dir("#common").abspath
] ]
if GetOption('asan'): if GetOption('asan'):
@ -173,8 +167,8 @@ if arch != "Darwin":
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"] ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
# Enable swaglog include in submodules # Enable swaglog include in submodules
cflags += ["-DSWAGLOG"] cflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
cxxflags += ["-DSWAGLOG"] cxxflags += ['-DSWAGLOG="\\"common/swaglog.h\\""']
env = Environment( env = Environment(
ENV=lenv, ENV=lenv,
@ -200,9 +194,7 @@ env = Environment(
"#third_party/acados/include/blasfeo/include", "#third_party/acados/include/blasfeo/include",
"#third_party/acados/include/hpipm/include", "#third_party/acados/include/hpipm/include",
"#third_party/catch2/include", "#third_party/catch2/include",
"#third_party/bzip2",
"#third_party/libyuv/include", "#third_party/libyuv/include",
"#third_party/openmax/include",
"#third_party/json11", "#third_party/json11",
"#third_party/curl/include", "#third_party/curl/include",
"#third_party/libgralloc/include", "#third_party/libgralloc/include",
@ -231,7 +223,7 @@ env = Environment(
"#third_party", "#third_party",
"#opendbc/can", "#opendbc/can",
"#selfdrive/boardd", "#selfdrive/boardd",
"#selfdrive/common", "#common",
], ],
CYTHONCFILESUFFIX=".cpp", CYTHONCFILESUFFIX=".cpp",
COMPILATIONDB_USE_ABSPATH=True, COMPILATIONDB_USE_ABSPATH=True,
@ -245,7 +237,7 @@ if GetOption('compile_db'):
env.CompilationDatabase('compile_commands.json') env.CompilationDatabase('compile_commands.json')
# Setup cache dir # Setup cache dir
cache_dir = '/data/scons_cache' if TICI else '/tmp/scons_cache' cache_dir = '/data/scons_cache' if AGNOS else '/tmp/scons_cache'
CacheDir(cache_dir) CacheDir(cache_dir)
Clean(["."], cache_dir) Clean(["."], cache_dir)
@ -261,6 +253,7 @@ if os.environ.get('SCONS_PROGRESS'):
SHARED = False SHARED = False
# TODO: this can probably be removed
def abspath(x): def abspath(x):
if arch == 'aarch64': if arch == 'aarch64':
pth = os.path.join("/data/pythonpath", x[0].path) pth = os.path.join("/data/pythonpath", x[0].path)
@ -270,7 +263,7 @@ def abspath(x):
# rpath works elsewhere # rpath works elsewhere
return x[0].path.rsplit("/", 1)[1][:-3] return x[0].path.rsplit("/", 1)[1][:-3]
# Cython build enviroment # Cython build environment
py_include = sysconfig.get_paths()['include'] py_include = sysconfig.get_paths()['include']
envCython = env.Clone() envCython = env.Clone()
envCython["CPPPATH"] += [py_include, np.get_include()] envCython["CPPPATH"] += [py_include, np.get_include()]
@ -289,9 +282,7 @@ Export('envCython')
# Qt build environment # Qt build environment
qt_env = env.Clone() qt_env = env.Clone()
qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia", "Quick", "Qml", "QuickWidgets", "Location", "Positioning"] qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia", "Quick", "Qml", "QuickWidgets", "Location", "Positioning", "DBus"]
if arch != "aarch64":
qt_modules += ["DBus"]
qt_libs = [] qt_libs = []
if arch == "Darwin": if arch == "Darwin":
@ -306,22 +297,16 @@ if arch == "Darwin":
qt_env["LINKFLAGS"] += ["-F" + os.path.join(qt_env['QTDIR'], "lib")] qt_env["LINKFLAGS"] += ["-F" + os.path.join(qt_env['QTDIR'], "lib")]
qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"] qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"]
qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin")) qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin"))
elif arch == "aarch64":
qt_env['QTDIR'] = "/system/comma/usr"
qt_dirs = [
f"/system/comma/usr/include/qt",
]
qt_dirs += [f"/system/comma/usr/include/qt/Qt{m}" for m in qt_modules]
qt_libs = [f"Qt5{m}" for m in qt_modules]
qt_libs += ['EGL', 'GLESv3', 'c++_shared']
else: else:
qt_env['QTDIR'] = "/usr" qt_install_prefix = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_PREFIX'], encoding='utf8').strip()
qt_install_headers = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_HEADERS'], encoding='utf8').strip()
qt_env['QTDIR'] = qt_install_prefix
qt_dirs = [ qt_dirs = [
f"/usr/include/{real_arch}-linux-gnu/qt5", f"{qt_install_headers}",
f"/usr/include/{real_arch}-linux-gnu/qt5/QtGui/5.12.8/QtGui", f"{qt_install_headers}/QtGui/5.12.8/QtGui",
] ]
qt_dirs += [f"/usr/include/{real_arch}-linux-gnu/qt5/Qt{m}" for m in qt_modules] qt_dirs += [f"{qt_install_headers}/Qt{m}" for m in qt_modules]
qt_libs = [f"Qt5{m}" for m in qt_modules] qt_libs = [f"Qt5{m}" for m in qt_modules]
if arch == "larch64": if arch == "larch64":
@ -345,6 +330,7 @@ qt_flags = [
qt_env['CXXFLAGS'] += qt_flags qt_env['CXXFLAGS'] += qt_flags
qt_env['LIBPATH'] += ['#selfdrive/ui'] qt_env['LIBPATH'] += ['#selfdrive/ui']
qt_env['LIBS'] = qt_libs qt_env['LIBS'] = qt_libs
qt_env['QT_MOCHPREFIX'] = cache_dir + '/moc_files/moc_'
if GetOption("clazy"): if GetOption("clazy"):
checks = [ checks = [
@ -357,16 +343,16 @@ if GetOption("clazy"):
qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0] qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0]
qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks) qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks)
Export('env', 'qt_env', 'arch', 'real_arch', 'SHARED', 'USE_WEBCAM') Export('env', 'qt_env', 'arch', 'real_arch', 'SHARED')
SConscript(['selfdrive/common/SConscript']) SConscript(['common/SConscript'])
Import('_common', '_gpucommon', '_gpu_libs') Import('_common', '_gpucommon')
if SHARED: if SHARED:
common, gpucommon = abspath(common), abspath(gpucommon) common, gpucommon = abspath(common), abspath(gpucommon)
else: else:
common = [_common, 'json11'] common = [_common, 'json11']
gpucommon = [_gpucommon] + _gpu_libs gpucommon = [_gpucommon]
Export('common', 'gpucommon') Export('common', 'gpucommon')
@ -384,40 +370,56 @@ Export('cereal', 'messaging', 'visionipc')
# Build rednose library and ekf models # Build rednose library and ekf models
rednose_deps = [
"#selfdrive/locationd/models/constants.py",
"#selfdrive/locationd/models/gnss_helpers.py",
]
rednose_config = { rednose_config = {
'generated_folder': '#selfdrive/locationd/models/generated', 'generated_folder': '#selfdrive/locationd/models/generated',
'to_build': { 'to_build': {
'live': ('#selfdrive/locationd/models/live_kf.py', True, ['live_kf_constants.h']), 'gnss': ('#selfdrive/locationd/models/gnss_kf.py', True, [], rednose_deps),
'car': ('#selfdrive/locationd/models/car_kf.py', True, []), 'live': ('#selfdrive/locationd/models/live_kf.py', True, ['live_kf_constants.h'], rednose_deps),
'car': ('#selfdrive/locationd/models/car_kf.py', True, [], rednose_deps),
}, },
} }
if arch not in ["aarch64", "larch64"]: if arch != "larch64":
rednose_config['to_build'].update({ rednose_config['to_build'].update({
'gnss': ('#selfdrive/locationd/models/gnss_kf.py', True, []), 'loc_4': ('#selfdrive/locationd/models/loc_kf.py', True, [], rednose_deps),
'loc_4': ('#selfdrive/locationd/models/loc_kf.py', True, []), 'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', False, [], []),
'pos_computer_4': ('#rednose/helpers/lst_sq_computer.py', False, []), 'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', False, [], []),
'pos_computer_5': ('#rednose/helpers/lst_sq_computer.py', False, []), 'feature_handler_5': ('#rednose/helpers/feature_handler.py', False, [], []),
'feature_handler_5': ('#rednose/helpers/feature_handler.py', False, []), 'lane': ('#xx/pipeline/lib/ekf/lane_kf.py', True, [], rednose_deps),
'lane': ('#xx/pipeline/lib/ekf/lane_kf.py', True, []),
}) })
Export('rednose_config') Export('rednose_config')
SConscript(['rednose/SConscript']) SConscript(['rednose/SConscript'])
# Build system services
SConscript([
'system/camerad/SConscript',
'system/clocksd/SConscript',
'system/proclogd/SConscript',
])
if arch != "Darwin":
SConscript(['system/logcatd/SConscript'])
# Build openpilot # Build openpilot
SConscript(['cereal/SConscript']) # build submodules
SConscript(['panda/board/SConscript']) SConscript([
SConscript(['opendbc/can/SConscript']) 'body/board/SConscript',
'cereal/SConscript',
'opendbc/can/SConscript',
'panda/SConscript',
])
SConscript(['third_party/SConscript']) SConscript(['third_party/SConscript'])
SConscript(['common/SConscript'])
SConscript(['common/kalman/SConscript']) SConscript(['common/kalman/SConscript'])
SConscript(['common/transformations/SConscript']) SConscript(['common/transformations/SConscript'])
SConscript(['selfdrive/camerad/SConscript'])
SConscript(['selfdrive/modeld/SConscript']) SConscript(['selfdrive/modeld/SConscript'])
SConscript(['selfdrive/controls/lib/cluster/SConscript']) SConscript(['selfdrive/controls/lib/cluster/SConscript'])
@ -425,20 +427,20 @@ SConscript(['selfdrive/controls/lib/lateral_mpc_lib/SConscript'])
SConscript(['selfdrive/controls/lib/longitudinal_mpc_lib/SConscript']) SConscript(['selfdrive/controls/lib/longitudinal_mpc_lib/SConscript'])
SConscript(['selfdrive/boardd/SConscript']) SConscript(['selfdrive/boardd/SConscript'])
SConscript(['selfdrive/proclogd/SConscript'])
SConscript(['selfdrive/clocksd/SConscript'])
SConscript(['selfdrive/loggerd/SConscript']) SConscript(['selfdrive/loggerd/SConscript'])
SConscript(['selfdrive/locationd/SConscript']) SConscript(['selfdrive/locationd/SConscript'])
SConscript(['selfdrive/sensord/SConscript']) SConscript(['selfdrive/sensord/SConscript'])
SConscript(['selfdrive/ui/SConscript']) SConscript(['selfdrive/ui/SConscript'])
SConscript(['selfdrive/navd/SConscript'])
if arch != "Darwin": if arch in ['x86_64', 'Darwin'] or GetOption('extras'):
SConscript(['selfdrive/logcatd/SConscript']) SConscript(['tools/replay/SConscript'])
if GetOption('test'): opendbc = abspath([File('opendbc/can/libdbc.so')])
SConscript('panda/tests/safety/SConscript') Export('opendbc')
SConscript(['tools/cabana/SConscript'])
external_sconscript = GetOption('external_sconscript') external_sconscript = GetOption('external_sconscript')
if external_sconscript: if external_sconscript:

@ -0,0 +1,5 @@
# Security Policy
## Reporting a Vulnerability
Suspected vulnerabilities can be reported to both `adeeb@comma.ai` and `security@comma.ai`.

@ -0,0 +1 @@
Subproject commit dc780f858c1ef641471d09b72569e199e3e10acb

@ -1 +1 @@
Subproject commit 32eae5e80deb4d9b0f1422c1d0f5846e5b26144a Subproject commit 7765176413c0bb14143fe2469d5390ea0ea61a1e

@ -1,4 +1,33 @@
Import('envCython', 'common') Import('env', 'envCython', 'arch', 'SHARED')
if SHARED:
fxn = env.SharedLibrary
else:
fxn = env.Library
common_libs = [
'params.cc',
'statlog.cc',
'swaglog.cc',
'util.cc',
'gpio.cc',
'i2c.cc',
'watchdog.cc',
]
_common = fxn('common', common_libs, LIBS="json11")
files = [
'clutil.cc',
]
_gpucommon = fxn('gpucommon', files)
Export('_common', '_gpucommon')
if GetOption('test'):
env.Program('tests/test_util', ['tests/test_util.cc'], LIBS=[_common])
env.Program('tests/test_swaglog', ['tests/test_swaglog.cc'], LIBS=[_common, 'json11', 'zmq', 'pthread'])
# Cython
envCython.Program('clock.so', 'clock.pyx') envCython.Program('clock.so', 'clock.pyx')
envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [common, 'zmq']) envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq', 'json11'])

@ -3,7 +3,7 @@ import os
import requests import requests
from datetime import datetime, timedelta from datetime import datetime, timedelta
from common.basedir import PERSIST from common.basedir import PERSIST
from selfdrive.version import get_version from system.version import get_version
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com') API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
@ -22,13 +22,13 @@ class Api():
def request(self, method, endpoint, timeout=None, access_token=None, **params): def request(self, method, endpoint, timeout=None, access_token=None, **params):
return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params) return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
def get_token(self): def get_token(self, expiry_hours=1):
now = datetime.utcnow() now = datetime.utcnow()
payload = { payload = {
'identity': self.dongle_id, 'identity': self.dongle_id,
'nbf': now, 'nbf': now,
'iat': now, 'iat': now,
'exp': now + timedelta(hours=1) 'exp': now + timedelta(hours=expiry_hours)
} }
token = jwt.encode(payload, self.private_key, algorithm='RS256') token = jwt.encode(payload, self.private_key, algorithm='RS256')
if isinstance(token, bytes): if isinstance(token, bytes):

@ -1,7 +1,7 @@
import os import os
from pathlib import Path from pathlib import Path
from selfdrive.hardware import PC from system.hardware import PC
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")) BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))

@ -1,10 +1,10 @@
#include "selfdrive/common/clutil.h" #include "common/clutil.h"
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include "selfdrive/common/util.h" #include "common/util.h"
namespace { // helper functions namespace { // helper functions
@ -78,7 +78,8 @@ cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const ch
} }
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args) { cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args) {
cl_program prg = CL_CHECK_ERR(clCreateProgramWithSource(ctx, 1, (const char*[]){src.c_str()}, NULL, &err)); const char *csrc = src.c_str();
cl_program prg = CL_CHECK_ERR(clCreateProgramWithSource(ctx, 1, &csrc, NULL, &err));
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) { if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
cl_print_build_errors(prg, device_id); cl_print_build_errors(prg, device_id);
assert(0); assert(0);
@ -87,7 +88,7 @@ cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const
} }
cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args) { cl_program cl_program_from_binary(cl_context ctx, cl_device_id device_id, const uint8_t* binary, size_t length, const char* args) {
cl_program prg = CL_CHECK_ERR(clCreateProgramWithBinary(ctx, 1, &device_id, &length, (const uint8_t*[]){binary}, NULL, &err)); cl_program prg = CL_CHECK_ERR(clCreateProgramWithBinary(ctx, 1, &device_id, &length, &binary, NULL, &err));
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) { if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
cl_print_build_errors(prg, device_id); cl_print_build_errors(prg, device_id);
assert(0); assert(0);

@ -0,0 +1,19 @@
import numpy as np
class Conversions:
# Speed
MPH_TO_KPH = 1.609344
KPH_TO_MPH = 1. / MPH_TO_KPH
MS_TO_KPH = 3.6
KPH_TO_MS = 1. / MS_TO_KPH
MS_TO_MPH = MS_TO_KPH * KPH_TO_MPH
MPH_TO_MS = MPH_TO_KPH * KPH_TO_MS
MS_TO_KNOTS = 1.9438
KNOTS_TO_MS = 1. / MS_TO_KNOTS
# Angle
DEG_TO_RAD = np.pi / 180.
RAD_TO_DEG = 1. / DEG_TO_RAD
# Mass
LB_TO_KG = 0.453592

@ -81,25 +81,12 @@ def _get_fileobject_func(writer, temp_dir):
return writer.get_fileobject(dir=temp_dir) return writer.get_fileobject(dir=temp_dir)
return _get_fileobject return _get_fileobject
def monkeypatch_os_link():
# This is neccesary on EON/C2, where os.link is patched out of python
if not hasattr(os, 'link'):
from cffi import FFI
ffi = FFI()
ffi.cdef("int link(const char *oldpath, const char *newpath);")
libc = ffi.dlopen(None)
def link(src, dest):
return libc.link(src.encode(), dest.encode())
os.link = link
def atomic_write_on_fs_tmp(path, **kwargs): def atomic_write_on_fs_tmp(path, **kwargs):
"""Creates an atomic writer using a temporary file in a temporary directory """Creates an atomic writer using a temporary file in a temporary directory
on the same filesystem as path. on the same filesystem as path.
""" """
# TODO(mgraczyk): This use of AtomicWriter relies on implementation details to set the temp # TODO(mgraczyk): This use of AtomicWriter relies on implementation details to set the temp
# directory. # directory.
monkeypatch_os_link()
writer = AtomicWriter(path, **kwargs) writer = AtomicWriter(path, **kwargs)
return writer._open(_get_fileobject_func(writer, get_tmpdir_on_same_filesystem(path))) return writer._open(_get_fileobject_func(writer, get_tmpdir_on_same_filesystem(path)))
@ -108,6 +95,5 @@ def atomic_write_in_dir(path, **kwargs):
"""Creates an atomic writer using a temporary file in the same directory """Creates an atomic writer using a temporary file in the same directory
as the destination file. as the destination file.
""" """
monkeypatch_os_link()
writer = AtomicWriter(path, **kwargs) writer = AtomicWriter(path, **kwargs)
return writer._open(_get_fileobject_func(writer, os.path.dirname(path))) return writer._open(_get_fileobject_func(writer, os.path.dirname(path)))

@ -0,0 +1,65 @@
#include "common/gpio.h"
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <linux/gpio.h>
#include <sys/ioctl.h>
#include "common/util.h"
#include "common/swaglog.h"
int gpio_init(int pin_nr, bool output) {
char pin_dir_path[50];
int pin_dir_path_len = snprintf(pin_dir_path, sizeof(pin_dir_path),
"/sys/class/gpio/gpio%d/direction", pin_nr);
if(pin_dir_path_len <= 0) {
return -1;
}
const char *value = output ? "out" : "in";
return util::write_file(pin_dir_path, (void*)value, strlen(value));
}
int gpio_set(int pin_nr, bool high) {
char pin_val_path[50];
int pin_val_path_len = snprintf(pin_val_path, sizeof(pin_val_path),
"/sys/class/gpio/gpio%d/value", pin_nr);
if(pin_val_path_len <= 0) {
return -1;
}
return util::write_file(pin_val_path, (void*)(high ? "1" : "0"), 1);
}
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
// Assumed that all interrupt pins are unexported and rights are given to
// read from gpiochip0.
std::string gpiochip_path = "/dev/gpiochip" + std::to_string(gpiochiop_id);
int fd = open(gpiochip_path.c_str(), O_RDONLY);
if (fd < 0) {
LOGE("Error opening gpiochip0 fd")
return -1;
}
// Setup event
struct gpioevent_request rq;
rq.lineoffset = pin_nr;
rq.handleflags = GPIOHANDLE_REQUEST_INPUT;
/* Requesting both edges as the data ready pulse from the lsm6ds sensor is
very short(75us) and is mostly detected as falling edge instead of rising.
So if it is detected as rising the following falling edge is skipped. */
rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
strncpy(rq.consumer_label, consumer_label, std::size(rq.consumer_label) - 1);
int ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq);
if (ret == -1) {
LOGE("Unable to get line event from ioctl : %s", strerror(errno));
close(fd);
return -1;
}
close(fd);
return rq.fd;
}

@ -8,6 +8,11 @@
#define GPIO_UBLOX_PWR_EN 34 #define GPIO_UBLOX_PWR_EN 34
#define GPIO_STM_RST_N 124 #define GPIO_STM_RST_N 124
#define GPIO_STM_BOOT0 134 #define GPIO_STM_BOOT0 134
#define GPIO_BMX_ACCEL_INT 21
#define GPIO_BMX_GYRO_INT 23
#define GPIO_BMX_MAGN_INT 87
#define GPIO_LSM_INT 84
#define GPIOCHIP_INT 0
#else #else
#define GPIO_HUB_RST_N 0 #define GPIO_HUB_RST_N 0
#define GPIO_UBLOX_RST_N 0 #define GPIO_UBLOX_RST_N 0
@ -15,7 +20,14 @@
#define GPIO_UBLOX_PWR_EN 0 #define GPIO_UBLOX_PWR_EN 0
#define GPIO_STM_RST_N 0 #define GPIO_STM_RST_N 0
#define GPIO_STM_BOOT0 0 #define GPIO_STM_BOOT0 0
#define GPIO_BMX_ACCEL_INT 0
#define GPIO_BMX_GYRO_INT 0
#define GPIO_BMX_MAGN_INT 0
#define GPIO_LSM_INT 0
#define GPIOCHIP_INT 0
#endif #endif
int gpio_init(int pin_nr, bool output); int gpio_init(int pin_nr, bool output);
int gpio_set(int pin_nr, bool high); int gpio_set(int pin_nr, bool high);
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr);

@ -1,14 +1,25 @@
def gpio_init(pin, output): from typing import Optional
def gpio_init(pin: int, output: bool) -> None:
try: try:
with open(f"/sys/class/gpio/gpio{pin}/direction", 'wb') as f: with open(f"/sys/class/gpio/gpio{pin}/direction", 'wb') as f:
f.write(b"out" if output else b"in") f.write(b"out" if output else b"in")
except Exception as e: except Exception as e:
print(f"Failed to set gpio {pin} direction: {e}") print(f"Failed to set gpio {pin} direction: {e}")
def gpio_set(pin: int, high: bool) -> None:
def gpio_set(pin, high):
try: try:
with open(f"/sys/class/gpio/gpio{pin}/value", 'wb') as f: with open(f"/sys/class/gpio/gpio{pin}/value", 'wb') as f:
f.write(b"1" if high else b"0") f.write(b"1" if high else b"0")
except Exception as e: except Exception as e:
print(f"Failed to set gpio {pin} value: {e}") print(f"Failed to set gpio {pin} value: {e}")
def gpio_read(pin: int) -> Optional[bool]:
val = None
try:
with open(f"/sys/class/gpio/gpio{pin}/value", 'rb') as f:
val = bool(int(f.read().strip()))
except Exception as e:
print(f"Failed to set gpio {pin} value: {e}")
return val

@ -1,4 +1,4 @@
#include "selfdrive/common/i2c.h" #include "common/i2c.h"
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -8,9 +8,9 @@
#include <cstdio> #include <cstdio>
#include <stdexcept> #include <stdexcept>
#include "selfdrive/common/util.h" #include "common/util.h"
#include "selfdrive/common/swaglog.h" #include "common/swaglog.h"
#include "selfdrive/common/util.h" #include "common/util.h"
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)

@ -3,6 +3,7 @@ import os
import sys import sys
import copy import copy
import json import json
import time
import uuid import uuid
import socket import socket
import logging import logging
@ -11,6 +12,8 @@ from threading import local
from collections import OrderedDict from collections import OrderedDict
from contextlib import contextmanager from contextlib import contextmanager
LOG_TIMESTAMPS = "LOG_TIMESTAMPS" in os.environ
def json_handler(obj): def json_handler(obj):
# if isinstance(obj, (datetime.date, datetime.time)): # if isinstance(obj, (datetime.date, datetime.time)):
# return obj.isoformat() # return obj.isoformat()
@ -163,6 +166,15 @@ class SwagLogger(logging.Logger):
else: else:
self.info(evt) self.info(evt)
def timestamp(self, event_name):
if LOG_TIMESTAMPS:
t = time.monotonic()
tstp = NiceOrderedDict()
tstp['timestamp'] = NiceOrderedDict()
tstp['timestamp']["event"] = event_name
tstp['timestamp']["time"] = t*1e9
self.debug(tstp)
def findCaller(self, stack_info=False, stacklevel=1): def findCaller(self, stack_info=False, stacklevel=1):
""" """
Find the stack frame of the caller so that we can note the source Find the stack frame of the caller so that we can note the source

@ -1,48 +0,0 @@
from typing import List
HTML_REPLACEMENTS = [
(r'&', r'&amp;'),
(r'"', r'&quot;'),
]
def parse_markdown(text: str, tab_length: int = 2) -> str:
lines = text.split("\n")
output: List[str] = []
list_level = 0
def end_outstanding_lists(level: int, end_level: int) -> int:
while level > end_level:
level -= 1
output.append("</ul>")
if level > 0:
output.append("</li>")
return end_level
for i, line in enumerate(lines):
if i + 1 < len(lines) and lines[i + 1].startswith("==="): # heading
output.append(f"<h1>{line}</h1>")
elif line.startswith("==="):
pass
elif line.lstrip().startswith("* "): # list
line_level = 1 + line.count(" " * tab_length, 0, line.index("*"))
if list_level >= line_level:
list_level = end_outstanding_lists(list_level, line_level)
else:
list_level += 1
if list_level > 1:
output[-1] = output[-1].replace("</li>", "")
output.append("<ul>")
output.append(f"<li>{line.replace('*', '', 1).lstrip()}</li>")
else:
list_level = end_outstanding_lists(list_level, 0)
if len(line) > 0:
output.append(line)
end_outstanding_lists(list_level, 0)
output_str = "\n".join(output) + "\n"
for (fr, to) in HTML_REPLACEMENTS:
output_str = output_str.replace(fr, to)
return output_str

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <array> #include <array>
#include "selfdrive/common/mat.h" #include "common/mat.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
const int TRAJECTORY_SIZE = 33; const int TRAJECTORY_SIZE = 33;
const int LAT_MPC_N = 16; const int LAT_MPC_N = 16;
@ -24,19 +24,7 @@ constexpr auto T_IDXS_FLOAT = build_idxs<float, TRAJECTORY_SIZE>(10.0);
constexpr auto X_IDXS = build_idxs<double, TRAJECTORY_SIZE>(192.0); constexpr auto X_IDXS = build_idxs<double, TRAJECTORY_SIZE>(192.0);
constexpr auto X_IDXS_FLOAT = build_idxs<float, TRAJECTORY_SIZE>(192.0); constexpr auto X_IDXS_FLOAT = build_idxs<float, TRAJECTORY_SIZE>(192.0);
const int TICI_CAM_WIDTH = 1928; const mat3 fcam_intrinsic_matrix = (mat3){{2648.0, 0.0, 1928.0 / 2,
namespace tici_dm_crop {
const int x_offset = -72;
const int y_offset = -144;
const int width = 954;
};
const mat3 fcam_intrinsic_matrix =
Hardware::EON() ? (mat3){{910., 0., 1164.0 / 2,
0., 910., 874.0 / 2,
0., 0., 1.}}
: (mat3){{2648.0, 0.0, 1928.0 / 2,
0.0, 2648.0, 1208.0 / 2, 0.0, 2648.0, 1208.0 / 2,
0.0, 0.0, 1.0}}; 0.0, 0.0, 1.0}};
@ -46,12 +34,13 @@ const mat3 ecam_intrinsic_matrix = (mat3){{567.0, 0.0, 1928.0 / 2,
0.0, 567.0, 1208.0 / 2, 0.0, 567.0, 1208.0 / 2,
0.0, 0.0, 1.0}}; 0.0, 0.0, 1.0}};
static inline mat3 get_model_yuv_transform(bool bayer = true) { static inline mat3 get_model_yuv_transform() {
float db_s = Hardware::EON() ? 0.5 : 1.0; // debayering does a 2x downscale on EON float db_s = 1.0;
const mat3 transform = (mat3){{ const mat3 transform = (mat3){{
1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 1.0 0.0, 0.0, 1.0
}}; }};
return bayer ? transform_scale_buffer(transform, db_s) : transform; // Can this be removed since scale is 1?
return transform_scale_buffer(transform, db_s);
} }

@ -1,14 +1,15 @@
#include "selfdrive/common/params.h" #include "common/params.h"
#include <dirent.h> #include <dirent.h>
#include <sys/file.h> #include <sys/file.h>
#include <algorithm>
#include <csignal> #include <csignal>
#include <unordered_map> #include <unordered_map>
#include "selfdrive/common/swaglog.h" #include "common/swaglog.h"
#include "selfdrive/common/util.h" #include "common/util.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
namespace { namespace {
@ -60,9 +61,9 @@ bool create_params_path(const std::string &param_path, const std::string &key_pa
return true; return true;
} }
std::string ensure_params_path(const std::string &path = {}) { std::string ensure_params_path(const std::string &prefix, const std::string &path = {}) {
std::string params_path = path.empty() ? Path::params() : path; std::string params_path = path.empty() ? Path::params() : path;
if (!create_params_path(params_path, params_path + "/d")) { if (!create_params_path(params_path, params_path + prefix)) {
throw std::runtime_error(util::string_format("Failed to ensure params path, errno=%d", errno)); throw std::runtime_error(util::string_format("Failed to ensure params path, errno=%d", errno));
} }
return params_path; return params_path;
@ -84,27 +85,32 @@ private:
std::unordered_map<std::string, uint32_t> keys = { std::unordered_map<std::string, uint32_t> keys = {
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG}, {"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
{"AssistNowToken", PERSISTENT},
{"AthenadPid", PERSISTENT}, {"AthenadPid", PERSISTENT},
{"AthenadUploadQueue", PERSISTENT}, {"AthenadUploadQueue", PERSISTENT},
{"CalibrationParams", PERSISTENT}, {"CalibrationParams", PERSISTENT},
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
{"CarBatteryCapacity", PERSISTENT}, {"CarBatteryCapacity", PERSISTENT},
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"CarParamsCache", CLEAR_ON_MANAGER_START}, {"CarParamsCache", CLEAR_ON_MANAGER_START},
{"CarParamsPersistent", PERSISTENT},
{"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"CellularUnmetered", PERSISTENT},
{"CompletedTrainingVersion", PERSISTENT}, {"CompletedTrainingVersion", PERSISTENT},
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"DashcamOverride", PERSISTENT},
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"DisablePowerDown", PERSISTENT}, {"DisablePowerDown", PERSISTENT},
{"DisableRadar_Allow", PERSISTENT}, {"ExperimentalMode", PERSISTENT},
{"DisableRadar", PERSISTENT}, // WARNING: THIS DISABLES AEB {"ExperimentalModeConfirmed", PERSISTENT},
{"ExperimentalLongitudinalEnabled", PERSISTENT}, // WARNING: THIS MAY DISABLE AEB
{"DisableUpdates", PERSISTENT}, {"DisableUpdates", PERSISTENT},
{"DisengageOnAccelerator", PERSISTENT},
{"DongleId", PERSISTENT}, {"DongleId", PERSISTENT},
{"DoReboot", CLEAR_ON_MANAGER_START}, {"DoReboot", CLEAR_ON_MANAGER_START},
{"DoShutdown", CLEAR_ON_MANAGER_START}, {"DoShutdown", CLEAR_ON_MANAGER_START},
{"DoUninstall", CLEAR_ON_MANAGER_START}, {"DoUninstall", CLEAR_ON_MANAGER_START},
{"EnableWideCamera", CLEAR_ON_MANAGER_START},
{"EndToEndToggle", PERSISTENT},
{"ForcePowerDown", CLEAR_ON_MANAGER_START}, {"ForcePowerDown", CLEAR_ON_MANAGER_START},
{"GitBranch", PERSISTENT}, {"GitBranch", PERSISTENT},
{"GitCommit", PERSISTENT}, {"GitCommit", PERSISTENT},
@ -113,6 +119,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"GithubUsername", PERSISTENT}, {"GithubUsername", PERSISTENT},
{"GitRemote", PERSISTENT}, {"GitRemote", PERSISTENT},
{"GsmApn", PERSISTENT}, {"GsmApn", PERSISTENT},
{"GsmMetered", PERSISTENT},
{"GsmRoaming", PERSISTENT}, {"GsmRoaming", PERSISTENT},
{"HardwareSerial", PERSISTENT}, {"HardwareSerial", PERSISTENT},
{"HasAcceptedTerms", PERSISTENT}, {"HasAcceptedTerms", PERSISTENT},
@ -124,31 +131,35 @@ std::unordered_map<std::string, uint32_t> keys = {
{"IsMetric", PERSISTENT}, {"IsMetric", PERSISTENT},
{"IsOffroad", CLEAR_ON_MANAGER_START}, {"IsOffroad", CLEAR_ON_MANAGER_START},
{"IsOnroad", PERSISTENT}, {"IsOnroad", PERSISTENT},
{"IsRHD", PERSISTENT}, {"IsRhdDetected", PERSISTENT},
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START}, {"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
{"IsUpdateAvailable", CLEAR_ON_MANAGER_START}, {"IsUpdateAvailable", CLEAR_ON_MANAGER_START},
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"LaikadEphemeris", PERSISTENT | DONT_LOG},
{"LanguageSetting", PERSISTENT},
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START}, {"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
{"LastGPSPosition", PERSISTENT}, {"LastGPSPosition", PERSISTENT},
{"LastManagerExitReason", CLEAR_ON_MANAGER_START}, {"LastManagerExitReason", CLEAR_ON_MANAGER_START},
{"LastPeripheralPandaType", PERSISTENT},
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START}, {"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
{"LastSystemShutdown", CLEAR_ON_MANAGER_START}, {"LastSystemShutdown", CLEAR_ON_MANAGER_START},
{"LastUpdateException", PERSISTENT}, {"LastUpdateException", CLEAR_ON_MANAGER_START},
{"LastUpdateTime", PERSISTENT}, {"LastUpdateTime", PERSISTENT},
{"LiveParameters", PERSISTENT}, {"LiveParameters", PERSISTENT},
{"LiveTorqueCarParams", PERSISTENT},
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
{"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"NavDestination", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"NavSettingTime24h", PERSISTENT}, {"NavSettingTime24h", PERSISTENT},
{"NavSettingLeftSide", PERSISTENT},
{"NavdRender", PERSISTENT}, {"NavdRender", PERSISTENT},
{"OpenpilotEnabledToggle", PERSISTENT}, {"OpenpilotEnabledToggle", PERSISTENT},
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"PandaSignatures", CLEAR_ON_MANAGER_START}, {"PandaSignatures", CLEAR_ON_MANAGER_START},
{"Passive", PERSISTENT}, {"Passive", PERSISTENT},
{"PrimeRedirected", PERSISTENT},
{"PrimeType", PERSISTENT}, {"PrimeType", PERSISTENT},
{"RecordFront", PERSISTENT}, {"RecordFront", PERSISTENT},
{"RecordFrontLock", PERSISTENT}, // for the internal fleet {"RecordFrontLock", PERSISTENT}, // for the internal fleet
{"ReleaseNotes", PERSISTENT}, {"ReplayControlsState", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"ShouldDoUpdate", CLEAR_ON_MANAGER_START}, {"ShouldDoUpdate", CLEAR_ON_MANAGER_START},
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF}, {"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_OFF},
{"SshEnabled", PERSISTENT}, {"SshEnabled", PERSISTENT},
@ -156,16 +167,26 @@ std::unordered_map<std::string, uint32_t> keys = {
{"TermsVersion", PERSISTENT}, {"TermsVersion", PERSISTENT},
{"Timezone", PERSISTENT}, {"Timezone", PERSISTENT},
{"TrainingVersion", PERSISTENT}, {"TrainingVersion", PERSISTENT},
{"UbloxAvailable", PERSISTENT},
{"UpdateAvailable", CLEAR_ON_MANAGER_START}, {"UpdateAvailable", CLEAR_ON_MANAGER_START},
{"UpdateFailedCount", CLEAR_ON_MANAGER_START}, {"UpdateFailedCount", CLEAR_ON_MANAGER_START},
{"UpdaterState", CLEAR_ON_MANAGER_START},
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
{"UpdaterAvailableBranches", CLEAR_ON_MANAGER_START},
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
{"Version", PERSISTENT}, {"Version", PERSISTENT},
{"VisionRadarToggle", PERSISTENT}, {"VisionRadarToggle", PERSISTENT},
{"WideCameraOnly", PERSISTENT},
{"ApiCache_Device", PERSISTENT}, {"ApiCache_Device", PERSISTENT},
{"ApiCache_DriveStats", PERSISTENT}, {"ApiCache_DriveStats", PERSISTENT},
{"ApiCache_NavDestinations", PERSISTENT}, {"ApiCache_NavDestinations", PERSISTENT},
{"ApiCache_Owner", PERSISTENT}, {"ApiCache_Owner", PERSISTENT},
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
{"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON}, {"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"Offroad_ChargeDisabled", CLEAR_ON_MANAGER_START },
{"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START}, {"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
{"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START}, {"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
{"Offroad_InvalidTime", CLEAR_ON_MANAGER_START}, {"Offroad_InvalidTime", CLEAR_ON_MANAGER_START},
@ -180,9 +201,18 @@ std::unordered_map<std::string, uint32_t> keys = {
} // namespace } // namespace
Params::Params(const std::string &path) { Params::Params(const std::string &path) {
static std::string default_param_path = ensure_params_path(); prefix = "/" + util::getenv("OPENPILOT_PREFIX", "d");
params_path = path.empty() ? default_param_path : ensure_params_path(path); params_path = ensure_params_path(prefix, path);
}
std::vector<std::string> Params::allKeys() const {
std::vector<std::string> ret;
for (auto &p : keys) {
ret.push_back(p.first);
}
return ret;
} }
bool Params::checkKey(const std::string &key) { bool Params::checkKey(const std::string &key) {
@ -270,12 +300,15 @@ std::map<std::string, std::string> Params::readAll() {
void Params::clearAll(ParamKeyType key_type) { void Params::clearAll(ParamKeyType key_type) {
FileLock file_lock(params_path + "/.lock"); FileLock file_lock(params_path + "/.lock");
std::string path; if (key_type == ALL) {
util::remove_files_in_dir(getParamPath());
} else {
for (auto &[key, type] : keys) { for (auto &[key, type] : keys) {
if (type & key_type) { if (type & key_type) {
unlink(getParamPath(key).c_str()); unlink(getParamPath(key).c_str());
} }
} }
}
fsync_dir(getParamPath()); fsync_dir(getParamPath());
} }

@ -2,6 +2,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include <vector>
enum ParamKeyType { enum ParamKeyType {
PERSISTENT = 0x02, PERSISTENT = 0x02,
@ -15,10 +16,11 @@ enum ParamKeyType {
class Params { class Params {
public: public:
Params(const std::string &path = {}); Params(const std::string &path = {});
std::vector<std::string> allKeys() const;
bool checkKey(const std::string &key); bool checkKey(const std::string &key);
ParamKeyType getKeyType(const std::string &key); ParamKeyType getKeyType(const std::string &key);
inline std::string getParamPath(const std::string &key = {}) { inline std::string getParamPath(const std::string &key = {}) {
return key.empty() ? params_path + "/d" : params_path + "/d/" + key; return params_path + prefix + (key.empty() ? "" : "/" + key);
} }
// Delete a value // Delete a value
@ -27,8 +29,8 @@ public:
// helpers for reading values // helpers for reading values
std::string get(const std::string &key, bool block = false); std::string get(const std::string &key, bool block = false);
inline bool getBool(const std::string &key) { inline bool getBool(const std::string &key, bool block = false) {
return get(key) == "1"; return get(key, block) == "1";
} }
std::map<std::string, std::string> readAll(); std::map<std::string, std::string> readAll();
@ -43,4 +45,5 @@ public:
private: private:
std::string params_path; std::string params_path;
std::string prefix;
}; };

@ -1,8 +1,9 @@
from common.params_pyx import Params, ParamKeyType, UnknownKeyName, put_nonblocking # pylint: disable=no-name-in-module, import-error from common.params_pyx import Params, ParamKeyType, UnknownKeyName, put_nonblocking, put_bool_nonblocking # pylint: disable=no-name-in-module, import-error
assert Params assert Params
assert ParamKeyType assert ParamKeyType
assert UnknownKeyName assert UnknownKeyName
assert put_nonblocking assert put_nonblocking
assert put_bool_nonblocking
if __name__ == "__main__": if __name__ == "__main__":
import sys import sys

@ -2,9 +2,10 @@
# cython: language_level = 3 # cython: language_level = 3
from libcpp cimport bool from libcpp cimport bool
from libcpp.string cimport string from libcpp.string cimport string
from libcpp.vector cimport vector
import threading import threading
cdef extern from "selfdrive/common/params.h": cdef extern from "common/params.h":
cpdef enum ParamKeyType: cpdef enum ParamKeyType:
PERSISTENT PERSISTENT
CLEAR_ON_MANAGER_START CLEAR_ON_MANAGER_START
@ -15,12 +16,14 @@ cdef extern from "selfdrive/common/params.h":
cdef cppclass c_Params "Params": cdef cppclass c_Params "Params":
c_Params(string) nogil c_Params(string) nogil
string get(string, bool) nogil string get(string, bool) nogil
bool getBool(string) nogil bool getBool(string, bool) nogil
int remove(string) nogil int remove(string) nogil
int put(string, string) nogil int put(string, string) nogil
int putBool(string, bool) nogil int putBool(string, bool) nogil
bool checkKey(string) nogil bool checkKey(string) nogil
string getParamPath(string) nogil
void clearAll(ParamKeyType) void clearAll(ParamKeyType)
vector[string] allKeys()
def ensure_bytes(v): def ensure_bytes(v):
@ -65,11 +68,11 @@ cdef class Params:
return val if encoding is None else val.decode(encoding) return val if encoding is None else val.decode(encoding)
def get_bool(self, key): def get_bool(self, key, bool block=False):
cdef string k = self.check_key(key) cdef string k = self.check_key(key)
cdef bool r cdef bool r
with nogil: with nogil:
r = self.p.getBool(k) r = self.p.getBool(k, block)
return r return r
def put(self, key, dat): def put(self, key, dat):
@ -89,17 +92,20 @@ cdef class Params:
with nogil: with nogil:
self.p.putBool(k, val) self.p.putBool(k, val)
def delete(self, key): def remove(self, key):
cdef string k = self.check_key(key) cdef string k = self.check_key(key)
with nogil: with nogil:
self.p.remove(k) self.p.remove(k)
def get_param_path(self, key=""):
cdef string key_bytes = ensure_bytes(key)
return self.p.getParamPath(key_bytes).decode("utf-8")
def all_keys(self):
return self.p.allKeys()
def put_nonblocking(key, val, d=""): def put_nonblocking(key, val, d=""):
def f(key, val): threading.Thread(target=lambda: Params(d).put(key, val)).start()
params = Params(d)
cdef string k = ensure_bytes(key) def put_bool_nonblocking(key, bool val, d=""):
params.put(k, val) threading.Thread(target=lambda: Params(d).put_bool(key, val)).start()
t = threading.Thread(target=f, args=(key, val))
t.start()
return t

@ -2,23 +2,20 @@
import gc import gc
import os import os
import time import time
import multiprocessing from collections import deque
from typing import Optional from typing import Optional, List, Union
from setproctitle import getproctitle # pylint: disable=no-name-in-module
from common.clock import sec_since_boot # pylint: disable=no-name-in-module, import-error from common.clock import sec_since_boot # pylint: disable=no-name-in-module, import-error
from selfdrive.hardware import PC, TICI from system.hardware import PC
# time step for each process # time step for each process
DT_CTRL = 0.01 # controlsd DT_CTRL = 0.01 # controlsd
DT_MDL = 0.05 # model DT_MDL = 0.05 # model
DT_TRML = 0.5 # thermald and manager DT_TRML = 0.5 # thermald and manager
DT_DMON = 0.05 # driver monitoring
# driver monitoring
if TICI:
DT_DMON = 0.05
else:
DT_DMON = 0.1
class Priority: class Priority:
@ -34,29 +31,32 @@ class Priority:
def set_realtime_priority(level: int) -> None: def set_realtime_priority(level: int) -> None:
if not PC: if not PC:
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level)) # type: ignore[attr-defined] os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(level)) # pylint: disable=no-member
def set_core_affinity(core: int) -> None: def set_core_affinity(cores: List[int]) -> None:
if not PC: if not PC:
os.sched_setaffinity(0, [core,]) # type: ignore[attr-defined] os.sched_setaffinity(0, cores) # pylint: disable=no-member
def config_realtime_process(core: int, priority: int) -> None: def config_realtime_process(cores: Union[int, List[int]], priority: int) -> None:
gc.disable() gc.disable()
set_realtime_priority(priority) set_realtime_priority(priority)
set_core_affinity(core) c = cores if isinstance(cores, list) else [cores, ]
set_core_affinity(c)
class Ratekeeper: class Ratekeeper:
def __init__(self, rate: int, print_delay_threshold: Optional[float] = 0.0) -> None: def __init__(self, rate: float, print_delay_threshold: Optional[float] = 0.0) -> None:
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative.""" """Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
self._interval = 1. / rate self._interval = 1. / rate
self._next_frame_time = sec_since_boot() + self._interval self._next_frame_time = sec_since_boot() + self._interval
self._print_delay_threshold = print_delay_threshold self._print_delay_threshold = print_delay_threshold
self._frame = 0 self._frame = 0
self._remaining = 0.0 self._remaining = 0.0
self._process_name = multiprocessing.current_process().name self._process_name = getproctitle()
self._dts = deque([self._interval], maxlen=100)
self._last_monitor_time = sec_since_boot()
@property @property
def frame(self) -> int: def frame(self) -> int:
@ -66,6 +66,12 @@ class Ratekeeper:
def remaining(self) -> float: def remaining(self) -> float:
return self._remaining return self._remaining
@property
def lagging(self) -> bool:
avg_dt = sum(self._dts) / len(self._dts)
expected_dt = self._interval * (1 / 0.9)
return avg_dt > expected_dt
# Maintain loop rate by calling this at the end of each loop # Maintain loop rate by calling this at the end of each loop
def keep_time(self) -> bool: def keep_time(self) -> bool:
lagged = self.monitor_time() lagged = self.monitor_time()
@ -75,6 +81,10 @@ class Ratekeeper:
# this only monitor the cumulative lag, but does not enforce a rate # this only monitor the cumulative lag, but does not enforce a rate
def monitor_time(self) -> bool: def monitor_time(self) -> bool:
prev = self._last_monitor_time
self._last_monitor_time = sec_since_boot()
self._dts.append(self._last_monitor_time - prev)
lagged = False lagged = False
remaining = self._next_frame_time - sec_since_boot() remaining = self._next_frame_time - sec_since_boot()
self._next_frame_time += self._interval self._next_frame_time += self._interval

@ -2,8 +2,8 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#endif #endif
#include "selfdrive/common/statlog.h" #include "common/statlog.h"
#include "selfdrive/common/util.h" #include "common/util.h"
#include <stdio.h> #include <stdio.h>
#include <mutex> #include <mutex>
@ -17,6 +17,9 @@ class StatlogState : public LogState {
static StatlogState s = {}; static StatlogState s = {};
static void log(const char* metric_type, const char* metric, const char* fmt, ...) { static void log(const char* metric_type, const char* metric, const char* fmt, ...) {
std::lock_guard lk(s.lock);
if (!s.initialized) s.initialize();
char* value_buf = nullptr; char* value_buf = nullptr;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);

@ -1,6 +0,0 @@
def replace_right(s, old, new, occurrence):
# replace_right('1232425', '2', ' ', 1) -> '12324 5'
# replace_right('1232425', '2', ' ', 2) -> '123 4 5'
split = s.rsplit(old, occurrence)
return new.join(split)

@ -2,25 +2,25 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#endif #endif
#include "selfdrive/common/swaglog.h" #include "common/swaglog.h"
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <limits>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <zmq.h> #include <zmq.h>
#include "json11.hpp" #include "json11.hpp"
#include "selfdrive/common/util.h" #include "common/util.h"
#include "selfdrive/common/version.h" #include "common/version.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
class SwaglogState : public LogState { class SwaglogState : public LogState {
public: public:
SwaglogState() : LogState("ipc:///tmp/logmessage") {} SwaglogState() : LogState("ipc:///tmp/logmessage") {}
bool initialized = false;
json11::Json::object ctx_j; json11::Json::object ctx_j;
inline void initialize() { inline void initialize() {
@ -50,19 +50,14 @@ class SwaglogState : public LogState {
ctx_j["dirty"] = !getenv("CLEAN"); ctx_j["dirty"] = !getenv("CLEAN");
// device type // device type
if (Hardware::EON()) { ctx_j["device"] = Hardware::get_name();
ctx_j["device"] = "eon"; LogState::initialize();
} else if (Hardware::TICI()) {
ctx_j["device"] = "tici";
} else {
ctx_j["device"] = "pc";
}
initialized = true;
} }
}; };
static SwaglogState s = {}; static SwaglogState s = {};
bool LOG_TIMESTAMPS = getenv("LOG_TIMESTAMPS");
uint32_t NO_FRAME_ID = std::numeric_limits<uint32_t>::max();
static void log(int levelnum, const char* filename, int lineno, const char* func, const char* msg, const std::string& log_s) { static void log(int levelnum, const char* filename, int lineno, const char* func, const char* msg, const std::string& log_s) {
if (levelnum >= s.print_level) { if (levelnum >= s.print_level) {
@ -72,22 +67,12 @@ static void log(int levelnum, const char* filename, int lineno, const char* func
zmq_send(s.sock, (levelnum_c + log_s).c_str(), log_s.length() + 1, ZMQ_NOBLOCK); zmq_send(s.sock, (levelnum_c + log_s).c_str(), log_s.length() + 1, ZMQ_NOBLOCK);
} }
void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func, static void cloudlog_common(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) { char* msg_buf, const json11::Json::object &msg_j={}) {
char* msg_buf = nullptr;
va_list args;
va_start(args, fmt);
int ret = vasprintf(&msg_buf, fmt, args);
va_end(args);
if (ret <= 0 || !msg_buf) return;
std::lock_guard lk(s.lock); std::lock_guard lk(s.lock);
if (!s.initialized) s.initialize(); if (!s.initialized) s.initialize();
json11::Json log_j = json11::Json::object { json11::Json::object log_j = json11::Json::object {
{"msg", msg_buf},
{"ctx", s.ctx_j}, {"ctx", s.ctx_j},
{"levelnum", levelnum}, {"levelnum", levelnum},
{"filename", filename}, {"filename", filename},
@ -95,7 +80,58 @@ void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func
{"funcname", func}, {"funcname", func},
{"created", seconds_since_epoch()} {"created", seconds_since_epoch()}
}; };
std::string log_s = log_j.dump(); if (msg_j.empty()) {
log_j["msg"] = msg_buf;
} else {
log_j["msg"] = msg_j;
}
std::string log_s = ((json11::Json)log_j).dump();
log(levelnum, filename, lineno, func, msg_buf, log_s); log(levelnum, filename, lineno, func, msg_buf, log_s);
free(msg_buf); free(msg_buf);
} }
void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) {
va_list args;
va_start(args, fmt);
char* msg_buf = nullptr;
int ret = vasprintf(&msg_buf, fmt, args);
va_end(args);
if (ret <= 0 || !msg_buf) return;
cloudlog_common(levelnum, filename, lineno, func, msg_buf);
}
void cloudlog_t_common(int levelnum, const char* filename, int lineno, const char* func,
uint32_t frame_id, const char* fmt, va_list args) {
if (!LOG_TIMESTAMPS) return;
char* msg_buf = nullptr;
int ret = vasprintf(&msg_buf, fmt, args);
if (ret <= 0 || !msg_buf) return;
json11::Json::object tspt_j = json11::Json::object{
{"event", msg_buf},
{"time", std::to_string(nanos_since_boot())}
};
if (frame_id < NO_FRAME_ID) {
tspt_j["frame_id"] = std::to_string(frame_id);
}
tspt_j = json11::Json::object{{"timestamp", tspt_j}};
cloudlog_common(levelnum, filename, lineno, func, msg_buf, tspt_j);
}
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) {
va_list args;
va_start(args, fmt);
cloudlog_t_common(levelnum, filename, lineno, func, NO_FRAME_ID, fmt, args);
va_end(args);
}
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
uint32_t frame_id, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
cloudlog_t_common(levelnum, filename, lineno, func, frame_id, fmt, args);
va_end(args);
}

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "selfdrive/common/timing.h" #include "common/timing.h"
#define CLOUDLOG_DEBUG 10 #define CLOUDLOG_DEBUG 10
#define CLOUDLOG_INFO 20 #define CLOUDLOG_INFO 20
@ -9,13 +9,24 @@
#define CLOUDLOG_CRITICAL 50 #define CLOUDLOG_CRITICAL 50
void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func, void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) /*__attribute__ ((format (printf, 6, 7)))*/; const char* fmt, ...) /*__attribute__ ((format (printf, 6, 7)))*/;
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
const char* fmt, ...) /*__attribute__ ((format (printf, 6, 7)))*/;
void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func,
uint32_t frame_id, const char* fmt, ...) /*__attribute__ ((format (printf, 6, 7)))*/;
#define cloudlog(lvl, fmt, ...) cloudlog_e(lvl, __FILE__, __LINE__, \ #define cloudlog(lvl, fmt, ...) cloudlog_e(lvl, __FILE__, __LINE__, \
__func__, \ __func__, \
fmt, ## __VA_ARGS__) fmt, ## __VA_ARGS__);
#define cloudlog_t(lvl, ...) cloudlog_te(lvl, __FILE__, __LINE__, \
__func__, \
__VA_ARGS__);
#define cloudlog_rl(burst, millis, lvl, fmt, ...) \ #define cloudlog_rl(burst, millis, lvl, fmt, ...) \
{ \ { \
@ -46,6 +57,8 @@ void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func
} \ } \
} }
#define LOGT(...) cloudlog_t(CLOUDLOG_DEBUG, __VA_ARGS__)
#define LOGD(fmt, ...) cloudlog(CLOUDLOG_DEBUG, fmt, ## __VA_ARGS__) #define LOGD(fmt, ...) cloudlog(CLOUDLOG_DEBUG, fmt, ## __VA_ARGS__)
#define LOG(fmt, ...) cloudlog(CLOUDLOG_INFO, fmt, ## __VA_ARGS__) #define LOG(fmt, ...) cloudlog(CLOUDLOG_INFO, fmt, ## __VA_ARGS__)
#define LOGW(fmt, ...) cloudlog(CLOUDLOG_WARNING, fmt, ## __VA_ARGS__) #define LOGW(fmt, ...) cloudlog(CLOUDLOG_WARNING, fmt, ## __VA_ARGS__)

@ -1,26 +0,0 @@
#!/usr/bin/env python3
from markdown_it import MarkdownIt
import os
import unittest
from common.basedir import BASEDIR
from common.markdown import parse_markdown
class TestMarkdown(unittest.TestCase):
# validate that our simple markdown parser produces the same output as `markdown_it` from pip
def test_current_release_notes(self):
self.maxDiff = None
with open(os.path.join(BASEDIR, "RELEASES.md")) as f:
for r in f.read().split("\n\n"):
# No hyperlink support is ok
if '[' in r:
continue
self.assertEqual(MarkdownIt().render(r), parse_markdown(r))
if __name__ == "__main__":
unittest.main()

@ -4,7 +4,7 @@ import tempfile
import shutil import shutil
import unittest import unittest
from common.params import Params, ParamKeyType, UnknownKeyName, put_nonblocking from common.params import Params, ParamKeyType, UnknownKeyName, put_nonblocking, put_bool_nonblocking
class TestParams(unittest.TestCase): class TestParams(unittest.TestCase):
def setUp(self): def setUp(self):
@ -59,13 +59,13 @@ class TestParams(unittest.TestCase):
with self.assertRaises(UnknownKeyName): with self.assertRaises(UnknownKeyName):
self.params.put_bool("swag", True) self.params.put_bool("swag", True)
def test_delete_not_there(self): def test_remove_not_there(self):
assert self.params.get("CarParams") is None assert self.params.get("CarParams") is None
self.params.delete("CarParams") self.params.remove("CarParams")
assert self.params.get("CarParams") is None assert self.params.get("CarParams") is None
def test_get_bool(self): def test_get_bool(self):
self.params.delete("IsMetric") self.params.remove("IsMetric")
self.assertFalse(self.params.get_bool("IsMetric")) self.assertFalse(self.params.get_bool("IsMetric"))
self.params.put_bool("IsMetric", True) self.params.put_bool("IsMetric", True)
@ -89,6 +89,23 @@ class TestParams(unittest.TestCase):
assert q.get("CarParams") is None assert q.get("CarParams") is None
assert q.get("CarParams", True) == b"test" assert q.get("CarParams", True) == b"test"
def test_put_bool_non_blocking_with_get_block(self):
q = Params(self.tmpdir)
def _delayed_writer():
time.sleep(0.1)
put_bool_nonblocking("CarParams", True, self.tmpdir)
threading.Thread(target=_delayed_writer).start()
assert q.get("CarParams") is None
assert q.get("CarParams", True) == b"1"
def test_params_all_keys(self):
keys = Params().all_keys()
# sanity checks
assert len(keys) > 20
assert len(keys) == len(set(keys))
assert b"CarParams" in keys
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

@ -4,10 +4,10 @@
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
#include "json11.hpp" #include "json11.hpp"
#include "selfdrive/common/swaglog.h" #include "common/swaglog.h"
#include "selfdrive/common/util.h" #include "common/util.h"
#include "selfdrive/common/version.h" #include "common/version.h"
#include "selfdrive/hardware/hw.h" #include "system/hardware/hw.h"
const char *SWAGLOG_ADDR = "ipc:///tmp/logmessage"; const char *SWAGLOG_ADDR = "ipc:///tmp/logmessage";
std::string daemon_name = "testy"; std::string daemon_name = "testy";
@ -56,12 +56,7 @@ void recv_log(int thread_cnt, int thread_msg_cnt) {
REQUIRE(ctx["version"].string_value() == COMMA_VERSION); REQUIRE(ctx["version"].string_value() == COMMA_VERSION);
std::string device = "pc"; std::string device = Hardware::get_name();
if (Hardware::EON()) {
device = "eon";
} else if (Hardware::TICI()) {
device = "tici";
}
REQUIRE(ctx["device"].string_value() == device); REQUIRE(ctx["device"].string_value() == device);
int thread_id = atoi(msg["msg"].string_value().c_str()); int thread_id = atoi(msg["msg"].string_value().c_str());

@ -10,7 +10,7 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp" #include "catch2/catch.hpp"
#include "selfdrive/common/util.h" #include "common/util.h"
std::string random_bytes(int size) { std::string random_bytes(int size) {
std::random_device rd; std::random_device rd;
@ -136,10 +136,27 @@ TEST_CASE("util::create_directories") {
REQUIRE(util::create_directories(dir + "/file", 0755) == false); REQUIRE(util::create_directories(dir + "/file", 0755) == false);
REQUIRE(util::create_directories(dir + "/file/1/2/3", 0755) == false); REQUIRE(util::create_directories(dir + "/file/1/2/3", 0755) == false);
} }
SECTION("end with slashs") { SECTION("end with slashes") {
REQUIRE(util::create_directories(dir + "/", 0755)); REQUIRE(util::create_directories(dir + "/", 0755));
} }
SECTION("empty") { SECTION("empty") {
REQUIRE(util::create_directories("", 0755) == false); REQUIRE(util::create_directories("", 0755) == false);
} }
} }
TEST_CASE("util::remove_files_in_dir") {
std::string tmp_dir = "/tmp/test_remove_all_in_dir";
system("rm /tmp/test_remove_all_in_dir -rf");
REQUIRE(util::create_directories(tmp_dir, 0755));
const int tmp_file_cnt = 10;
for (int i = 0; i < tmp_file_cnt; ++i) {
std::string tmp_file = tmp_dir + "/test_XXXXXX";
int fd = mkstemp((char*)tmp_file.c_str());
close(fd);
REQUIRE(util::file_exists(tmp_file.c_str()));
}
REQUIRE(util::read_files_in_dir(tmp_dir).size() == tmp_file_cnt);
util::remove_files_in_dir(tmp_dir);
REQUIRE(util::read_files_in_dir(tmp_dir).empty());
}

@ -1,47 +0,0 @@
import os
import tempfile
import shutil
import unittest
from common.xattr import getxattr, setxattr, listxattr, removexattr
class TestParams(unittest.TestCase):
USER_TEST='user.test'
def setUp(self):
self.tmpdir = tempfile.mkdtemp()
self.tmpfn = os.path.join(self.tmpdir, 'test.txt')
open(self.tmpfn, 'w').close()
#print("using", self.tmpfn)
def tearDown(self):
shutil.rmtree(self.tmpdir)
def test_getxattr_none(self):
a = getxattr(self.tmpfn, TestParams.USER_TEST)
assert a is None
def test_listxattr_none(self):
l = listxattr(self.tmpfn)
assert l == []
def test_setxattr(self):
setxattr(self.tmpfn, TestParams.USER_TEST, b'123')
a = getxattr(self.tmpfn, TestParams.USER_TEST)
assert a == b'123'
def test_listxattr(self):
setxattr(self.tmpfn, 'user.test1', b'123')
setxattr(self.tmpfn, 'user.test2', b'123')
l = listxattr(self.tmpfn)
assert l == ['user.test1', 'user.test2']
def test_removexattr(self):
setxattr(self.tmpfn, TestParams.USER_TEST, b'123')
a = getxattr(self.tmpfn, TestParams.USER_TEST)
assert a == b'123'
removexattr(self.tmpfn, TestParams.USER_TEST)
a = getxattr(self.tmpfn, TestParams.USER_TEST)
assert a is None
if __name__ == "__main__":
unittest.main()

@ -24,7 +24,7 @@ by generating a rotation matrix and multiplying.
Orientation Conventations Orientation Conventions
------ ------
Quaternions, rotation matrices and euler angles are three Quaternions, rotation matrices and euler angles are three
equivalent representations of orientation and all three are equivalent representations of orientation and all three are

@ -1,7 +1,6 @@
import numpy as np import numpy as np
import common.transformations.orientation as orient import common.transformations.orientation as orient
from selfdrive.hardware import TICI
## -- hardcoded hardware params -- ## -- hardcoded hardware params --
eon_f_focal_length = 910.0 eon_f_focal_length = 910.0
@ -45,11 +44,6 @@ tici_fcam_intrinsics_inv = np.linalg.inv(tici_fcam_intrinsics)
tici_ecam_intrinsics_inv = np.linalg.inv(tici_ecam_intrinsics) tici_ecam_intrinsics_inv = np.linalg.inv(tici_ecam_intrinsics)
if not TICI:
FULL_FRAME_SIZE = eon_f_frame_size
FOCAL = eon_f_focal_length
fcam_intrinsics = eon_fcam_intrinsics
else:
FULL_FRAME_SIZE = tici_f_frame_size FULL_FRAME_SIZE = tici_f_frame_size
FOCAL = tici_f_focal_length FOCAL = tici_f_focal_length
fcam_intrinsics = tici_fcam_intrinsics fcam_intrinsics = tici_fcam_intrinsics
@ -83,6 +77,7 @@ def get_view_frame_from_road_frame(roll, pitch, yaw, height):
return np.hstack((view_from_road, [[0], [height], [0]])) return np.hstack((view_from_road, [[0], [height], [0]]))
# aka 'extrinsic_matrix' # aka 'extrinsic_matrix'
def get_view_frame_from_calib_frame(roll, pitch, yaw, height): def get_view_frame_from_calib_frame(roll, pitch, yaw, height):
device_from_calib= orient.rot_from_euler([roll, pitch, yaw]) device_from_calib= orient.rot_from_euler([roll, pitch, yaw])
@ -100,12 +95,6 @@ def vp_from_ke(m):
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, intrinsics=fcam_intrinsics):
e = get_view_frame_from_road_frame(rpy[0], rpy[1], rpy[2], 1.22)
ke = np.dot(intrinsics, e)
return vp_from_ke(ke)
def roll_from_ke(m): def roll_from_ke(m):
# note: different from calibration.h/RollAnglefromKE: i think that one's just wrong # note: different from calibration.h/RollAnglefromKE: i think that one's just wrong
return np.arctan2(-(m[1, 0] - m[1, 1] * m[2, 0] / m[2, 1]), return np.arctan2(-(m[1, 0] - m[1, 1] * m[2, 0] / m[2, 1]),
@ -169,11 +158,3 @@ def img_from_device(pt_device):
pt_img = pt_view/pt_view[:, 2:3] pt_img = pt_view/pt_view[:, 2:3]
return pt_img.reshape(input_shape)[:, :2] return pt_img.reshape(input_shape)[:, :2]
def get_camera_frame_from_calib_frame(camera_frame_from_road_frame, intrinsics=fcam_intrinsics):
camera_frame_from_ground = camera_frame_from_road_frame[:, (0, 1, 3)]
calib_frame_from_ground = np.dot(intrinsics,
get_view_frame_from_road_frame(0, 0, 0, 1.22))[:, (0, 1, 3)]
ground_from_calib_frame = np.linalg.inv(calib_frame_from_ground)
camera_frame_from_calib_frame = np.dot(camera_frame_from_ground, ground_from_calib_frame)
return camera_frame_from_calib_frame

@ -1,10 +1,7 @@
import numpy as np import numpy as np
from common.transformations.camera import (FULL_FRAME_SIZE, from common.transformations.camera import (FULL_FRAME_SIZE,
FOCAL, get_view_frame_from_calib_frame)
get_view_frame_from_road_frame,
get_view_frame_from_calib_frame,
vp_from_ke)
# segnet # segnet
SEGNET_SIZE = (512, 384) SEGNET_SIZE = (512, 384)
@ -14,21 +11,6 @@ def get_segnet_frame_from_camera_frame(segnet_size=SEGNET_SIZE, full_frame_size=
[0.0, float(segnet_size[1]) / full_frame_size[1]]]) [0.0, float(segnet_size[1]) / full_frame_size[1]]])
segnet_frame_from_camera_frame = get_segnet_frame_from_camera_frame() # xx segnet_frame_from_camera_frame = get_segnet_frame_from_camera_frame() # xx
# model
MODEL_INPUT_SIZE = (320, 160)
MODEL_YUV_SIZE = (MODEL_INPUT_SIZE[0], MODEL_INPUT_SIZE[1] * 3 // 2)
MODEL_CX = MODEL_INPUT_SIZE[0] / 2.
MODEL_CY = 21.
model_fl = 728.0
model_height = 1.22
# canonical model transform
model_intrinsics = np.array([
[model_fl, 0.0, MODEL_CX],
[0.0, model_fl, MODEL_CY],
[0.0, 0.0, 1.0]])
# MED model # MED model
MEDMODEL_INPUT_SIZE = (512, 256) MEDMODEL_INPUT_SIZE = (512, 256)
@ -42,18 +24,6 @@ medmodel_intrinsics = np.array([
[0.0, 0.0, 1.0]]) [0.0, 0.0, 1.0]])
# 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_fl = 606.7
calmodel_intrinsics = np.array([
[calmodel_fl, 0.0, 0.5 * CALMODEL_INPUT_SIZE[0]],
[0.0, calmodel_fl, CALMODEL_CY],
[0.0, 0.0, 1.0]])
# BIG model # BIG model
BIGMODEL_INPUT_SIZE = (1024, 512) BIGMODEL_INPUT_SIZE = (1024, 512)
BIGMODEL_YUV_SIZE = (BIGMODEL_INPUT_SIZE[0], BIGMODEL_INPUT_SIZE[1] * 3 // 2) BIGMODEL_YUV_SIZE = (BIGMODEL_INPUT_SIZE[0], BIGMODEL_INPUT_SIZE[1] * 3 // 2)
@ -75,104 +45,73 @@ sbigmodel_intrinsics = np.array([
[0.0, sbigmodel_fl, 0.5 * (256 + MEDMODEL_CY)], [0.0, sbigmodel_fl, 0.5 * (256 + MEDMODEL_CY)],
[0.0, 0.0, 1.0]]) [0.0, 0.0, 1.0]])
model_frame_from_road_frame = np.dot(model_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
bigmodel_frame_from_road_frame = np.dot(bigmodel_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
bigmodel_frame_from_calib_frame = np.dot(bigmodel_intrinsics, bigmodel_frame_from_calib_frame = np.dot(bigmodel_intrinsics,
get_view_frame_from_calib_frame(0, 0, 0, 0)) get_view_frame_from_calib_frame(0, 0, 0, 0))
sbigmodel_frame_from_road_frame = np.dot(sbigmodel_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
sbigmodel_frame_from_calib_frame = np.dot(sbigmodel_intrinsics, sbigmodel_frame_from_calib_frame = np.dot(sbigmodel_intrinsics,
get_view_frame_from_calib_frame(0, 0, 0, 0)) get_view_frame_from_calib_frame(0, 0, 0, 0))
medmodel_frame_from_road_frame = np.dot(medmodel_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
medmodel_frame_from_calib_frame = np.dot(medmodel_intrinsics, medmodel_frame_from_calib_frame = np.dot(medmodel_intrinsics,
get_view_frame_from_calib_frame(0, 0, 0, 0)) get_view_frame_from_calib_frame(0, 0, 0, 0))
model_frame_from_bigmodel_frame = np.dot(model_intrinsics, np.linalg.inv(bigmodel_intrinsics))
medmodel_frame_from_bigmodel_frame = np.dot(medmodel_intrinsics, np.linalg.inv(bigmodel_intrinsics)) medmodel_frame_from_bigmodel_frame = np.dot(medmodel_intrinsics, np.linalg.inv(bigmodel_intrinsics))
# 'camera from model camera' ### This function mimics the update_calibration logic in modeld.cc
def get_model_height_transform(camera_frame_from_road_frame, height): ### Manually verified to give similar results to xx.uncommon.utils.transform_img
camera_frame_from_road_ground = np.dot(camera_frame_from_road_frame, np.array([ def get_warp_matrix(rpy_calib, wide_cam=False, big_model=False, tici=True):
[1, 0, 0], from common.transformations.orientation import rot_from_euler
[0, 1, 0], from common.transformations.camera import view_frame_from_device_frame, eon_fcam_intrinsics, tici_ecam_intrinsics, tici_fcam_intrinsics
[0, 0, 0],
[0, 0, 1],
]))
camera_frame_from_road_high = np.dot(camera_frame_from_road_frame, np.array([
[1, 0, 0],
[0, 1, 0],
[0, 0, height - model_height],
[0, 0, 1],
]))
road_high_from_camera_frame = np.linalg.inv(camera_frame_from_road_high)
high_camera_from_low_camera = np.dot(camera_frame_from_road_ground, road_high_from_camera_frame)
return high_camera_from_low_camera
# camera_frame_from_model_frame aka 'warp matrix'
# was: calibration.h/CalibrationTransform
def get_camera_frame_from_model_frame(camera_frame_from_road_frame, height=model_height, camera_fl=FOCAL):
vp = vp_from_ke(camera_frame_from_road_frame)
model_zoom = camera_fl / model_fl
model_camera_from_model_frame = np.array([
[model_zoom, 0.0, vp[0] - MODEL_CX * model_zoom],
[0.0, model_zoom, vp[1] - MODEL_CY * model_zoom],
[0.0, 0.0, 1.0],
])
# 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:
camera_from_model_camera = get_model_height_transform(camera_frame_from_road_frame, height)
else:
camera_from_model_camera = np.eye(3)
return np.dot(camera_from_model_camera, model_camera_from_model_frame)
def get_camera_frame_from_medmodel_frame(camera_frame_from_road_frame): if tici and wide_cam:
camera_frame_from_ground = camera_frame_from_road_frame[:, (0, 1, 3)] intrinsics = tici_ecam_intrinsics
medmodel_frame_from_ground = medmodel_frame_from_road_frame[:, (0, 1, 3)] elif tici:
intrinsics = tici_fcam_intrinsics
else:
intrinsics = eon_fcam_intrinsics
ground_from_medmodel_frame = np.linalg.inv(medmodel_frame_from_ground) if big_model:
camera_frame_from_medmodel_frame = np.dot(camera_frame_from_ground, ground_from_medmodel_frame) sbigmodel_from_calib = sbigmodel_frame_from_calib_frame[:, (0,1,2)]
calib_from_model = np.linalg.inv(sbigmodel_from_calib)
else:
medmodel_from_calib = medmodel_frame_from_calib_frame[:, (0,1,2)]
calib_from_model = np.linalg.inv(medmodel_from_calib)
device_from_calib = rot_from_euler(rpy_calib)
camera_from_calib = intrinsics.dot(view_frame_from_device_frame.dot(device_from_calib))
warp_matrix = camera_from_calib.dot(calib_from_model)
return warp_matrix
return camera_frame_from_medmodel_frame
### This is old, just for debugging
def get_warp_matrix_old(rpy_calib, wide_cam=False, big_model=False, tici=True):
from common.transformations.orientation import rot_from_euler
from common.transformations.camera import view_frame_from_device_frame, eon_fcam_intrinsics, tici_ecam_intrinsics, tici_fcam_intrinsics
def get_camera_frame_from_bigmodel_frame(camera_frame_from_road_frame):
camera_frame_from_ground = camera_frame_from_road_frame[:, (0, 1, 3)]
bigmodel_frame_from_ground = bigmodel_frame_from_road_frame[:, (0, 1, 3)]
ground_from_bigmodel_frame = np.linalg.inv(bigmodel_frame_from_ground) def get_view_frame_from_road_frame(roll, pitch, yaw, height):
camera_frame_from_bigmodel_frame = np.dot(camera_frame_from_ground, ground_from_bigmodel_frame) device_from_road = rot_from_euler([roll, pitch, yaw]).dot(np.diag([1, -1, -1]))
view_from_road = view_frame_from_device_frame.dot(device_from_road)
return camera_frame_from_bigmodel_frame return np.hstack((view_from_road, [[0], [height], [0]]))
if tici and wide_cam:
intrinsics = tici_ecam_intrinsics
elif tici:
intrinsics = tici_fcam_intrinsics
else:
intrinsics = eon_fcam_intrinsics
def get_model_frame(snu_full, camera_frame_from_model_frame, size): model_height = 1.22
idxs = camera_frame_from_model_frame.dot(np.column_stack([np.tile(np.arange(size[0]), size[1]), if big_model:
np.tile(np.arange(size[1]), (size[0], 1)).T.flatten(), model_from_road = np.dot(sbigmodel_intrinsics,
np.ones(size[0] * size[1])]).T).T.astype(int) get_view_frame_from_road_frame(0, 0, 0, model_height))
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:
calib = calib_flat.reshape((size[1], size[0]))
else: else:
raise ValueError("shape of input img is weird") model_from_road = np.dot(medmodel_intrinsics,
return calib get_view_frame_from_road_frame(0, 0, 0, model_height))
ground_from_model = np.linalg.inv(model_from_road[:, (0, 1, 3)])
E = get_view_frame_from_road_frame(*rpy_calib, 1.22)
camera_frame_from_road_frame = intrinsics.dot(E)
camera_frame_from_ground = camera_frame_from_road_frame[:,(0,1,3)]
warp_matrix = camera_frame_from_ground .dot(ground_from_model)
return warp_matrix

@ -1,5 +1,6 @@
# pylint: skip-file # pylint: skip-file
import numpy as np import numpy as np
from typing import Callable
from common.transformations.transformations import (ecef_euler_from_ned_single, from common.transformations.transformations import (ecef_euler_from_ned_single,
euler2quat_single, euler2quat_single,
@ -11,7 +12,7 @@ from common.transformations.transformations import (ecef_euler_from_ned_single,
rot2quat_single) rot2quat_single)
def numpy_wrap(function, input_shape, output_shape): def numpy_wrap(function, input_shape, output_shape) -> Callable[..., np.ndarray]:
"""Wrap a function to take either an input or list of inputs and return the correct shape""" """Wrap a function to take either an input or list of inputs and return the correct shape"""
def f(*inps): def f(*inps):
*args, inp = inps *args, inp = inps

@ -1,5 +1,6 @@
#include "selfdrive/common/util.h" #include "common/util.h"
#include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <dirent.h> #include <dirent.h>
@ -97,6 +98,22 @@ std::map<std::string, std::string> read_files_in_dir(const std::string &path) {
return ret; return ret;
} }
void remove_files_in_dir(const std::string &path) {
DIR *d = opendir(path.c_str());
if (!d) return;
std::string fn;
struct dirent *de = NULL;
while ((de = readdir(d))) {
if (de->d_type != DT_DIR) {
fn = path + "/" + de->d_name;
unlink(fn.c_str());
}
}
closedir(d);
}
int write_file(const char* path, const void* data, size_t size, int flags, mode_t mode) { int write_file(const char* path, const void* data, size_t size, int flags, mode_t mode) {
int fd = HANDLE_EINTR(open(path, flags, mode)); int fd = HANDLE_EINTR(open(path, flags, mode));
if (fd == -1) { if (fd == -1) {
@ -133,6 +150,14 @@ int safe_fflush(FILE *stream) {
return ret; return ret;
} }
int safe_ioctl(int fd, unsigned long request, void *argp) {
int ret;
do {
ret = ioctl(fd, request, argp);
} while ((ret == -1) && (errno == EINTR));
return ret;
}
std::string readlink(const std::string &path) { std::string readlink(const std::string &path) {
char buff[4096]; char buff[4096];
ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1); ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1);

@ -80,11 +80,13 @@ std::string dir_name(std::string const& path);
// **** file fhelpers ***** // **** file fhelpers *****
std::string read_file(const std::string& fn); std::string read_file(const std::string& fn);
std::map<std::string, std::string> read_files_in_dir(const std::string& path); std::map<std::string, std::string> read_files_in_dir(const std::string& path);
void remove_files_in_dir(const std::string& path);
int write_file(const char* path, const void* data, size_t size, int flags = O_WRONLY, mode_t mode = 0664); int write_file(const char* path, const void* data, size_t size, int flags = O_WRONLY, mode_t mode = 0664);
FILE* safe_fopen(const char* filename, const char* mode); FILE* safe_fopen(const char* filename, const char* mode);
size_t safe_fwrite(const void * ptr, size_t size, size_t count, FILE * stream); size_t safe_fwrite(const void * ptr, size_t size, size_t count, FILE * stream);
int safe_fflush(FILE *stream); int safe_fflush(FILE *stream);
int safe_ioctl(int fd, unsigned long request, void *argp);
std::string readlink(const std::string& path); std::string readlink(const std::string& path);
bool file_exists(const std::string& fn); bool file_exists(const std::string& fn);
@ -168,12 +170,18 @@ void update_max_atomic(std::atomic<T>& max, T const& value) {
class LogState { class LogState {
public: public:
bool initialized = false;
std::mutex lock; std::mutex lock;
void *zctx; void *zctx = nullptr;
void *sock; void *sock = nullptr;
int print_level; int print_level;
const char* endpoint;
LogState(const char* endpoint) { LogState(const char* _endpoint) {
endpoint = _endpoint;
}
inline void initialize() {
zctx = zmq_ctx_new(); zctx = zmq_ctx_new();
sock = zmq_socket(zctx, ZMQ_PUSH); sock = zmq_socket(zctx, ZMQ_PUSH);
@ -182,9 +190,13 @@ class LogState {
zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout)); zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout));
zmq_connect(sock, endpoint); zmq_connect(sock, endpoint);
}; initialized = true;
}
~LogState() { ~LogState() {
if (initialized) {
zmq_close(sock); zmq_close(sock);
zmq_ctx_destroy(zctx); zmq_ctx_destroy(zctx);
} }
}
}; };

@ -0,0 +1 @@
#define COMMA_VERSION "0.9.1"

@ -1,12 +1,9 @@
#include "selfdrive/common/watchdog.h" #include "common/watchdog.h"
#include "selfdrive/common/timing.h" #include "common/util.h"
#include "selfdrive/common/util.h"
const std::string watchdog_fn_prefix = "/dev/shm/wd_"; // + <pid> const std::string watchdog_fn_prefix = "/dev/shm/wd_"; // + <pid>
bool watchdog_kick() { bool watchdog_kick(uint64_t ts) {
static std::string fn = watchdog_fn_prefix + std::to_string(getpid()); static std::string fn = watchdog_fn_prefix + std::to_string(getpid());
uint64_t ts = nanos_since_boot();
return util::write_file(fn.c_str(), &ts, sizeof(ts), O_WRONLY | O_CREAT) > 0; return util::write_file(fn.c_str(), &ts, sizeof(ts), O_WRONLY | O_CREAT) > 0;
} }

@ -0,0 +1,5 @@
#pragma once
#include <cstdint>
bool watchdog_kick(uint64_t ts);

@ -2,7 +2,7 @@ import sys
import pygame # pylint: disable=import-error import pygame # pylint: disable=import-error
import cv2 # pylint: disable=import-error import cv2 # pylint: disable=import-error
class Window(): class Window:
def __init__(self, w, h, caption="window", double=False, halve=False): def __init__(self, w, h, caption="window", double=False, halve=False):
self.w = w self.w = w
self.h = h self.h = h
@ -54,7 +54,7 @@ class Window():
if __name__ == "__main__": if __name__ == "__main__":
import numpy as np import numpy as np
win = Window(200, 200, double=True) win = Window(200, 200, double=True)
img = np.zeros((200, 200, 3), np.uint8) img: np.ndarray = np.zeros((200, 200, 3), np.uint8)
while 1: while 1:
print("draw") print("draw")
img += 1 img += 1

@ -1,5 +1,6 @@
import os import os
from cffi import FFI from cffi import FFI
from typing import Any, List
# Workaround for the EON/termux build of Python having os.*xattr removed. # Workaround for the EON/termux build of Python having os.*xattr removed.
ffi = FFI() ffi = FFI()
@ -11,7 +12,7 @@ int removexattr(const char *path, const char *name);
""") """)
libc = ffi.dlopen(None) libc = ffi.dlopen(None)
def setxattr(path, name, value, flags=0): def setxattr(path, name, value, flags=0) -> None:
path = path.encode() path = path.encode()
name = name.encode() name = name.encode()
if libc.setxattr(path, name, value, len(value), flags) == -1: if libc.setxattr(path, name, value, len(value), flags) == -1:
@ -29,7 +30,7 @@ def getxattr(path, name, size=128):
raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: getxattr({path}, {name}, {size})") raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: getxattr({path}, {name}, {size})")
return ffi.buffer(value)[:l] return ffi.buffer(value)[:l]
def listxattr(path, size=128): def listxattr(path, size=128) -> List[Any]:
path = path.encode() path = path.encode()
attrs = ffi.new(f"char[{size}]") attrs = ffi.new(f"char[{size}]")
l = libc.listxattr(path, attrs, size) l = libc.listxattr(path, attrs, size)
@ -38,7 +39,7 @@ def listxattr(path, size=128):
# attrs is b'\0' delimited values (so chop off trailing empty item) # attrs is b'\0' delimited values (so chop off trailing empty item)
return [a.decode() for a in ffi.buffer(attrs)[:l].split(b"\0")[0:-1]] return [a.decode() for a in ffi.buffer(attrs)[:l].split(b"\0")[0:-1]]
def removexattr(path, name): def removexattr(path, name) -> None:
path = path.encode() path = path.encode()
name = name.encode() name = name.encode()
if libc.removexattr(path, name) == -1: if libc.removexattr(path, name) == -1:

@ -1,185 +1,284 @@
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
# Supported Cars # Supported Cars
## comma.ai supported cars A supported vehicle is one that just works when you install a comma three. All supported cars provide a better experience than any stock system.
| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below | # 219 Supported Cars
| ----------| ------------------------------| ------------------| -----------------| -------------------| ------------------|
| Acura | ILX 2016-19 | AcuraWatch Plus | openpilot | 25mph<sup>1</sup> | 25mph | |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Harness|
| Acura | RDX 2016-18 | AcuraWatch Plus | openpilot | 25mph<sup>1</sup> | 12mph | |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|
| Acura | RDX 2019-21 | All | Stock | 0mph | 3mph | |Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Honda | Accord 2018-21 | All | Stock | 0mph | 3mph | |Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Honda | Accord Hybrid 2018-21 | All | Stock | 0mph | 3mph | |Acura|RDX 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Honda | Civic Hatchback 2017-21 | Honda Sensing | Stock | 0mph | 12mph | |Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Honda | Civic Coupe 2016-18 | Honda Sensing | openpilot | 0mph | 12mph | |Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Honda | Civic Coupe 2019-20 | All | Stock | 0mph | 2mph<sup>2</sup> | |Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Honda | Civic Sedan 2016-18 | Honda Sensing | openpilot | 0mph | 12mph | |Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Honda | Civic Sedan 2019-20 | All | Stock | 0mph | 2mph<sup>2</sup> | |Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Honda | CR-V 2015-16 | Touring | openpilot | 25mph<sup>1</sup> | 12mph | |Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Honda | CR-V 2017-21 | Honda Sensing | Stock | 0mph | 12mph | |Cadillac|Escalade ESV 2016[<sup>3</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
| Honda | CR-V Hybrid 2017-2019 | Honda Sensing | Stock | 0mph | 12mph | |Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
| Honda | e 2020 | All | Stock | 0mph | 3mph | |Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
| Honda | Fit 2018-19 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph | |Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
| Honda | Freed 2020 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph | |Chevrolet|Volt 2017-18[<sup>3</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
| Honda | HR-V 2019-20 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph | |Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
| Honda | Insight 2019-21 | All | Stock | 0mph | 3mph | |Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
| Honda | Inspire 2018 | All | Stock | 0mph | 3mph | |Chrysler|Pacifica 2021|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
| Honda | Odyssey 2018-20 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 0mph | |Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
| Honda | Passport 2019-21 | All | openpilot | 25mph<sup>1</sup> | 12mph | |Chrysler|Pacifica Hybrid 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
| Honda | Pilot 2016-21 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph | |comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None|
| Honda | Ridgeline 2017-21 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph | |Genesis|G70 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
| Hyundai | Palisade 2020-21 | All | Stock | 0mph | 0mph | |Genesis|G70 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
| Hyundai | Sonata 2020-22 | All | Stock | 0mph | 0mph | |Genesis|G80 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
| Lexus | CT Hybrid 2017-18 | LSS | Stock<sup>3</sup>| 0mph | 0mph | |Genesis|G90 2017-18|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
| Lexus | ES 2019-21 | All | openpilot | 0mph | 0mph | |Genesis|GV70 2022-23[<sup>5</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
| Lexus | ES Hybrid 2017-18 | LSS | Stock<sup>3</sup>| 0mph | 0mph | |GMC|Acadia 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control (ACC)|openpilot|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|OBD-II|
| Lexus | ES Hybrid 2019-21 | All | openpilot | 0mph | 0mph | |GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|GM|
| Lexus | IS 2017-2019 | All | Stock | 22mph | 0mph | |Honda|Accord 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Lexus | NX 2018-2019 | All | Stock<sup>3</sup>| 0mph | 0mph | |Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Lexus | NX 2020 | All | openpilot | 0mph | 0mph | |Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Lexus | NX Hybrid 2018-19 | All | Stock<sup>3</sup>| 0mph | 0mph | |Honda|Civic 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Lexus | RC 2020 | All | Stock | 22mph | 0mph | |Honda|Civic 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|
| Lexus | RX 2016-18 | All | Stock<sup>3</sup>| 0mph | 0mph | |Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Lexus | RX 2020-21 | All | openpilot | 0mph | 0mph | |Honda|Civic Hatchback 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch B|
| Lexus | RX Hybrid 2016-19 | All | Stock<sup>3</sup>| 0mph | 0mph | |Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Lexus | RX Hybrid 2020-21 | All | openpilot | 0mph | 0mph | |Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Lexus | UX Hybrid 2019-21 | All | openpilot | 0mph | 0mph | |Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Toyota | Alphard 2019-20 | All | openpilot | 0mph | 0mph | |Honda|e 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Toyota | Avalon 2016-21 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph | |Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Toyota | Avalon 2022 | All | openpilot | 0mph | 0mph | |Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Toyota | Avalon Hybrid 2019-21 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph | |Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Toyota | Camry 2018-20 | All | Stock | 0mph<sup>4</sup> | 0mph | |Honda|Insight 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Toyota | Camry 2021-22 | All | openpilot | 0mph<sup>4</sup> | 0mph | |Honda|Inspire 2018|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Bosch A|
| Toyota | Camry Hybrid 2018-20 | All | Stock | 0mph<sup>4</sup> | 0mph | |Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Toyota | Camry Hybrid 2021-22 | All | openpilot | 0mph | 0mph | |Honda|Passport 2019-21|All|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Toyota | C-HR 2017-21 | All | Stock | 0mph | 0mph | |Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Toyota | C-HR Hybrid 2017-19 | All | Stock | 0mph | 0mph | |Honda|Ridgeline 2017-22|Honda Sensing|openpilot|25 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Honda Nidec|
| Toyota | Corolla 2017-19 | All | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph | |Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|
| Toyota | Corolla 2020-22 | All | openpilot | 0mph | 0mph | |Hyundai|Elantra 2021-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|
| Toyota | Corolla Hatchback 2019-22 | All | openpilot | 0mph | 0mph | |Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
| Toyota | Corolla Hybrid 2020-22 | All | openpilot | 0mph | 0mph | |Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|
| Toyota | Highlander 2017-19 | All | Stock<sup>3</sup>| 0mph | 0mph | |Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai J|
| Toyota | Highlander 2020-22 | All | openpilot | 0mph | 0mph | |Hyundai|i30 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
| Toyota | Highlander Hybrid 2017-19 | All | Stock<sup>3</sup>| 0mph | 0mph | |Hyundai|Ioniq 5 (with HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai Q|
| Toyota | Highlander Hybrid 2020-22 | All | openpilot | 0mph | 0mph | |Hyundai|Ioniq 5 (without HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|
| Toyota | Mirai 2021 | All | openpilot | 0mph | 0mph | |Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
| Toyota | Prius 2016-20 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph | |Hyundai|Ioniq Electric 2020|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
| Toyota | Prius 2021-22 | All | openpilot | 0mph | 0mph | |Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
| Toyota | Prius v 2017 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph | |Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
| Toyota | Prius Prime 2017-20 | All | Stock<sup>3</sup>| 0mph | 0mph | |Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
| Toyota | Prius Prime 2021-22 | All | openpilot | 0mph | 0mph | |Hyundai|Ioniq Plug-in Hybrid 2020-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
| Toyota | Rav4 2016-18 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph | |Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|
| Toyota | Rav4 2019-21 | All | openpilot | 0mph | 0mph | |Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|
| Toyota | Rav4 Hybrid 2016-18 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph | |Hyundai|Kona Electric 2022|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai O|
| Toyota | Rav4 Hybrid 2019-21 | All | openpilot | 0mph | 0mph | |Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai I|
| Toyota | Sienna 2018-20 | All | Stock<sup>3</sup>| 0mph | 0mph | |Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
|Hyundai|Santa Cruz 2021-22[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|
<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 /> |Hyundai|Santa Fe 2019-20|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai D|
<sup>2</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br /> |Hyundai|Santa Fe 2021-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
<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 /> |Hyundai|Santa Fe Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
<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 /> |Hyundai|Santa Fe Plug-in Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
## Community Maintained Cars and Features |Hyundai|Sonata 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
|Hyundai|Sonata Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below | |Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
| ----------| --------------------------------| ------------------| -----------------| -------------------| -------------| |Hyundai|Tucson 2022[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|
| Audi | A3 2014-19 | ACC + Lane Assist | Stock | 0mph | 0mph | |Hyundai|Tucson 2023[<sup>5</sup>](#footnotes)|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|
| Audi | A3 Sportback e-tron 2017-18 | ACC + Lane Assist | Stock | 0mph | 0mph | |Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
| Audi | Q2 2018 | ACC + Lane Assist | Stock | 0mph | 0mph | |Hyundai|Tucson Hybrid 2022[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|
| Audi | Q3 2020-21 | ACC + Lane Assist | Stock | 0mph | 0mph | |Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
| Audi | S3 2015 | ACC + Lane Assist | Stock | 0mph | 0mph | |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
| Cadillac | Escalade ESV 2016<sup>1</sup> | ACC + LKAS | openpilot | 0mph | 7mph | |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|FCA|
| Chevrolet | Volt 2017-18<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph | |Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
| Chrysler | Pacifica 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph | |Kia|EV6 (with HDA II) 2022[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai P|
| Chrysler | Pacifica 2020 | Adaptive Cruise | Stock | 0mph | 39mph | |Kia|EV6 (without HDA II) 2022[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai L|
| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph | |Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|
| Chrysler | Pacifica Hybrid 2019-21 | Adaptive Cruise | Stock | 0mph | 39mph | |Kia|K5 2021-22|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
| Genesis | G70 2018 | All | Stock | 0mph | 0mph | |Kia|Niro EV 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
| Genesis | G70 2020 | All | Stock | 0mph | 0mph | |Kia|Niro EV 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
| Genesis | G80 2018 | All | Stock | 0mph | 0mph | |Kia|Niro EV 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
| Genesis | G90 2018 | All | Stock | 0mph | 0mph | |Kia|Niro EV 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
| GMC | Acadia 2018<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph | |Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai F|
| Hyundai | Elantra 2017-19 | SCC + LKAS | Stock | 19mph | 34mph | |Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
| Hyundai | Elantra 2021-22 | SCC + LKAS | Stock | 0mph | 0mph | |Kia|Niro Plug-in Hybrid 2018-19|All|openpilot available[<sup>1</sup>](#footnotes)|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
| Hyundai | Elantra Hybrid 2021 | SCC + LKAS | Stock | 0mph | 0mph | |Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai B|
| Hyundai | Genesis 2015-16 | SCC + LKAS | Stock | 19mph | 37mph | |Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai G|
| Hyundai | Ioniq Electric 2019 | SCC + LKAS | Stock | 0mph | 32mph | |Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
| Hyundai | Ioniq Electric 2020 | SCC + LKAS | Stock | 0mph | 0mph | |Kia|Sorento 2018|Advanced Smart Cruise Control|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
| Hyundai | Ioniq Hybrid 2017-19 | SCC + LKAS | Stock | 0mph | 32mph | |Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai E|
| Hyundai | Ioniq Hybrid 2020-22 | SCC + LFA | Stock | 0mph | 0mph | |Kia|Sorento Plug-in Hybrid 2022-23[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai A|
| Hyundai | Ioniq PHEV 2020-21 | SCC + LKAS | Stock | 0mph | 0mph | |Kia|Sportage 2023[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|
| Hyundai | Kona 2020 | SCC + LKAS | Stock | 0mph | 0mph | |Kia|Sportage Hybrid 2023[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai N|
| Hyundai | Kona EV 2018-19 | SCC + LKAS | Stock | 0mph | 0mph | |Kia|Stinger 2018-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai C|
| Hyundai | Kona Hybrid 2020 | SCC + LKAS | Stock | 0mph | 0mph | |Kia|Stinger 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai K|
| Hyundai | Santa Fe 2019-20 | All | Stock | 0mph | 0mph | |Kia|Telluride 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Hyundai H|
| Hyundai | Santa Fe 2021-22 | All | Stock | 0mph | 0mph | |Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Hyundai | Santa Fe Hybrid 2022 | All | Stock | 0mph | 0mph | |Lexus|ES 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Hyundai | Santa Fe Plug-in Hybrid 2022 | All | Stock | 0mph | 0mph | |Lexus|ES Hybrid 2017-18|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Hyundai | Sonata 2018-2019 | SCC + LKAS | Stock | 0mph | 0mph | |Lexus|ES Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Hyundai | Sonata Hybrid 2021-22 | All | Stock | 0mph | 0mph | |Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Hyundai | Veloster 2019-20 | SCC + LKAS | Stock | 5mph | 0mph | |Lexus|NX 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Stock | 0mph | 9mph | |Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Jeep | Grand Cherokee 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph | |Lexus|NX Hybrid 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Kia | Ceed 2019 | SCC + LKAS | Stock | 0mph | 0mph | |Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Kia | Forte 2018-21 | SCC + LKAS | Stock | 0mph | 0mph | |Lexus|RC 2017-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Kia | K5 2021-22 | SCC + LFA | Stock | 0mph | 0mph | |Lexus|RX 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Kia | Niro EV 2019-22 | All | Stock | 0mph | 0mph | |Lexus|RX 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Kia | Niro Hybrid 2021 | SCC + LKAS | Stock | 0mph | 0mph | |Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Kia | Niro PHEV 2019 | SCC + LKAS | Stock | 10mph | 32mph | |Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Kia | Optima 2017 | SCC + LKAS | Stock | 0mph | 32mph | |Lexus|RX Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Kia | Optima 2019 | SCC + LKAS | Stock | 0mph | 0mph | |Lexus|RX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Kia | Seltos 2021 | SCC + LKAS | Stock | 0mph | 0mph | |Lexus|UX Hybrid 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Kia | Sorento 2018-19 | SCC + LKAS | Stock | 0mph | 0mph | |Mazda|CX-5 2022-23|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|
| Kia | Stinger 2018 | SCC + LKAS | Stock | 0mph | 0mph | |Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Mazda|
| Kia | Telluride 2020 | SCC + LKAS | Stock | 0mph | 0mph | |Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan B|
| Mazda | CX-5 2022 | All | Stock | 0mph | 0mph | |Nissan|Leaf 2018-22|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|
| Mazda | CX-9 2021 | All | Stock | 0mph | 28mph | |Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|
| Nissan | Altima 2019-20 | ProPILOT | Stock | 0mph | 0mph | |Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Nissan A|
| Nissan | Leaf 2018-22 | ProPILOT | Stock | 0mph | 0mph | |Ram|1500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Ram|
| Nissan | Rogue 2018-20 | ProPILOT | Stock | 0mph | 0mph | |SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Nissan | X-Trail 2017 | ProPILOT | Stock | 0mph | 0mph | |SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| SEAT | Ateca 2018 | Driver Assistance | Stock | 0mph | 0mph | |Subaru|Ascent 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
| SEAT | Leon 2014-2020 | Driver Assistance | Stock | 0mph | 0mph | |Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
| Subaru | Ascent 2019 | EyeSight | Stock | 0mph | 0mph | |Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
| Subaru | Crosstrek 2018-20 | EyeSight | Stock | 0mph | 0mph | |Subaru|Forester 2019-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
| Subaru | Forester 2019-21 | EyeSight | Stock | 0mph | 0mph | |Subaru|Impreza 2017-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
| Subaru | Impreza 2017-19 | EyeSight | Stock | 0mph | 0mph | |Subaru|Impreza 2020-22|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
| Škoda | Kamiq 2021<sup>2</sup> | Driver Assistance | Stock | 0mph | 0mph | |Subaru|Legacy 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|
| Škoda | Karoq 2019 | Driver Assistance | Stock | 0mph | 0mph | |Subaru|Outback 2020-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru B|
| Škoda | Kodiaq 2018-19 | Driver Assistance | Stock | 0mph | 0mph | |Subaru|XV 2018-19|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
| Škoda | Octavia 2015, 2018-19 | Driver Assistance | Stock | 0mph | 0mph | |Subaru|XV 2020-21|EyeSight Driver Assistance|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Subaru A|
| Škoda | Octavia RS 2016 | Driver Assistance | Stock | 0mph | 0mph | |Škoda|Kamiq 2021[<sup>7</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)|
| Škoda | Scala 2020 | Driver Assistance | Stock | 0mph | 0mph | |Škoda|Karoq 2019-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Škoda | Superb 2015-18 | Driver Assistance | Stock | 0mph | 0mph | |Škoda|Kodiaq 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Volkswagen| Arteon 2018, 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph | |Škoda|Octavia 2015, 2018-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Volkswagen| Atlas 2018-19, 2022<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph | |Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Volkswagen| Caravelle 2020<sup>4</sup> | Driver Assistance | Stock | 0mph | 32mph | |Škoda|Scala 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)|
| Volkswagen| California 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 32mph | |Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
| Volkswagen| e-Golf 2014, 2019-20 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Volkswagen| Golf 2015-20 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Volkswagen| Golf Alltrack 2017-18 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Volkswagen| Golf GTE 2016 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Avalon 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Volkswagen| Golf GTI 2018-20 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Avalon 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Volkswagen| Golf R 2016-19 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Volkswagen| Golf SportsVan 2016 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Avalon Hybrid 2019-21|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Volkswagen| Golf SportWagen 2015 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Volkswagen| Jetta 2018-20 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|C-HR 2017-21|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Volkswagen| Jetta GLI 2021 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|C-HR Hybrid 2017-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Volkswagen| Passat 2016-18<sup>3</sup> | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Camry 2018-20|All|Stock|0 mph[<sup>6</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Volkswagen| Polo 2020 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Camry 2021-22|All|openpilot|0 mph[<sup>6</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Volkswagen| T-Cross 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Volkswagen| T-Roc 2021<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Camry Hybrid 2021-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Volkswagen| Taos 2022<sup>4</sup> | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Corolla 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
| Volkswagen| Tiguan 2020 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
| Volkswagen| Touran 2017 | Driver Assistance | Stock | 0mph | 0mph | |Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
<sup>1</sup>Requires an [OBD-II car harness](https://comma.ai/shop/products/comma-car-harness) and [community built ASCM harness](https://github.com/commaai/openpilot/wiki/GM#hardware). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).*** <br /> |Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
<sup>2</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br /> |Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
<sup>3</sup>Not including the USA/China market Passat, which is based on the (currently) unsupported PQ35/NMS platform. <br /> |Toyota|Highlander 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
<sup>4</sup>Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma store. Before ordering, |Toyota|Highlander 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
remove the Lane Assist camera cover and check to see if the connector is black (older design) or light brown (newer design). For the newer design, |Toyota|Highlander Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
in the interim, choose "VW J533 Development" from the vehicle drop-down for a harness that integrates at the CAN gateway inside the dashboard.<br /> |Toyota|Highlander Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
Community Maintained Cars and Features are not verified by comma to meet our [safety model](SAFETY.md). Be extra cautious using them. |Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
To promote a car from community maintained, it must meet a few requirements. We must own one from the brand, we must sell the harness for it, has full ISO26262 in both panda and openpilot, there must be a path forward for longitudinal control, it must have AEB still enabled, and it must support fingerprinting 2.0 |Toyota|Prius 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Prius Prime 2017-20|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|RAV4 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|Toyota|
|Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|Toyota|
|Volkswagen|Arteon 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Arteon eHybrid 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Arteon R 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|California 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat 2015-22[<sup>8</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Polo 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)|
|Volkswagen|Polo GTI 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)|
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)|
|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533[<sup>10</sup>](#footnotes)|
|Volkswagen|Taos 2022|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Tiguan 2019-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
|Volkswagen|Touran 2017|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,9</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|J533|
<a id="footnotes"></a>
<sup>1</sup>Experimental openpilot longitudinal control is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`. <br />
<sup>2</sup>By default, this car will use the stock Adaptive Cruise Control (ACC) for longitudinal control. If the Driver Support Unit (DSU) is disconnected, openpilot ACC will replace stock ACC. <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b> <br />
<sup>3</sup>Requires a <a href="https://github.com/commaai/openpilot/wiki/GM#hardware">community built ASCM harness</a>. <b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b> <br />
<sup>4</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
<sup>5</sup>Requires a <a href="https://comma.ai/shop/panda" target="_blank">red panda</a>, additional <a href="https://comma.ai/shop/harness-box" target="_blank">harness box</a>, additional <a href="https://comma.ai/shop/obd-c-cable" target="_blank">OBD-C cable</a>, USB-A to USB-A cable, and a USB-A to USB-C OTG dongle. <br />
<sup>6</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>7</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>8</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
<sup>9</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br />
<sup>10</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
## Community Maintained Cars
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/). Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).
# Don't see your car here?
**openpilot can support many more cars than it currently does.** There are a few reasons your car may not be supported.
If your car doesn't fit into any of the incompatibility criteria here, then there's a good chance it can be supported! We're adding support for new cars all the time. **We don't have a roadmap for car support**, and in fact, most car support comes from users like you!
### Which cars are able to be supported?
openpilot uses the existing steering, gas, and brake interfaces in your car. If your car lacks any one of these interfaces, openpilot will not be able to control the car. If your car has [ACC](https://en.wikipedia.org/wiki/Adaptive_cruise_control) and any form of [LKAS](https://en.wikipedia.org/wiki/Automated_Lane_Keeping_Systems)/[LCA](https://en.wikipedia.org/wiki/Lane_centering), then it almost certainly has these interfaces. These features generally started shipping on cars around 2016. Note that manufacturers will often make their own [marketing terms](https://en.wikipedia.org/wiki/Adaptive_cruise_control#Vehicle_models_supporting_adaptive_cruise_control) for these features, such as Hyundai's "Smart Cruise Control" branding of Adaptive Cruise Control.
If your car has the following packages or features, then it's a good candidate for support.
| Make | Required Package/Features |
| ---- | ------------------------- |
| Acura | Any car with AcuraWatch Plus will work. AcuraWatch Plus comes standard on many newer models. |
| Honda | Any car with Honda Sensing will work. Honda Sensing comes standard on many newer models. |
| Subaru | Any car with EyeSight will work. EyeSight comes standard on many newer models. |
| Nissan | Any car with ProPILOT will likely work. |
| Toyota & Lexus | Any car that has Toyota/Lexus Safety Sense with "Lane Departure Alert with Steering Assist (LDA w/SA)" and/or "Lane Tracing Assist (LTA)" will work. Note that LDA without Steering Assist will not work. These features come standard on most newer models. |
| Hyundai, Kia, & Genesis | Any car with Smart Cruise Control (SCC) and Lane Following Assist (LFA) or Lane Keeping Assist (LKAS) will work. LKAS/LFA comes standard on most newer models. Any form of SCC will work, such as NSCC. |
| Chrysler, Jeep, & Ram | Any car with LaneSense and Adaptive Cruise Control will likely work. These come standard on many newer models. |
### FlexRay
All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the cars in your computer can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay.
### Toyota Security
openpilot does not yet support these Toyota models due to a new message authentication method.
[Vote](https://comma.ai/shop/products/vote) if you'd like to see openpilot support on these models.
* Toyota RAV4 Prime 2021+
* Toyota Sienna 2021+
* Toyota Venza 2021+
* Toyota Sequoia 2023+
* Toyota Tundra 2022+
* Toyota Corolla Cross 2022+ (only US model)
* Lexus NX 2022+
* Toyota bZ4x 2023+
* Subaru Solterra 2023+

@ -8,4 +8,4 @@ Additionally, on specific supported cars (see ACC column in [supported cars](CAR
* Stock ACC is replaced by openpilot ACC. * Stock ACC is replaced by openpilot ACC.
* openpilot FCW operates in addition to stock FCW. * openpilot FCW operates in addition to stock FCW.
openpilot should preserve all other vehicle's stock features, including, but are not limited to: FCW, Automatic Emergency Braking (AEB), auto high-beam, blind spot warning, and side collision warning. openpilot should preserve all other vehicle's stock features, including, but not limited to: FCW, Automatic Emergency Braking (AEB), auto high-beam, blind spot warning, and side collision warning.

@ -32,7 +32,7 @@ clean:
@echo "Copying docs & config to build folder..." @echo "Copying docs & config to build folder..."
cp -a "$(DOCSDIR)" "$(BUILDDIR)" cp -a "$(DOCSDIR)" "$(BUILDDIR)"
cd "$(OPENPILOT_ROOT)" && \ cd "$(OPENPILOT_ROOT)" && \
find . -type f \( -name "*.md" -o -name "*.rst" -o -name "*.png" -o -name "*.jpg" \) \ find . -type f \( -name "*.md" -o -name "*.rst" -o -name "*.png" -o -name "*.jpg" -o -name "*.svg" \) \
-not -path "*/.*" \ -not -path "*/.*" \
-not -path "./build/*" \ -not -path "./build/*" \
-not -path "./docs/*" \ -not -path "./docs/*" \

@ -22,7 +22,7 @@ Following Hazard and Risk Analysis and FMEA, at a very high level, we have desig
ensuring two main safety requirements. 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. by stepping on the brake pedal or by pressing the cancel button.
2. The vehicle must not alter its trajectory too quickly for the driver to safely 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 react. This means that while the system is engaged, the actuators are constrained
to operate within reasonable limits. to operate within reasonable limits.

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="19.999983"
height="19"
viewBox="0 0 19.999983 19"
version="1.1"
id="svg1425"
sodipodi:docname="icon-star-empty.svg"
style="fill:none"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata1431">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1429" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1198"
inkscape:window-height="631"
id="namedview1427"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-8.3559301"
inkscape:cy="8.9999925"
inkscape:window-x="0"
inkscape:window-y="1267"
inkscape:window-maximized="0"
inkscape:current-layer="svg1425" />
<path
d="m 10.258402,14.841908 -0.2584,-0.1559 -0.2583999,0.1559 -5.16547,3.1177 1.3708,-5.876 0.06856,-0.2939 -0.2281,-0.1976 -4.56431,-3.9540698 6.00919,-0.50982 0.30043,-0.02549 0.11766,-0.27761 2.3496399,-5.54381 2.3496,5.54381 0.1177,0.27761 0.3004,0.02549 6.0092,0.50982 -4.5643,3.9540698 -0.2281,0.1976 0.0686,0.2939 1.3708,5.876 z"
id="path1423"
inkscape:connector-curvature="0"
style="stroke:#b7b7b7" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="19.999983"
height="19"
viewBox="0 0 19.999983 19"
version="1.1"
id="svg817"
sodipodi:docname="icon-star-full.svg"
style="fill:none"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata823">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs821" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1198"
inkscape:window-height="1898"
id="namedview819"
showgrid="false"
inkscape:zoom="20.005229"
inkscape:cx="8.4325646"
inkscape:cy="3.9969093"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg817" />
<path
d="m 10.258402,14.841908 -0.2584,-0.1559 -0.2583999,0.1559 -5.16547,3.1177 1.3708,-5.876 0.06856,-0.2939 -0.2281,-0.1976 -4.56431,-3.9540698 6.00919,-0.50982 0.30043,-0.02549 0.11766,-0.27761 2.3496399,-5.54381 2.3496,5.54381 0.1177,0.27761 0.3004,0.02549 6.0092,0.50982 -4.5643,3.9540698 -0.2281,0.1976 0.0686,0.2939 1.3708,5.876 z"
id="path815"
inkscape:connector-curvature="0"
style="fill:#f5c543;stroke:#f0a43b" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="19.999983"
height="19.000008"
viewBox="0 0 19.999983 19.000008"
version="1.1"
id="svg831"
sodipodi:docname="icon-star-half.svg"
style="fill:none"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata837">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs835" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1198"
inkscape:window-height="948"
id="namedview833"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-8.3559301"
inkscape:cy="9"
inkscape:window-x="0"
inkscape:window-y="950"
inkscape:window-maximized="0"
inkscape:current-layer="svg831" />
<path
d="M 10.000002,8.1671631e-6 V 15.270008 l -6.1799999,3.73 1.64,-7.03 L 2.0565151e-6,7.2400082 7.1900021,6.6300082 Z"
id="path825"
inkscape:connector-curvature="0"
style="fill:#f5c543" />
<path
d="m 10.258402,14.841908 -0.2584,-0.1559 -0.2583999,0.1559 -5.16547,3.1177 1.3708,-5.876 0.06856,-0.2939 -0.2281,-0.1976 -4.56431,-3.9540698 6.00919,-0.50982 0.30043,-0.02549 0.11766,-0.27761 2.3496399,-5.54381 2.3496,5.54381 0.1177,0.27761 0.3004,0.02549 6.0092,0.50982 -4.5643,3.9540698 -0.2281,0.1976 0.0686,0.2939 1.3708,5.876 z"
id="path827"
inkscape:connector-curvature="0"
style="stroke:#b7b7b7" />
<path
d="m 5.3322621,16.919208 3.66774,-2.2137 0.9999999,-0.6055 v 1.17 l -6.1799999,3.73 1.64,-7.03 L 2.0565151e-6,7.2400082 7.1900021,6.6300082 10.000002,8.1671631e-6 V 2.6000082 l -0.9999999,2.32203 -1.1246,2.65341 -5.42923,0.46066 4.12481,3.5732998 z"
id="path829"
inkscape:connector-curvature="0"
style="fill:#f0a43b" />
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -28,11 +28,9 @@ selfdrive
camerad camerad
^^^^^^^ ^^^^^^^
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_camerad_cameras :project: system_camerad_cameras
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_camerad_transforms :project: system_camerad_imgproc
.. autodoxygenindex::
:project: selfdrive_camerad_imgproc
locationd locationd
^^^^^^^^^ ^^^^^^^^^
@ -50,15 +48,11 @@ soundd
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_ui_soundd :project: selfdrive_ui_soundd
navd
""""
.. autodoxygenindex::
:project: selfdrive_ui_navd
replay replay
"""""" """"""
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_ui_replay :project: tools_replay
qt qt
"" ""
@ -70,7 +64,7 @@ qt
proclogd proclogd
^^^^^^^^ ^^^^^^^^
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_proclogd :project: system_proclogd
modeld modeld
^^^^^^ ^^^^^^
@ -78,15 +72,13 @@ modeld
:project: selfdrive_modeld_transforms :project: selfdrive_modeld_transforms
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_modeld_models :project: selfdrive_modeld_models
.. autodoxygenindex::
:project: selfdrive_modeld_thneed
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_modeld_runners :project: selfdrive_modeld_runners
common common
^^^^^^ ^^^^^^
.. autodoxygenindex:: .. autodoxygenindex::
:project: selfdrive_common :project: common
sensorsd sensorsd
^^^^^^^^ ^^^^^^^^

@ -14,10 +14,12 @@
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
# #
import os import os
from os.path import exists
import sys import sys
from selfdrive.version import get_version from os.path import exists
from common.basedir import BASEDIR from common.basedir import BASEDIR
from system.version import get_version
sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('..')) sys.path.insert(0, os.path.abspath('..'))

@ -4,16 +4,11 @@ ENV PYTHONUNBUFFERED 1
ENV OPENPILOT_PATH /home/batman/openpilot/ ENV OPENPILOT_PATH /home/batman/openpilot/
ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH} ENV PYTHONPATH ${OPENPILOT_PATH}:${PYTHONPATH}
ENV POETRY_VIRUALENVS_CREATE false
RUN mkdir -p ${OPENPILOT_PATH} RUN mkdir -p ${OPENPILOT_PATH}
WORKDIR ${OPENPILOT_PATH} WORKDIR ${OPENPILOT_PATH}
COPY Pipfile Pipfile.lock $OPENPILOT_PATH
RUN pip install --no-cache-dir pipenv==2021.5.29 pip==21.3.1 && \
pipenv install --system --deploy --dev --clear && \
pip uninstall -y pipenv
COPY SConstruct ${OPENPILOT_PATH} COPY SConstruct ${OPENPILOT_PATH}
COPY ./pyextra ${OPENPILOT_PATH}/pyextra COPY ./pyextra ${OPENPILOT_PATH}/pyextra
@ -30,6 +25,7 @@ COPY ./opendbc ${OPENPILOT_PATH}/opendbc
COPY ./cereal ${OPENPILOT_PATH}/cereal COPY ./cereal ${OPENPILOT_PATH}/cereal
COPY ./panda ${OPENPILOT_PATH}/panda COPY ./panda ${OPENPILOT_PATH}/panda
COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive
COPY ./system ${OPENPILOT_PATH}/system
COPY ./*.md ${OPENPILOT_PATH}/ COPY ./*.md ${OPENPILOT_PATH}/
RUN scons -j$(nproc) RUN scons -j$(nproc)

@ -1,2 +0,0 @@
#!/usr/bin/bash
echo "this is a compatability shim for old updaters"

@ -1 +1 @@
Subproject commit dec99a0f77328f7a9f104020d98d7227345d1288 Subproject commit e1049cde0a68f7d4a70b1ebd76befdc0e163ad55

@ -8,110 +8,13 @@ source "$BASEDIR/launch_env.sh"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
function two_init { function agnos_init {
# set IO scheduler
setprop sys.io.scheduler noop
for f in /sys/block/*/queue/scheduler; do
echo noop > $f
done
# *** shield cores 2-3 ***
# TODO: should we enable this?
# offline cores 2-3 to force recurring timers onto the other cores
#echo 0 > /sys/devices/system/cpu/cpu2/online
#echo 0 > /sys/devices/system/cpu/cpu3/online
#echo 1 > /sys/devices/system/cpu/cpu2/online
#echo 1 > /sys/devices/system/cpu/cpu3/online
# android gets two cores
echo 0-1 > /dev/cpuset/background/cpus
echo 0-1 > /dev/cpuset/system-background/cpus
echo 0-1 > /dev/cpuset/foreground/cpus
echo 0-1 > /dev/cpuset/foreground/boost/cpus
echo 0-1 > /dev/cpuset/android/cpus
# openpilot gets all the cores
echo 0-3 > /dev/cpuset/app/cpus
# mask off 2-3 from RPS and XPS - Receive/Transmit Packet Steering
echo 3 | tee /sys/class/net/*/queues/*/rps_cpus
echo 3 | tee /sys/class/net/*/queues/*/xps_cpus
# *** set up governors ***
# +50mW offroad, +500mW onroad for 30% more RAM bandwidth
echo "performance" > /sys/class/devfreq/soc:qcom,cpubw/governor
echo 1056000 > /sys/class/devfreq/soc:qcom,m4m/max_freq
echo "performance" > /sys/class/devfreq/soc:qcom,m4m/governor
# unclear if these help, but they don't seem to hurt
echo "performance" > /sys/class/devfreq/soc:qcom,memlat-cpu0/governor
echo "performance" > /sys/class/devfreq/soc:qcom,memlat-cpu2/governor
# GPU
echo "performance" > /sys/class/devfreq/b00000.qcom,kgsl-3d0/governor
# /sys/class/devfreq/soc:qcom,mincpubw is the only one left at "powersave"
# it seems to gain nothing but a wasted 500mW
# *** set up IRQ affinities ***
# 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)
echo 1 > /proc/irq/6/smp_affinity_list # MDSS
# USB traffic needs realtime handling on cpu 3
[ -d "/proc/irq/733" ] && echo 3 > /proc/irq/733/smp_affinity_list
# GPU and camera get cpu 2
CAM_IRQS="177 178 179 180 181 182 183 184 185 186 192"
for irq in $CAM_IRQS; do
echo 2 > /proc/irq/$irq/smp_affinity_list
done
echo 2 > /proc/irq/193/smp_affinity_list # GPU
# give GPU threads RT priority
for pid in $(pgrep "kgsl"); do
chrt -f -p 52 $pid
done
# the flippening!
LD_LIBRARY_PATH="" content insert --uri content://settings/system --bind name:s:user_rotation --bind value:i:1
# disable bluetooth
service call bluetooth_manager 8
# wifi scan
wpa_cli IFNAME=wlan0 SCAN
# Check for NEOS update
if [ $(< /VERSION) != "$REQUIRED_NEOS_VERSION" ]; then
echo "Installing NEOS update"
NEOS_PY="$DIR/selfdrive/hardware/eon/neos.py"
MANIFEST="$DIR/selfdrive/hardware/eon/neos.json"
$NEOS_PY --swap-if-ready $MANIFEST
$DIR/selfdrive/hardware/eon/updater $NEOS_PY $MANIFEST
fi
}
function tici_init {
# wait longer for weston to come up # wait longer for weston to come up
if [ -f "$BASEDIR/prebuilt" ]; then if [ -f "$BASEDIR/prebuilt" ]; then
sleep 3 sleep 3
fi fi
# setup governors
sudo su -c 'echo "performance" > /sys/class/devfreq/soc:qcom,memlat-cpu0/governor'
sudo su -c 'echo "performance" > /sys/class/devfreq/soc:qcom,memlat-cpu4/governor'
# TODO: move this to agnos # TODO: move this to agnos
# network manager config
nmcli connection modify --temporary lte gsm.auto-config yes
nmcli connection modify --temporary lte gsm.home-only yes
sudo rm -f /data/etc/NetworkManager/system-connections/*.nmmeta sudo rm -f /data/etc/NetworkManager/system-connections/*.nmmeta
# set success flag for current boot slot # set success flag for current boot slot
@ -119,12 +22,12 @@ function tici_init {
# Check if AGNOS update is required # Check if AGNOS update is required
if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then
AGNOS_PY="$DIR/selfdrive/hardware/tici/agnos.py" AGNOS_PY="$DIR/system/hardware/tici/agnos.py"
MANIFEST="$DIR/selfdrive/hardware/tici/agnos.json" MANIFEST="$DIR/system/hardware/tici/agnos.json"
if $AGNOS_PY --verify $MANIFEST; then if $AGNOS_PY --verify $MANIFEST; then
sudo reboot sudo reboot
fi fi
$DIR/selfdrive/hardware/tici/updater $AGNOS_PY $MANIFEST $DIR/system/hardware/tici/updater $AGNOS_PY $MANIFEST
fi fi
} }
@ -159,7 +62,6 @@ function launch {
cd $BASEDIR cd $BASEDIR
echo "Restarting launch script ${LAUNCHER_LOCATION}" echo "Restarting launch script ${LAUNCHER_LOCATION}"
unset REQUIRED_NEOS_VERSION
unset AGNOS_VERSION unset AGNOS_VERSION
exec "${LAUNCHER_LOCATION}" exec "${LAUNCHER_LOCATION}"
else else
@ -175,11 +77,7 @@ function launch {
export PYTHONPATH="$PWD:$PWD/pyextra" export PYTHONPATH="$PWD:$PWD/pyextra"
# hardware specific init # hardware specific init
if [ -f /EON ]; then agnos_init
two_init
elif [ -f /TICI ]; then
tici_init
fi
# write tmux scrollback to a file # write tmux scrollback to a file
tmux capture-pane -pq -S-1000 > /tmp/launch_log tmux capture-pane -pq -S-1000 > /tmp/launch_log

@ -6,12 +6,8 @@ export NUMEXPR_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1 export OPENBLAS_NUM_THREADS=1
export VECLIB_MAXIMUM_THREADS=1 export VECLIB_MAXIMUM_THREADS=1
if [ -z "$REQUIRED_NEOS_VERSION" ]; then
export REQUIRED_NEOS_VERSION="19.1"
fi
if [ -z "$AGNOS_VERSION" ]; then if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="4" export AGNOS_VERSION="6.2"
fi fi
if [ -z "$PASSIVE" ]; then if [ -z "$PASSIVE" ]; then

@ -1,109 +0,0 @@
## Neural networks in openpilot
To view the architecture of the ONNX networks, you can use [netron](https://netron.app/)
## Supercombo
### Supercombo input format (Full size: 393738 x float32)
* **image stream**
* Two consecutive images (256 * 512 * 3 in RGB) recorded at 20 Hz : 393216 = 2 * 6 * 128 * 256
* Each 256 * 512 image is represented in YUV420 with 6 channels : 6 * 128 * 256
* Channels 0,1,2,3 represent the full-res Y channel and are represented in numpy as Y[::2, ::2], Y[::2, 1::2], Y[1::2, ::2], and Y[1::2, 1::2]
* Channel 4 represents the half-res U channel
* Channel 5 represents the half-res V channel
* **desire**
* one-hot encoded vector to command model to execute certain actions, bit only needs to be sent for 1 frame : 8
* **traffic convention**
* one-hot encoded vector to tell model whether traffic is right-hand or left-hand traffic : 2
* **recurrent state**
* The recurrent state vector that is fed back into the GRU for temporal context : 512
### Supercombo output format (Full size: 6472 x float32)
* **plan**
* 5 potential desired plan predictions : 4955 = 5 * 991
* predicted mean and standard deviation of the following values at 33 timesteps : 990 = 2 * 33 * 15
* x,y,z position in current frame (meters)
* x,y,z velocity in local frame (meters/s)
* x,y,z acceleration local frame (meters/(s*s))
* roll, pitch , yaw in current frame (radians)
* roll, pitch , yaw rates in local frame (radians/s)
* probability[^1] of this plan hypothesis being the most likely: 1
* **lanelines**
* 4 lanelines (outer left, left, right, and outer right): 528 = 4 * 132
* predicted mean and standard deviation for the following values at 33 x positions : 132 = 2 * 33 * 2
* y position in current frame (meters)
* z position in current frame (meters)
* **laneline probabilties**
* 2 probabilities[^1] that each of the 4 lanelines exists : 8 = 4 * 2
* deprecated probability
* used probability
* **road-edges**
* 2 road-edges (left and right): 264 = 2 * 132
* predicted mean and standard deviation for the following values at 33 x positions : 132 = 2 * 33 * 2
* y position in current frame (meters)
* z position in current frame (meters)
* **leads**
* 2 hypotheses for potential lead cars : 102 = 2 * 51
* predicted mean and stadard deviation for the following values at 0,2,4,6,8,10s : 48 = 2 * 6 * 4
* x position of lead in current frame (meters)
* y position of lead in current frame (meters)
* speed of lead (meters/s)
* acceleration of lead(meters/(s*s))
* probabilities[^1] this hypothesis is the most likely hypothesis at 0s, 2s or 4s from now : 3
* **lead probabilities**
* probability[^1] that there is a lead car at 0s, 2s, 4s from now : 3 = 1 * 3
* **desire state**
* probability[^1] that the model thinks it is executing each of the 8 potential desire actions : 8
* **meta** [^2]
* Various metadata about the scene : 80 = 1 + 35 + 12 + 32
* Probability[^1] that openpilot is engaged : 1
* Probabilities[^1] of various things happening between now and 2,4,6,8,10s : 35 = 5 * 7
* Disengage of openpilot with gas pedal
* Disengage of openpilot with brake pedal
* Override of openpilot steering
* 3m/(s*s) of deceleration
* 4m/(s*s) of deceleration
* 5m/(s*s) of deceleration
* Probabilities[^1] of left or right blinker being active at 0,2,4,6,8,10s : 12 = 6 * 2
* Probabilities[^1] that each of the 8 desires is being executed at 0,2,4,6s : 32 = 4 * 8
* **pose** [^2]
* predicted mean and standard deviation of current translation and rotation rates : 12 = 2 * 6
* x,y,z velocity in current frame (meters/s)
* roll, pitch , yaw rates in current frame (radians/s)
* **recurrent state**
* The recurrent state vector that is fed back into the GRU for temporal context : 512
[^1]: All probabilities are in logits, so you need to apply sigmoid or softmax functions to get actual probabilities
[^2]: These outputs come directly from the vision blocks, they do not have access to temporal state or the desire input
## Driver Monitoring Model
* .onnx model can be run with onnx runtimes
* .dlc file is a pre-quantized model and only runs on qualcomm DSPs
### input format
* single image (640 * 320 * 3 in RGB):
* full input size is 6 * 640/2 * 320/2 = 307200
* represented in YUV420 with 6 channels:
* Channels 0,1,2,3 represent the full-res Y channel and are represented in numpy as Y[::2, ::2], Y[::2, 1::2], Y[1::2, ::2], and Y[1::2, 1::2]
* Channel 4 represents the half-res U channel
* Channel 5 represents the half-res V channel
* normalized, ranging from -1.0 to 1.0
### output format
* 39 x float32 outputs ([parsing example](https://github.com/commaai/openpilot/blob/master/selfdrive/modeld/models/dmonitoring.cc#L165))
* face pose: 12 = 6 + 6
* face orientation [pitch, yaw, roll] in camera frame: 3
* face position [dx, dy] relative to image center: 2
* normalized face size: 1
* standard deviations for above outputs: 6
* face visible probability: 1
* eyes: 20 = (8 + 1) + (8 + 1) + 1 + 1
* eye position and size, and their standard deviations: 8
* eye visible probability: 1
* eye closed probability: 1
* wearing sunglasses probability: 1
* poor camera vision probability: 1
* face partially out-of-frame probability: 1
* (deprecated) distracted probabilities: 2
* face covered probability: 1

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ba3fe3e61853cc1434e3e220f40c8e9d1f1b9bab8458196ba3bea6a10b82c6ed
size 72718099

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bda57c1a66944f5a633ecd739a24d62702c717a234f2fdcc499dfa1d61c3c19e
size 73147489

@ -1,2 +0,0 @@
4e19be90-bd5b-485d-b79a-2462f7f1b49e
08f7ec37b78228cd1cb750b6ddb9c6ba1769e911

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:895ee32e2a1c77496e015270db475eef65034b25331f2859bac0ccf702f64298
size 3294407

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6e4ac870984d11cd8e86cda4a63e3321fde837bacf4a055a27b7c8ba34facfe2
size 916079

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:209e9544e456dbc2a7d60490da65154e129bc84830909d8d931f97b3df93949b
size 56684955

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2365bae967cce21ce68707c30bf2981bb7081ee5c3e6a3dff793e660f23ff622
size 57554657

@ -1,4 +1,16 @@
[mypy] [mypy]
python_version = 3.8 python_version = 3.8
plugins = numpy.typing.mypy_plugin
files = body, common, docs, scripts, selfdrive, site_scons, system, tools
exclude = ^(pyextra/)|(cereal/)|(opendbc/)|(panda/)|(laika/)|(laika_repo/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(xx/)
; third-party packages
ignore_missing_imports = True ignore_missing_imports = True
; helpful warnings
warn_redundant_casts = True
warn_unreachable = True
warn_unused_ignores = True
; restrict dynamic typing
warn_return_any = True

@ -1 +1 @@
Subproject commit 46a942d6790531cf5b94b14266140e43afcfda3e Subproject commit 94fff4782be263efad10032a612b3c96a120c0b7

@ -1 +1 @@
Subproject commit cb88a1756ba2b8b06e06102691c75f8aa87f687b Subproject commit 4edd1a602131ec2f09a604a4bd28e7d00e334458

8030
poetry.lock generated

File diff suppressed because it is too large Load Diff

@ -5,6 +5,9 @@
"acados_include_path": [ "acados_include_path": [
"str" "str"
], ],
"cython_include_dirs": [
"str"
],
"model": { "model": {
"name" : [ "name" : [
"str" "str"
@ -23,7 +26,15 @@
], ],
"dyn_disc_fun" : [ "dyn_disc_fun" : [
"str" "str"
],
"gnsf" : {
"nontrivial_f_LO": [
"int"
],
"purely_linear": [
"int"
] ]
}
}, },
"parameter_values": [ "parameter_values": [
"ndarray", "ndarray",
@ -657,6 +668,9 @@
"hessian_approx": [ "hessian_approx": [
"str" "str"
], ],
"hpipm_mode": [
"str"
],
"regularize_method": [ "regularize_method": [
"str" "str"
], ],
@ -693,6 +707,18 @@
"alpha_reduction": [ "alpha_reduction": [
"float" "float"
], ],
"line_search_use_sufficient_descent": [
"int"
],
"globalization_use_SOC": [
"int"
],
"full_step_dual": [
"int"
],
"eps_sufficient_descent": [
"float"
],
"sim_method_num_stages": [ "sim_method_num_stages": [
"ndarray", "ndarray",
[ [

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

Loading…
Cancel
Save