Merge remote-tracking branch 'upstream/master' into gm-silverado-wip

pull/24875/head
Shane Smiskol 3 years ago
commit a11d15cb3f
  1. 3
      .github/workflows/badges.yaml
  2. 2
      .github/workflows/prebuilt.yaml
  3. 4
      .github/workflows/selfdrive_tests.yaml
  4. 2
      .github/workflows/tools_tests.yaml
  5. 2
      Jenkinsfile
  6. 122
      docs/CARS.md
  7. 9
      release/build_devel.sh
  8. 8
      selfdrive/car/chrysler/values.py
  9. 1
      selfdrive/car/docs_definitions.py
  10. 10
      selfdrive/car/gm/carcontroller.py
  11. 1
      selfdrive/car/gm/interface.py
  12. 29
      selfdrive/car/gm/values.py
  13. 16
      selfdrive/car/hyundai/values.py
  14. 7
      selfdrive/car/interfaces.py
  15. 2
      selfdrive/car/toyota/carcontroller.py
  16. 27
      selfdrive/manager/test/test_manager.py
  17. 2
      selfdrive/test/process_replay/model_replay_ref_commit
  18. 2
      selfdrive/test/process_replay/ref_commit
  19. 39
      selfdrive/test/test_onroad.py
  20. 3
      selfdrive/ui/qt/maps/map.cc
  21. 8
      selfdrive/ui/qt/onroad.cc
  22. 1
      selfdrive/ui/qt/onroad.h
  23. 9
      selfdrive/ui/qt/util.cc
  24. 16
      selfdrive/ui/tests/test_translations.py
  25. 3
      selfdrive/ui/translations/create_badges.py
  26. 26
      selfdrive/ui/translations/main_ja.ts
  27. 26
      selfdrive/ui/translations/main_ko.ts
  28. 26
      selfdrive/ui/translations/main_zh-CHS.ts
  29. 26
      selfdrive/ui/translations/main_zh-CHT.ts
  30. 6
      selfdrive/ui/update_translations.py
  31. 3
      system/hardware/tici/test_power_draw.py
  32. 17
      tools/plotjuggler/juggle.py
  33. 3
      tools/replay/README.md
  34. 6
      tools/sim/lib/replay.sh

@ -17,7 +17,8 @@ env:
jobs: jobs:
badges: badges:
name: create badges name: create badges
runs-on: ubuntu-latest runs-on: ubuntu-20.04
if: github.repository == 'commaai/openpilot'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:

@ -9,7 +9,7 @@ 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 pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true

@ -11,7 +11,7 @@ env:
DOCKER_REGISTRY: ghcr.io/commaai DOCKER_REGISTRY: ghcr.io/commaai
AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }} 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 pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true
docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true docker pull $DOCKER_REGISTRY/$BASE_IMAGE:latest || true
@ -39,6 +39,8 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- name: Pull LFS
run: git lfs pull
- 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

@ -7,7 +7,7 @@ env:
BASE_IMAGE: openpilot-base BASE_IMAGE: openpilot-base
CL_BASE_IMAGE: openpilot-base-cl 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 pull $(grep -iohP '(?<=^from)\s+\S+' Dockerfile.openpilot_base) || true

2
Jenkinsfile vendored

@ -127,7 +127,7 @@ pipeline {
steps { steps {
phone_steps("tici2", [ phone_steps("tici2", [
["build", "cd selfdrive/manager && ./build.py"], ["build", "cd selfdrive/manager && ./build.py"],
["test power draw", "python system/hardware/tici/test_power_draw.py"], //["test power draw", "python system/hardware/tici/test_power_draw.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 loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"],
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"],

@ -19,7 +19,7 @@ A supported vehicle is one that just works when you install a comma device. Ever
- [![star](assets/icon-star-empty.svg)](##) - Limited ability to make tighter turns. - [![star](assets/icon-star-empty.svg)](##) - Limited ability to make tighter turns.
# 200 Supported Cars # 201 Supported Cars
|Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque| |Make|Model|Supported Package|openpilot ACC|Stop and Go|Steer to 0|Steering Torque|
|---|---|---|:---:|:---:|:---:|:---:| |---|---|---|:---:|:---:|:---:|:---:|
@ -95,11 +95,12 @@ A supported vehicle is one that just works when you install a comma device. Ever
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Ceed 2019|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Ceed 2019|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|EV6 2022[<sup>4</sup>](#footnotes)|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|EV6 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Forte 2018|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Forte 2018|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Forte 2019-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Forte 2019-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|K5 2021-22|Smart Cruise Control (SCC)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|K5 2021-22|Smart Cruise Control (SCC)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Niro Electric 2019-20|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Electric 2019|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Niro Electric 2020|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Niro Electric 2021|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Electric 2021|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Niro Electric 2022|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Electric 2022|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Niro Hybrid 2021|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
@ -112,19 +113,19 @@ A supported vehicle is one that just works when you install a comma device. Ever
|Kia|Sorento 2019|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Sorento 2019|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Stinger 2018-20|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Stinger 2018-20|Smart Cruise Control (SCC) & LKAS|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Kia|Telluride 2020|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Kia|Telluride 2020|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|CT Hybrid 2017-18|Lexus Safety System+|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|ES 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|ES 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|ES Hybrid 2017-18|Lexus Safety System+|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|ES Hybrid 2017-18|Lexus Safety System+|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|ES Hybrid 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|ES Hybrid 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|IS 2017-19|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|IS 2017-19|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|NX 2018-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|NX 2018-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|NX 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|NX 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|NX Hybrid 2018-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|NX Hybrid 2018-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|NX Hybrid 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|NX Hybrid 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|RC 2017-20|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|RC 2017-20|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|RX 2016-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|RX 2016-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|RX 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|RX 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|RX Hybrid 2016-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|RX Hybrid 2016-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|RX Hybrid 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|RX Hybrid 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Lexus|UX Hybrid 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Lexus|UX Hybrid 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Mazda|CX-5 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Mazda|CX-5 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
@ -145,7 +146,7 @@ A supported vehicle is one that just works when you install a comma device. Ever
|Subaru|Outback 2020-22|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Subaru|Outback 2020-22|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Subaru|XV 2018-19|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)| |Subaru|XV 2018-19|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
|Subaru|XV 2020-21|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Subaru|XV 2020-21|EyeSight Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Škoda|Kamiq 2021[<sup>7</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Kamiq 2021[<sup>6</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Škoda|Karoq 2019-21|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Karoq 2019-21|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Škoda|Kodiaq 2018-19|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Kodiaq 2018-19|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Škoda|Octavia 2015, 2018-19|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Octavia 2015, 2018-19|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
@ -154,87 +155,86 @@ A supported vehicle is one that just works when you install a comma device. Ever
|Škoda|Superb 2015-18|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Škoda|Superb 2015-18|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Alphard 2019-20|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Alphard 2019-20|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Alphard Hybrid 2021|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Alphard Hybrid 2021|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Avalon 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Avalon 2017-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon 2017-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Avalon 2019-21|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon 2019-21|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Avalon 2022|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon 2022|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Avalon Hybrid 2019-21|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon Hybrid 2019-21|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Avalon Hybrid 2022|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Avalon Hybrid 2022|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|C-HR 2017-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|C-HR 2017-21|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|C-HR Hybrid 2017-19|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|C-HR Hybrid 2017-19|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Camry 2018-20|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)[<sup>6</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Camry 2018-20|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Camry 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)[<sup>6</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Camry 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Camry Hybrid 2018-20|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)[<sup>6</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Camry Hybrid 2018-20|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Camry Hybrid 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Camry Hybrid 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Corolla 2017-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Corolla 2017-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Corolla 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Corolla 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Corolla Cross (Non-US only) 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Corolla Cross (Non-US only) 2020-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Corolla Hatchback 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Corolla Hatchback 2019-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Corolla Hybrid 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Corolla Hybrid 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Highlander 2017-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Highlander 2017-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Highlander 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Highlander 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Highlander Hybrid 2017-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Highlander Hybrid 2017-19|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Highlander Hybrid 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Highlander Hybrid 2020-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Mirai 2021|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Mirai 2021|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Prius 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Prius 2017-20|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius 2017-20|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Prius 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Prius Prime 2017-20|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius Prime 2017-20|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Prius Prime 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius Prime 2021-22|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Prius v 2017|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Prius v 2017|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|RAV4 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|RAV4 2017-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 2017-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|RAV4 2019-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 2019-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|RAV4 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|RAV4 Hybrid 2017-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 Hybrid 2017-18|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|RAV4 Hybrid 2019-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 Hybrid 2019-21|All|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|RAV4 Hybrid 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|RAV4 Hybrid 2022|All|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Toyota|Sienna 2018-20|All|[![star](assets/icon-star-half.svg)](##)[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Toyota|Sienna 2018-20|All|[![star](assets/icon-star-half.svg)](##)[<sup>4</sup>](#footnotes)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Arteon 2018-22[<sup>9,10</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Arteon 2018-22[<sup>8,9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Arteon eHybrid 2020-22[<sup>9,10</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Arteon eHybrid 2020-22[<sup>8,9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Arteon R 2020-22[<sup>9,10</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Arteon R 2020-22[<sup>8,9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Atlas 2018-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Atlas 2018-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Atlas Cross Sport 2021-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Atlas Cross Sport 2021-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|California 2021[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|California 2021[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Caravelle 2020[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Caravelle 2020[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|CC 2018-22[<sup>9,10</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|CC 2018-22[<sup>8,9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|e-Golf 2014-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|e-Golf 2014-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Golf 2015-20[<sup>10</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf 2015-20[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Golf Alltrack 2015-19|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf Alltrack 2015-19|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Golf GTD 2015-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf GTD 2015-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Golf GTE 2015-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf GTE 2015-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Golf GTI 2015-21|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf GTI 2015-21|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Golf R 2015-19[<sup>10</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf R 2015-19[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Golf SportsVan 2015-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Golf SportsVan 2015-20|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Jetta 2018-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Jetta 2018-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Jetta GLI 2021-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Jetta GLI 2021-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Passat 2015-22[<sup>8,9,10</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Passat 2015-22[<sup>7,8,9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Passat Alltrack 2015-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Passat Alltrack 2015-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Passat GTE 2015-22[<sup>9,10</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Passat GTE 2015-22[<sup>8,9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Polo 2020-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Polo 2020-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Polo GTI 2020-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Polo GTI 2020-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|T-Cross 2021[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|T-Cross 2021[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|T-Roc 2021[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|T-Roc 2021[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Taos 2022[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Taos 2022[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Teramont 2018-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Teramont 2018-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Teramont Cross Sport 2021-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Teramont Cross Sport 2021-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Teramont X 2021-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Teramont X 2021-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Tiguan 2019-22[<sup>9</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Tiguan 2019-22[<sup>8</sup>](#footnotes)|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
|Volkswagen|Touran 2017|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)| |Volkswagen|Touran 2017|Driver Assistance|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
<a id="footnotes"></a> <a id="footnotes"></a>
<sup>1</sup>Requires an <a href="https://comma.ai/shop/products/comma-car-harness">OBD-II car harness</a> and <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>1</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>2</sup>Currently Requires a [harness box](https://comma.ai/shop/products/harness-box) and [community built GM camera harness](https://github.com/commaai/openpilot/wiki/GMCamHarness) <br /> <sup>2</sup>Currently Requires a [harness box](https://comma.ai/shop/products/harness-box) and [community built GM camera harness](https://github.com/commaai/openpilot/wiki/GMCamHarness) <br />
<sup>3</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br /> <sup>3</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
<sup>4</sup>Requires a <a href='https://comma.ai/shop/products/panda'>red panda</a> and additional <a href='https://comma.ai/shop/products/harness-box'>harness box.</a> <br /> <sup>4</sup>When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace stock Adaptive Cruise Control (ACC). <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b> <br />
<sup>5</sup>When the Driver Support Unit (DSU) is disconnected, openpilot Adaptive Cruise Control (ACC) will replace stock Adaptive Cruise Control (ACC). <b><i>NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).</i></b> <br /> <sup>5</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>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>6</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>7</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br /> <sup>7</sup>Not including the USA/China market Passat, which is based on the (currently) unsupported PQ35/NMS platform. <br />
<sup>8</sup>Not including the USA/China market Passat, which is based on the (currently) unsupported PQ35/NMS platform. <br /> <sup>8</sup>Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma store. Before ordering, 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, 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 />
<sup>9</sup>Model-years 2021 and beyond may have a new camera harness design, which isn't yet available from the comma store. Before ordering, 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, 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 /> <sup>9</sup>Includes versions with extra rear cargo space (may be called Variant, Estate, SportWagen, Shooting Brake, etc.) <br />
<sup>10</sup>Includes versions with extra rear cargo space (may be called Variant, Estate, SportWagen, Shooting Brake, etc.) <br />
## Community Maintained Cars ## 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/).

@ -69,6 +69,15 @@ date: $DATETIME
master commit: $GIT_HASH master commit: $GIT_HASH
" "
# ensure files are within GitHub's limit
BIG_FILES="$(find . -type f -not -path './.git/*' -size +95M)"
if [ ! -z "$BIG_FILES" ]; then
printf '\n\n\n'
echo "Found files exceeding GitHub's 100MB limit:"
echo "$BIG_FILES"
exit 1
fi
if [ ! -z "$BRANCH" ]; then if [ ! -z "$BRANCH" ]; then
echo "[-] Pushing to $BRANCH T=$SECONDS" echo "[-] Pushing to $BRANCH T=$SECONDS"
git push -f origin master-ci:$BRANCH git push -f origin master-ci:$BRANCH

@ -56,7 +56,7 @@ CAR_INFO: Dict[str, Optional[Union[ChryslerCarInfo, List[ChryslerCarInfo]]]] = {
], ],
CAR.JEEP_CHEROKEE: ChryslerCarInfo("Jeep Grand Cherokee 2016-18", video_link="https://www.youtube.com/watch?v=eLR9o2JkuRk"), CAR.JEEP_CHEROKEE: ChryslerCarInfo("Jeep Grand Cherokee 2016-18", video_link="https://www.youtube.com/watch?v=eLR9o2JkuRk"),
CAR.JEEP_CHEROKEE_2019: ChryslerCarInfo("Jeep Grand Cherokee 2019-21", video_link="https://www.youtube.com/watch?v=jBe4lWnRSu4"), CAR.JEEP_CHEROKEE_2019: ChryslerCarInfo("Jeep Grand Cherokee 2019-21", video_link="https://www.youtube.com/watch?v=jBe4lWnRSu4"),
CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-22", harness=Harness.none), CAR.RAM_1500: ChryslerCarInfo("Ram 1500 2019-22", harness=Harness.ram),
} }
# Unique CAN messages: # Unique CAN messages:
@ -107,6 +107,10 @@ FINGERPRINTS = {
}], }],
CAR.JEEP_CHEROKEE: [{ CAR.JEEP_CHEROKEE: [{
55: 8, 168: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 788: 3, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 874: 2, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 956: 8, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 975: 8, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1543: 8, 1562: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8 55: 8, 168: 8, 181: 8, 256: 4, 257: 5, 258: 8, 264: 8, 268: 8, 272: 6, 273: 6, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 579: 8, 584: 8, 608: 8, 618: 8, 624: 8, 625: 8, 632: 8, 639: 8, 656: 4, 658: 6, 660: 8, 671: 8, 672: 8, 676: 8, 678: 8, 680: 8, 683: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 738: 8, 746: 5, 752: 2, 754: 8, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 782: 8, 783: 8, 784: 8, 785: 8, 788: 3, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 808: 8, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 840: 8, 844: 5, 847: 1, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 874: 2, 882: 8, 897: 8, 906: 8, 924: 8, 937: 8, 938: 8, 939: 8, 940: 8, 941: 8, 942: 8, 943: 8, 947: 8, 948: 8, 956: 8, 968: 8, 969: 4, 970: 8, 973: 8, 974: 5, 975: 8, 976: 8, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1543: 8, 1562: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
},
# Based on c88f65eeaee4003a|2022-08-04--15-37-16
{
257: 5, 258: 8, 264: 8, 268: 8, 274: 2, 280: 8, 284: 8, 288: 7, 290: 6, 292: 8, 300: 8, 308: 8, 320: 8, 324: 8, 331: 8, 332: 8, 344: 8, 352: 8, 362: 8, 368: 8, 376: 3, 384: 8, 388: 4, 416: 7, 448: 6, 456: 4, 464: 8, 500: 8, 501: 8, 512: 8, 514: 8, 520: 8, 532: 8, 544: 8, 557: 8, 559: 8, 560: 4, 564: 4, 571: 3, 584: 8, 608: 8, 624: 8, 625: 8, 632: 8, 639: 8, 658: 6, 660: 8, 671: 8, 672: 8, 678: 8, 680: 8, 684: 8, 703: 8, 705: 8, 706: 8, 709: 8, 710: 8, 719: 8, 720: 6, 729: 5, 736: 8, 737: 8, 746: 5, 752: 2, 760: 8, 761: 8, 764: 8, 766: 8, 773: 8, 776: 8, 779: 8, 783: 8, 784: 8, 792: 8, 799: 8, 800: 8, 804: 8, 806: 2, 810: 8, 816: 8, 817: 8, 820: 8, 825: 2, 826: 8, 831: 6, 832: 8, 838: 2, 844: 5, 848: 8, 853: 8, 856: 4, 860: 6, 863: 8, 882: 8, 897: 8, 924: 3, 937: 8, 947: 8, 948: 8, 969: 4, 974: 5, 977: 4, 979: 8, 980: 8, 981: 8, 982: 8, 983: 8, 984: 8, 992: 8, 993: 7, 995: 8, 996: 8, 1000: 8, 1001: 8, 1002: 8, 1003: 8, 1008: 8, 1009: 8, 1010: 8, 1011: 8, 1012: 8, 1013: 8, 1014: 8, 1015: 8, 1024: 8, 1025: 8, 1026: 8, 1031: 8, 1033: 8, 1050: 8, 1059: 8, 1062: 8, 1098: 8, 1100: 8, 1216: 8, 1218: 8, 1220: 8, 1223: 8, 1235: 8, 1242: 8, 1252: 8, 1792: 8, 1798: 8, 1799: 8, 1810: 8, 1813: 8, 1824: 8, 1825: 8, 1840: 8, 1856: 8, 1858: 8, 1859: 8, 1860: 8, 1862: 8, 1863: 8, 1872: 8, 1875: 8, 1879: 8, 1882: 8, 1888: 8, 1892: 8, 1927: 8, 1937: 8, 1953: 8, 1968: 8, 1988: 8, 2000: 8, 2001: 8, 2004: 8, 2015: 8, 2016: 8, 2017: 8, 2024: 8, 2025: 8
}], }],
CAR.JEEP_CHEROKEE_2019: [{ CAR.JEEP_CHEROKEE_2019: [{
# Jeep Grand Cherokee 2019, including most 2020 models # Jeep Grand Cherokee 2019, including most 2020 models
@ -138,7 +142,7 @@ FW_VERSIONS = {
b'68535469AB', b'68535469AB',
b'68438454AC', b'68438454AC',
], ],
(Ecu.fwdCamera, 0x753, None): [ (Ecu.fwdRadar, 0x753, None): [
b'68320950AL', b'68320950AL',
b'68320950AJ', b'68320950AJ',
b'68454268AB', b'68454268AB',

@ -188,6 +188,7 @@ class Harness(Enum):
toyota = "Toyota" toyota = "Toyota"
subaru = "Subaru" subaru = "Subaru"
fca = "FCA" fca = "FCA"
ram = "Ram"
vw = "VW" vw = "VW"
j533 = "J533" j533 = "J533"
hyundai_a = "Hyundai A" hyundai_a = "Hyundai A"

@ -5,7 +5,7 @@ from common.realtime import DT_CTRL
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car import apply_std_steer_torque_limits
from selfdrive.car.gm import gmcan from selfdrive.car.gm import gmcan
from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, EV_CAR
VisualAlert = car.CarControl.HUDControl.VisualAlert VisualAlert = car.CarControl.HUDControl.VisualAlert
NetworkLocation = car.CarParams.NetworkLocation NetworkLocation = car.CarParams.NetworkLocation
@ -79,8 +79,12 @@ class CarController:
self.apply_gas = self.params.MAX_ACC_REGEN self.apply_gas = self.params.MAX_ACC_REGEN
self.apply_brake = 0 self.apply_brake = 0
else: else:
self.apply_gas = int(round(interp(actuators.accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))) if self.CP.carFingerprint in EV_CAR:
self.apply_brake = int(round(interp(actuators.accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V))) self.apply_gas = int(round(interp(actuators.accel, self.params.EV_GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V)))
self.apply_brake = int(round(interp(actuators.accel, self.params.EV_BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
else:
self.apply_gas = int(round(interp(actuators.accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V)))
self.apply_brake = int(round(interp(actuators.accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
idx = (self.frame // 4) % 4 idx = (self.frame // 4) % 4

@ -140,6 +140,7 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 14.4 # end to end is 13.46 ret.steerRatio = 14.4 # end to end is 13.46
ret.centerToFront = ret.wheelbase * 0.4 ret.centerToFront = ret.wheelbase * 0.4
ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_acadia() ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_acadia()
ret.longitudinalActuatorDelayUpperBound = 0.5 # large delay to initially start braking
elif candidate == CAR.BUICK_REGAL: elif candidate == CAR.BUICK_REGAL:
ret.mass = 3779. * CV.LB_TO_KG + STD_CARGO_KG # (3849+3708)/2 ret.mass = 3779. * CV.LB_TO_KG + STD_CARGO_KG # (3849+3708)/2

@ -44,13 +44,17 @@ class CarControllerParams:
ACCEL_MAX = 2. # m/s^2 ACCEL_MAX = 2. # m/s^2
ACCEL_MIN = -4. # m/s^2 ACCEL_MIN = -4. # m/s^2
GAS_LOOKUP_BP = [-1., 0., ACCEL_MAX] EV_GAS_LOOKUP_BP = [-1., 0., ACCEL_MAX]
EV_BRAKE_LOOKUP_BP = [ACCEL_MIN, -1.]
# ICE has much less engine braking force compared to regen in EVs,
# lower threshold removes some braking deadzone
GAS_LOOKUP_BP = [-0.1, 0., ACCEL_MAX]
BRAKE_LOOKUP_BP = [ACCEL_MIN, -0.1]
GAS_LOOKUP_V = [MAX_ACC_REGEN, ZERO_GAS, MAX_GAS] GAS_LOOKUP_V = [MAX_ACC_REGEN, ZERO_GAS, MAX_GAS]
BRAKE_LOOKUP_BP = [ACCEL_MIN, -1.]
BRAKE_LOOKUP_V = [MAX_BRAKE, 0.] BRAKE_LOOKUP_V = [MAX_BRAKE, 0.]
STEER_THRESHOLD = 1.0
class CAR: class CAR:
HOLDEN_ASTRA = "HOLDEN ASTRA RS-V BK 2017" HOLDEN_ASTRA = "HOLDEN ASTRA RS-V BK 2017"
@ -64,10 +68,13 @@ class CAR:
BOLT_EUV = "CHEVROLET BOLT EUV PREMIER 2022" BOLT_EUV = "CHEVROLET BOLT EUV PREMIER 2022"
EV_CAR = {CAR.VOLT}
STEER_THRESHOLD = 1.0
class Footnote(Enum): class Footnote(Enum):
OBD_II = CarFootnote( OBD_II = CarFootnote(
'Requires an <a href="https://comma.ai/shop/products/comma-car-harness">OBD-II car harness</a> and ' + 'Requires a <a href="https://github.com/commaai/openpilot/wiki/GM#hardware">community built ASCM harness</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>', '<b><i>NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).</i></b>',
Column.MODEL) Column.MODEL)
CAM_HARNESS = CarFootnote( CAM_HARNESS = CarFootnote(
@ -81,18 +88,18 @@ class Footnote(Enum):
@dataclass @dataclass
class GMCarInfo(CarInfo): class GMCarInfo(CarInfo):
package: str = "Adaptive Cruise Control" package: str = "Adaptive Cruise Control"
harness: Enum = Harness.none harness: Enum = Harness.obd_ii
footnotes: List[Enum] = field(default_factory=lambda: [Footnote.OBD_II]) footnotes: List[Enum] = field(default_factory=lambda: [Footnote.OBD_II])
CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = { CAR_INFO: Dict[str, Union[GMCarInfo, List[GMCarInfo]]] = {
CAR.HOLDEN_ASTRA: GMCarInfo("Holden Astra 2017", harness=Harness.custom), CAR.HOLDEN_ASTRA: GMCarInfo("Holden Astra 2017"),
CAR.VOLT: GMCarInfo("Chevrolet Volt 2017-18", min_enable_speed=0, harness=Harness.custom), CAR.VOLT: GMCarInfo("Chevrolet Volt 2017-18", min_enable_speed=0),
CAR.CADILLAC_ATS: GMCarInfo("Cadillac ATS Premium Performance 2018"), CAR.CADILLAC_ATS: GMCarInfo("Cadillac ATS Premium Performance 2018"),
CAR.MALIBU: GMCarInfo("Chevrolet Malibu Premier 2017", harness=Harness.custom), CAR.MALIBU: GMCarInfo("Chevrolet Malibu Premier 2017"),
CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"), CAR.ACADIA: GMCarInfo("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo"),
CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"), CAR.BUICK_REGAL: GMCarInfo("Buick Regal Essence 2018"),
CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"), # TODO: can probably just be ACC? CAR.ESCALADE_ESV: GMCarInfo("Cadillac Escalade ESV 2016", "Adaptive Cruise Control (ACC) & LKAS"),
CAR.SILVERADO: GMCarInfo("Chevrolet Silverado 1500 2020", "Driver Alert Package II", footnotes=[Footnote.CAM_HARNESS], harness=Harness.gm_cam), CAR.SILVERADO: GMCarInfo("Chevrolet Silverado 1500 2020", "Driver Alert Package II", footnotes=[Footnote.CAM_HARNESS], harness=Harness.gm_cam),
CAR.BOLT_EUV: GMCarInfo("Chevrolet Bolt EUV Premier 2022", "Chevy Safety Assist", footnotes=[Footnote.CAM_HARNESS], harness=Harness.gm_cam), CAR.BOLT_EUV: GMCarInfo("Chevrolet Bolt EUV Premier 2022", "Chevy Safety Assist", footnotes=[Footnote.CAM_HARNESS], harness=Harness.gm_cam),
} }

@ -1,11 +1,10 @@
from enum import Enum
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict, List, Optional, Union from typing import Dict, List, Optional, Union
from cereal import car from cereal import car
from common.conversions import Conversions as CV from common.conversions import Conversions as CV
from selfdrive.car import dbc_dict from selfdrive.car import dbc_dict
from selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, Harness from selfdrive.car.docs_definitions import CarInfo, Harness
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
@ -88,12 +87,6 @@ class CAR:
GENESIS_G90 = "GENESIS G90 2017" GENESIS_G90 = "GENESIS G90 2017"
class Footnote(Enum):
CANFD = CarFootnote(
"Requires a <a href='https://comma.ai/shop/products/panda'>red panda</a> and additional <a href='https://comma.ai/shop/products/harness-box'>harness box.</a>",
Column.MODEL)
@dataclass @dataclass
class HyundaiCarInfo(CarInfo): class HyundaiCarInfo(CarInfo):
# TODO: we can probably remove LKAS. LKAS is standard on many # TODO: we can probably remove LKAS. LKAS is standard on many
@ -141,7 +134,8 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
], ],
CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", "Smart Cruise Control (SCC)", harness=Harness.hyundai_a), CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-22", "Smart Cruise Control (SCC)", harness=Harness.hyundai_a),
CAR.KIA_NIRO_EV: [ CAR.KIA_NIRO_EV: [
HyundaiCarInfo("Kia Niro Electric 2019-20", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_f), HyundaiCarInfo("Kia Niro Electric 2019", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h),
HyundaiCarInfo("Kia Niro Electric 2020", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_f),
HyundaiCarInfo("Kia Niro Electric 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_c), HyundaiCarInfo("Kia Niro Electric 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_c),
HyundaiCarInfo("Kia Niro Electric 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h), HyundaiCarInfo("Kia Niro Electric 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", harness=Harness.hyundai_h),
], ],
@ -162,7 +156,7 @@ CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
], ],
CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c), CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0", harness=Harness.hyundai_c),
CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", harness=Harness.hyundai_e), CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", harness=Harness.hyundai_e),
CAR.KIA_EV6: HyundaiCarInfo("Kia EV6 2022", "All", harness=Harness.hyundai_p, footnotes=[Footnote.CANFD,]), CAR.KIA_EV6: HyundaiCarInfo("Kia EV6 2022", "All", harness=Harness.hyundai_p),
# Genesis # Genesis
CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f), CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", harness=Harness.hyundai_f),
@ -742,6 +736,7 @@ FW_VERSIONS = {
b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360', b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360',
b'\xf1\x00ON ESC \x0b 100\x18\x12\x18 58910-S9360', b'\xf1\x00ON ESC \x0b 100\x18\x12\x18 58910-S9360',
b'\xf1\x00ON ESC \x0b 101\x19\t\x08 58910-S9360', b'\xf1\x00ON ESC \x0b 101\x19\t\x08 58910-S9360',
b'\xf1\x00ON ESC \x0b 101\x19\t\x05 58910-S9320',
], ],
(Ecu.engine, 0x7e0, None): [ (Ecu.engine, 0x7e0, None): [
b'\xf1\x81640J0051\x00\x00\x00\x00\x00\x00\x00\x00', b'\xf1\x81640J0051\x00\x00\x00\x00\x00\x00\x00\x00',
@ -812,6 +807,7 @@ FW_VERSIONS = {
b'\xf1\x87LDMVBN899222KF37\xa8\x88x\x87\x97www\x98\x99\x99\x89\x88\x99\x98\x89f\x88\x96hdo\xf7\xff\xbb\xaa\x9f\xff\xe2U\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89', b'\xf1\x87LDMVBN899222KF37\xa8\x88x\x87\x97www\x98\x99\x99\x89\x88\x99\x98\x89f\x88\x96hdo\xf7\xff\xbb\xaa\x9f\xff\xe2U\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
b"\xf1\x87LBLUFN622950KF36\xa8\x88\x88\x88\x87w\x87xh\x99\x96\x89\x88\x99\x98\x89\x88\x99\x98\x89\x87o\xf6\xff\x98\x88o\xffx'\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8", b"\xf1\x87LBLUFN622950KF36\xa8\x88\x88\x88\x87w\x87xh\x99\x96\x89\x88\x99\x98\x89\x88\x99\x98\x89\x87o\xf6\xff\x98\x88o\xffx'\xf1\x81U891\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U891\x00\x00\x00\x00\x00\x00SLX2G38NB3\xd1\xc3\xf8\xa8",
b'\xf1\x87LDMVBN950669KF37\x97www\x96fffy\x99\xa7\x99\xa9\x99\xaa\x99g\x88\x96x\xb8\x8f\xf9\xffTD/\xff\xa7\xcb\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89', b'\xf1\x87LDMVBN950669KF37\x97www\x96fffy\x99\xa7\x99\xa9\x99\xaa\x99g\x88\x96x\xb8\x8f\xf9\xffTD/\xff\xa7\xcb\xf1\x81U922\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U922\x00\x00\x00\x00\x00\x00SLX4G38NB5\xb9\x94\xe8\x89',
b'\xf1\x87LDLVAA4478824HH1\x87wwwvfvg\x89\x99\xa8\x99w\x88\x87x\x89\x99\xa8\x99\xa6o\xfa\xfffU/\xffu\x92\xf1\x81U903\x00\x00\x00\x00\x00\x00\xf1\x00bcsh8p54 U903\x00\x00\x00\x00\x00\x00TON4G38NB2[v\\\xb6',
], ],
}, },
CAR.VELOSTER: { CAR.VELOSTER: {

@ -61,6 +61,7 @@ class CarInterfaceBase(ABC):
self.steering_unpressed = 0 self.steering_unpressed = 0
self.low_speed_alert = False self.low_speed_alert = False
self.silent_steer_warning = True self.silent_steer_warning = True
self.v_ego_cluster_seen = False
self.CS = None self.CS = None
self.can_parsers = [] self.can_parsers = []
@ -162,8 +163,10 @@ class CarInterfaceBase(ABC):
ret.canValid = all(cp.can_valid for cp in self.can_parsers if cp is not None) ret.canValid = all(cp.can_valid for cp in self.can_parsers if cp is not None)
ret.canTimeout = any(cp.bus_timeout for cp in self.can_parsers if cp is not None) ret.canTimeout = any(cp.bus_timeout for cp in self.can_parsers if cp is not None)
if ret.vEgoCluster == 0.0: if ret.vEgoCluster == 0.0 and not self.v_ego_cluster_seen:
ret.vEgoCluster = ret.vEgo ret.vEgoCluster = ret.vEgo
else:
self.v_ego_cluster_seen = True
if ret.cruiseState.speedCluster == 0: if ret.cruiseState.speedCluster == 0:
ret.cruiseState.speedCluster = ret.cruiseState.speed ret.cruiseState.speedCluster = ret.cruiseState.speed
@ -321,7 +324,7 @@ class CarStateBase(ABC):
def parse_gear_shifter(gear: Optional[str]) -> car.CarState.GearShifter: def parse_gear_shifter(gear: Optional[str]) -> car.CarState.GearShifter:
if gear is None: if gear is None:
return GearShifter.unknown return GearShifter.unknown
d: Dict[str, car.CarState.GearShifter] = { d: Dict[str, car.CarState.GearShifter] = {
'P': GearShifter.park, 'PARK': GearShifter.park, 'P': GearShifter.park, 'PARK': GearShifter.park,
'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse, 'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse,

@ -129,7 +129,7 @@ class CarController:
hud_control.rightLaneVisible, hud_control.leftLaneDepart, hud_control.rightLaneVisible, hud_control.leftLaneDepart,
hud_control.rightLaneDepart, CC.enabled)) hud_control.rightLaneDepart, CC.enabled))
if self.frame % 100 == 0 and self.CP.enableDsu: if (self.frame % 100 == 0 or send_ui) and self.CP.enableDsu:
can_sends.append(create_fcw_command(self.packer, fcw_alert)) can_sends.append(create_fcw_command(self.packer, fcw_alert))
# *** static msgs *** # *** static msgs ***

@ -7,7 +7,7 @@ import unittest
import selfdrive.manager.manager as manager import selfdrive.manager.manager as manager
from selfdrive.manager.process import DaemonProcess from selfdrive.manager.process import DaemonProcess
from selfdrive.manager.process_config import managed_processes from selfdrive.manager.process_config import managed_processes
from system.hardware import AGNOS, HARDWARE from system.hardware import HARDWARE
os.environ['FAKEUPLOAD'] = "1" os.environ['FAKEUPLOAD'] = "1"
@ -35,8 +35,10 @@ class TestManager(unittest.TestCase):
t = time.monotonic() - start t = time.monotonic() - start
assert t < MAX_STARTUP_TIME, f"startup took {t}s, expected <{MAX_STARTUP_TIME}s" assert t < MAX_STARTUP_TIME, f"startup took {t}s, expected <{MAX_STARTUP_TIME}s"
# ensure all processes exit cleanly
def test_clean_exit(self): def test_clean_exit(self):
"""
Ensure all processes exit cleanly when stopped.
"""
HARDWARE.set_power_save(False) HARDWARE.set_power_save(False)
manager.manager_prepare() manager.manager_prepare()
for p in ALL_PROCESSES: for p in ALL_PROCESSES:
@ -45,19 +47,18 @@ class TestManager(unittest.TestCase):
time.sleep(10) time.sleep(10)
for p in reversed(ALL_PROCESSES): for p in reversed(ALL_PROCESSES):
state = managed_processes[p].get_process_state_msg() with self.subTest(proc=p):
self.assertTrue(state.running, f"{p} not running") state = managed_processes[p].get_process_state_msg()
self.assertTrue(state.running, f"{p} not running")
exit_code = managed_processes[p].stop(retry=False)
exit_code = managed_processes[p].stop(retry=False) self.assertTrue(exit_code is not None, f"{p} failed to exit")
if (AGNOS and p in ['ui',]):
# TODO: make Qt UI exit gracefully
continue
# TODO: interrupted blocking read exits with 1 in cereal. use a more unique return code # TODO: interrupted blocking read exits with 1 in cereal. use a more unique return code
exit_codes = [0, 1] exit_codes = [0, 1]
if managed_processes[p].sigkill: if managed_processes[p].sigkill:
exit_codes = [-signal.SIGKILL] exit_codes = [-signal.SIGKILL]
assert exit_code in exit_codes, f"{p} died with {exit_code}" self.assertIn(exit_code, exit_codes, f"{p} died with {exit_code}")
if __name__ == "__main__": if __name__ == "__main__":

@ -1 +1 @@
df0ce74929dd6b5fa7a55224baefeff4bac6d785 5c2cb8fb9787584a1eb553968cb87e7e6782dac5

@ -1 +1 @@
82d3f0a3bfe07a76983e7e4603a0553d077ba15b c556add24a92c9d8593d9d3ebbeed9434b751d66

@ -5,7 +5,7 @@ import subprocess
import time import time
import numpy as np import numpy as np
import unittest import unittest
from collections import Counter from collections import Counter, defaultdict
from pathlib import Path from pathlib import Path
from cereal import car from cereal import car
@ -70,32 +70,40 @@ def cputime_total(ct):
return ct.cpuUser + ct.cpuSystem + ct.cpuChildrenUser + ct.cpuChildrenSystem return ct.cpuUser + ct.cpuSystem + ct.cpuChildrenUser + ct.cpuChildrenSystem
def check_cpu_usage(first_proc, last_proc): def check_cpu_usage(proclogs):
result = "\n" result = "\n"
result += "------------------------------------------------\n" result += "------------------------------------------------\n"
result += "------------------ CPU Usage -------------------\n" result += "------------------ CPU Usage -------------------\n"
result += "------------------------------------------------\n" result += "------------------------------------------------\n"
plogs_by_proc = defaultdict(list)
for pl in proclogs:
for x in pl.procLog.procs:
if len(x.cmdline) > 0:
n = list(x.cmdline)[0]
plogs_by_proc[n].append(x)
print(plogs_by_proc.keys())
r = True r = True
dt = (last_proc.logMonoTime - first_proc.logMonoTime) / 1e9 dt = (proclogs[-1].logMonoTime - proclogs[0].logMonoTime) / 1e9
for proc_name, normal_cpu_usage in PROCS.items(): for proc_name, expected_cpu in PROCS.items():
err = "" err = ""
first, last = None, None cpu_usage = 0.
try: x = plogs_by_proc[proc_name]
first = [p for p in first_proc.procLog.procs if proc_name in p.cmdline][0] if len(x) > 2:
last = [p for p in last_proc.procLog.procs if proc_name in p.cmdline][0] cpu_time = cputime_total(x[-1]) - cputime_total(x[0])
cpu_time = cputime_total(last) - cputime_total(first)
cpu_usage = cpu_time / dt * 100. cpu_usage = cpu_time / dt * 100.
if cpu_usage > max(normal_cpu_usage * 1.15, normal_cpu_usage + 5.0): if cpu_usage > max(expected_cpu * 1.15, expected_cpu + 5.0):
# cpu usage is high while playing sounds # cpu usage is high while playing sounds
if not (proc_name == "./_soundd" and cpu_usage < 65.): if not (proc_name == "./_soundd" and cpu_usage < 65.):
err = "using more CPU than normal" err = "using more CPU than normal"
elif cpu_usage < min(normal_cpu_usage * 0.65, max(normal_cpu_usage - 1.0, 0.0)): elif cpu_usage < min(expected_cpu * 0.65, max(expected_cpu - 1.0, 0.0)):
err = "using less CPU than normal" err = "using less CPU than normal"
except IndexError: else:
err = f"NO METRICS FOUND {first=} {last=}\n" err = "NO METRICS FOUND"
result += f"{proc_name.ljust(35)} {cpu_usage:5.2f}% ({normal_cpu_usage:5.2f}%) {err}\n" result += f"{proc_name.ljust(35)} {cpu_usage:5.2f}% ({expected_cpu:5.2f}%) {err}\n"
if len(err) > 0: if len(err) > 0:
r = False r = False
@ -111,6 +119,7 @@ class TestOnroad(unittest.TestCase):
if "DEBUG" in os.environ: if "DEBUG" in os.environ:
segs = filter(lambda x: os.path.exists(os.path.join(x, "rlog")), Path(ROOT).iterdir()) segs = filter(lambda x: os.path.exists(os.path.join(x, "rlog")), Path(ROOT).iterdir())
segs = sorted(segs, key=lambda x: x.stat().st_mtime) segs = sorted(segs, key=lambda x: x.stat().st_mtime)
print(segs[-1])
cls.lr = list(LogReader(os.path.join(segs[-1], "rlog"))) cls.lr = list(LogReader(os.path.join(segs[-1], "rlog")))
return return
@ -180,7 +189,7 @@ class TestOnroad(unittest.TestCase):
def test_cpu_usage(self): def test_cpu_usage(self):
proclogs = [m for m in self.lr if m.which() == 'procLog'] proclogs = [m for m in self.lr if m.which() == 'procLog']
self.assertGreater(len(proclogs), service_list['procLog'].frequency * 45, "insufficient samples") self.assertGreater(len(proclogs), service_list['procLog'].frequency * 45, "insufficient samples")
cpu_ok = check_cpu_usage(proclogs[0], proclogs[-1]) cpu_ok = check_cpu_usage(proclogs)
self.assertTrue(cpu_ok) self.assertTrue(cpu_ok)
def test_camera_processing_time(self): def test_camera_processing_time(self):

@ -531,8 +531,7 @@ void MapInstructions::updateInstructions(cereal::NavInstruction::Reader instruct
} }
auto icon = new QLabel; auto icon = new QLabel;
int wh = active ? 125 : 75; icon->setPixmap(loadPixmap(fn + ICON_SUFFIX, {125, 125}, Qt::IgnoreAspectRatio));
icon->setPixmap(loadPixmap(fn + ICON_SUFFIX, {wh, wh}, Qt::IgnoreAspectRatio));
icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); icon->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
lane_layout->addWidget(icon); lane_layout->addWidget(icon);
} }

@ -193,7 +193,13 @@ void NvgWindow::updateState(const UIState &s) {
} }
// Handle older routes where vEgoCluster is not set // Handle older routes where vEgoCluster is not set
float v_ego = sm["carState"].getCarState().getVEgoCluster() == 0.0 ? sm["carState"].getCarState().getVEgo() : sm["carState"].getCarState().getVEgoCluster(); float v_ego;
if (sm["carState"].getCarState().getVEgoCluster() == 0.0 && !v_ego_cluster_seen) {
v_ego = sm["carState"].getCarState().getVEgo();
} else {
v_ego = sm["carState"].getCarState().getVEgoCluster();
v_ego_cluster_seen = true;
}
float cur_speed = cs_alive ? std::max<float>(0.0, v_ego) : 0.0; float cur_speed = cs_alive ? std::max<float>(0.0, v_ego) : 0.0;
cur_speed *= s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH; cur_speed *= s.scene.is_metric ? MS_TO_KPH : MS_TO_MPH;

@ -66,6 +66,7 @@ private:
bool rightHandDM = false; bool rightHandDM = false;
bool has_us_speed_limit = false; bool has_us_speed_limit = false;
bool has_eu_speed_limit = false; bool has_eu_speed_limit = false;
bool v_ego_cluster_seen = false;
int status = STATUS_DISENGAGED; int status = STATUS_DISENGAGED;
protected: protected:

@ -106,10 +106,19 @@ void setQtSurfaceFormat() {
QSurfaceFormat::setDefaultFormat(fmt); QSurfaceFormat::setDefaultFormat(fmt);
} }
void sigTermHandler(int s) {
std::signal(s, SIG_DFL);
qApp->quit();
}
void initApp(int argc, char *argv[]) { void initApp(int argc, char *argv[]) {
Hardware::set_display_power(true); Hardware::set_display_power(true);
Hardware::set_brightness(65); Hardware::set_brightness(65);
// setup signal handlers to exit gracefully
std::signal(SIGINT, sigTermHandler);
std::signal(SIGTERM, sigTermHandler);
#ifdef __APPLE__ #ifdef __APPLE__
{ {
// Get the devicePixelRatio, and scale accordingly to maintain 1:1 rendering // Get the devicePixelRatio, and scale accordingly to maintain 1:1 rendering

@ -32,9 +32,6 @@ class TestTranslations(unittest.TestCase):
def test_missing_translation_files(self): def test_missing_translation_files(self):
for name, file in self.translation_files.items(): for name, file in self.translation_files.items():
with self.subTest(name=name, file=file): with self.subTest(name=name, file=file):
if not len(file):
self.skipTest(f"{name} translation has no defined file")
self.assertTrue(os.path.exists(os.path.join(TRANSLATIONS_DIR, f"{file}.ts")), self.assertTrue(os.path.exists(os.path.join(TRANSLATIONS_DIR, f"{file}.ts")),
f"{name} has no XML translation file, run selfdrive/ui/update_translations.py") f"{name} has no XML translation file, run selfdrive/ui/update_translations.py")
@ -43,9 +40,6 @@ class TestTranslations(unittest.TestCase):
for name, file in self.translation_files.items(): for name, file in self.translation_files.items():
with self.subTest(name=name, file=file): with self.subTest(name=name, file=file):
if not len(file):
self.skipTest(f"{name} translation has no defined file")
# caught by test_missing_translation_files # caught by test_missing_translation_files
if not os.path.exists(os.path.join(TRANSLATIONS_DIR, f"{file}.ts")): if not os.path.exists(os.path.join(TRANSLATIONS_DIR, f"{file}.ts")):
self.skipTest(f"{name} missing translation file") self.skipTest(f"{name} missing translation file")
@ -59,13 +53,17 @@ class TestTranslations(unittest.TestCase):
def test_unfinished_translations(self): def test_unfinished_translations(self):
for name, file in self.translation_files.items(): for name, file in self.translation_files.items():
with self.subTest(name=name, file=file): with self.subTest(name=name, file=file):
if not len(file):
raise self.skipTest(f"{name} translation has no defined file")
cur_translations = self._read_translation_file(TRANSLATIONS_DIR, file) cur_translations = self._read_translation_file(TRANSLATIONS_DIR, file)
self.assertTrue(b"<translation type=\"unfinished\">" not in cur_translations, self.assertTrue(b"<translation type=\"unfinished\">" not in cur_translations,
f"{file} ({name}) translation file has unfinished translations. Finish translations or mark them as completed in Qt Linguist") f"{file} ({name}) translation file has unfinished translations. Finish translations or mark them as completed in Qt Linguist")
def test_vanished_translations(self):
for name, file in self.translation_files.items():
with self.subTest(name=name, file=file):
cur_translations = self._read_translation_file(TRANSLATIONS_DIR, file)
self.assertTrue(b"<translation type=\"vanished\">" not in cur_translations,
f"{file} ({name}) translation file has obsolete translations. Run selfdrive/ui/update_translations.py --vanish to remove them")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

@ -17,9 +17,6 @@ if __name__ == "__main__":
print("Copy into selfdrive/ui/translations/README.md:\n") print("Copy into selfdrive/ui/translations/README.md:\n")
for name, file in translation_files.items(): for name, file in translation_files.items():
if not len(file):
continue
with open(os.path.join(TRANSLATIONS_DIR, f"{file}.ts"), "r") as tr_f: with open(os.path.join(TRANSLATIONS_DIR, f"{file}.ts"), "r") as tr_f:
tr_file = tr_f.read() tr_file = tr_f.read()

@ -340,27 +340,27 @@
<context> <context>
<name>MapETA</name> <name>MapETA</name>
<message> <message>
<location filename="../qt/maps/map.cc" line="622"/> <location filename="../qt/maps/map.cc" line="621"/>
<source>eta</source> <source>eta</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="632"/> <location filename="../qt/maps/map.cc" line="631"/>
<source>min</source> <source>min</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="636"/> <location filename="../qt/maps/map.cc" line="635"/>
<source>hr</source> <source>hr</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="656"/> <location filename="../qt/maps/map.cc" line="655"/>
<source>km</source> <source>km</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="659"/> <location filename="../qt/maps/map.cc" line="658"/>
<source>mi</source> <source>mi</source>
<translation></translation> <translation></translation>
</message> </message>
@ -490,30 +490,30 @@ location set</source>
<context> <context>
<name>NvgWindow</name> <name>NvgWindow</name>
<message> <message>
<location filename="../qt/onroad.cc" line="212"/> <location filename="../qt/onroad.cc" line="218"/>
<source>km/h</source> <source>km/h</source>
<translation>km/h</translation> <translation>km/h</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="212"/> <location filename="../qt/onroad.cc" line="218"/>
<source>mph</source> <source>mph</source>
<translation>mph</translation> <translation>mph</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="280"/> <location filename="../qt/onroad.cc" line="286"/>
<location filename="../qt/onroad.cc" line="283"/> <location filename="../qt/onroad.cc" line="289"/>
<source>MAX</source> <source>MAX</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="327"/> <location filename="../qt/onroad.cc" line="333"/>
<location filename="../qt/onroad.cc" line="330"/> <location filename="../qt/onroad.cc" line="336"/>
<source>SPEED</source> <source>SPEED</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="333"/> <location filename="../qt/onroad.cc" line="339"/>
<location filename="../qt/onroad.cc" line="336"/> <location filename="../qt/onroad.cc" line="342"/>
<source>LIMIT</source> <source>LIMIT</source>
<translation></translation> <translation></translation>
</message> </message>

@ -340,27 +340,27 @@
<context> <context>
<name>MapETA</name> <name>MapETA</name>
<message> <message>
<location filename="../qt/maps/map.cc" line="622"/> <location filename="../qt/maps/map.cc" line="621"/>
<source>eta</source> <source>eta</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="632"/> <location filename="../qt/maps/map.cc" line="631"/>
<source>min</source> <source>min</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="636"/> <location filename="../qt/maps/map.cc" line="635"/>
<source>hr</source> <source>hr</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="656"/> <location filename="../qt/maps/map.cc" line="655"/>
<source>km</source> <source>km</source>
<translation>km</translation> <translation>km</translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="659"/> <location filename="../qt/maps/map.cc" line="658"/>
<source>mi</source> <source>mi</source>
<translation>mi</translation> <translation>mi</translation>
</message> </message>
@ -490,30 +490,30 @@ location set</source>
<context> <context>
<name>NvgWindow</name> <name>NvgWindow</name>
<message> <message>
<location filename="../qt/onroad.cc" line="212"/> <location filename="../qt/onroad.cc" line="218"/>
<source>km/h</source> <source>km/h</source>
<translation>km/h</translation> <translation>km/h</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="212"/> <location filename="../qt/onroad.cc" line="218"/>
<source>mph</source> <source>mph</source>
<translation>mph</translation> <translation>mph</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="280"/> <location filename="../qt/onroad.cc" line="286"/>
<location filename="../qt/onroad.cc" line="283"/> <location filename="../qt/onroad.cc" line="289"/>
<source>MAX</source> <source>MAX</source>
<translation>MAX</translation> <translation>MAX</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="327"/> <location filename="../qt/onroad.cc" line="333"/>
<location filename="../qt/onroad.cc" line="330"/> <location filename="../qt/onroad.cc" line="336"/>
<source>SPEED</source> <source>SPEED</source>
<translation>SPEED</translation> <translation>SPEED</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="333"/> <location filename="../qt/onroad.cc" line="339"/>
<location filename="../qt/onroad.cc" line="336"/> <location filename="../qt/onroad.cc" line="342"/>
<source>LIMIT</source> <source>LIMIT</source>
<translation>LIMIT</translation> <translation>LIMIT</translation>
</message> </message>

@ -340,27 +340,27 @@
<context> <context>
<name>MapETA</name> <name>MapETA</name>
<message> <message>
<location filename="../qt/maps/map.cc" line="622"/> <location filename="../qt/maps/map.cc" line="621"/>
<source>eta</source> <source>eta</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="632"/> <location filename="../qt/maps/map.cc" line="631"/>
<source>min</source> <source>min</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="636"/> <location filename="../qt/maps/map.cc" line="635"/>
<source>hr</source> <source>hr</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="656"/> <location filename="../qt/maps/map.cc" line="655"/>
<source>km</source> <source>km</source>
<translation>km</translation> <translation>km</translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="659"/> <location filename="../qt/maps/map.cc" line="658"/>
<source>mi</source> <source>mi</source>
<translation>mi</translation> <translation>mi</translation>
</message> </message>
@ -488,30 +488,30 @@ location set</source>
<context> <context>
<name>NvgWindow</name> <name>NvgWindow</name>
<message> <message>
<location filename="../qt/onroad.cc" line="212"/> <location filename="../qt/onroad.cc" line="218"/>
<source>km/h</source> <source>km/h</source>
<translation>km/h</translation> <translation>km/h</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="212"/> <location filename="../qt/onroad.cc" line="218"/>
<source>mph</source> <source>mph</source>
<translation>mph</translation> <translation>mph</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="280"/> <location filename="../qt/onroad.cc" line="286"/>
<location filename="../qt/onroad.cc" line="283"/> <location filename="../qt/onroad.cc" line="289"/>
<source>MAX</source> <source>MAX</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="327"/> <location filename="../qt/onroad.cc" line="333"/>
<location filename="../qt/onroad.cc" line="330"/> <location filename="../qt/onroad.cc" line="336"/>
<source>SPEED</source> <source>SPEED</source>
<translation>SPEED</translation> <translation>SPEED</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="333"/> <location filename="../qt/onroad.cc" line="339"/>
<location filename="../qt/onroad.cc" line="336"/> <location filename="../qt/onroad.cc" line="342"/>
<source>LIMIT</source> <source>LIMIT</source>
<translation>LIMIT</translation> <translation>LIMIT</translation>
</message> </message>

@ -340,27 +340,27 @@
<context> <context>
<name>MapETA</name> <name>MapETA</name>
<message> <message>
<location filename="../qt/maps/map.cc" line="622"/> <location filename="../qt/maps/map.cc" line="621"/>
<source>eta</source> <source>eta</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="632"/> <location filename="../qt/maps/map.cc" line="631"/>
<source>min</source> <source>min</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="636"/> <location filename="../qt/maps/map.cc" line="635"/>
<source>hr</source> <source>hr</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="656"/> <location filename="../qt/maps/map.cc" line="655"/>
<source>km</source> <source>km</source>
<translation>km</translation> <translation>km</translation>
</message> </message>
<message> <message>
<location filename="../qt/maps/map.cc" line="659"/> <location filename="../qt/maps/map.cc" line="658"/>
<source>mi</source> <source>mi</source>
<translation>mi</translation> <translation>mi</translation>
</message> </message>
@ -490,30 +490,30 @@ location set</source>
<context> <context>
<name>NvgWindow</name> <name>NvgWindow</name>
<message> <message>
<location filename="../qt/onroad.cc" line="212"/> <location filename="../qt/onroad.cc" line="218"/>
<source>km/h</source> <source>km/h</source>
<translation>km/h</translation> <translation>km/h</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="212"/> <location filename="../qt/onroad.cc" line="218"/>
<source>mph</source> <source>mph</source>
<translation>mph</translation> <translation>mph</translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="280"/> <location filename="../qt/onroad.cc" line="286"/>
<location filename="../qt/onroad.cc" line="283"/> <location filename="../qt/onroad.cc" line="289"/>
<source>MAX</source> <source>MAX</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="327"/> <location filename="../qt/onroad.cc" line="333"/>
<location filename="../qt/onroad.cc" line="330"/> <location filename="../qt/onroad.cc" line="336"/>
<source>SPEED</source> <source>SPEED</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../qt/onroad.cc" line="333"/> <location filename="../qt/onroad.cc" line="339"/>
<location filename="../qt/onroad.cc" line="336"/> <location filename="../qt/onroad.cc" line="342"/>
<source>LIMIT</source> <source>LIMIT</source>
<translation></translation> <translation></translation>
</message> </message>

@ -17,11 +17,7 @@ def update_translations(vanish=False, plural_only=None, translations_dir=TRANSLA
with open(LANGUAGES_FILE, "r") as f: with open(LANGUAGES_FILE, "r") as f:
translation_files = json.load(f) translation_files = json.load(f)
for name, file in translation_files.items(): for file in translation_files.values():
if not len(file):
print(f"{name} has no translation file, skipping...")
continue
tr_file = os.path.join(translations_dir, f"{file}.ts") tr_file = os.path.join(translations_dir, f"{file}.ts")
args = f"lupdate -recursive {UI_DIR} -ts {tr_file}" args = f"lupdate -recursive {UI_DIR} -ts {tr_file}"
if vanish: if vanish:

@ -37,6 +37,9 @@ class TestPowerDraw(unittest.TestCase):
HARDWARE.initialize_hardware() HARDWARE.initialize_hardware()
HARDWARE.set_power_save(False) HARDWARE.set_power_save(False)
# wait a bit for power save to disable
time.sleep(5)
def tearDown(self): def tearDown(self):
manager_cleanup() manager_cleanup()

@ -23,6 +23,7 @@ DEMO_ROUTE = "4cf7a6ad03080c90|2021-09-29--13-46-36"
RELEASES_URL="https://github.com/commaai/PlotJuggler/releases/download/latest" RELEASES_URL="https://github.com/commaai/PlotJuggler/releases/download/latest"
INSTALL_DIR = os.path.join(juggle_dir, "bin") INSTALL_DIR = os.path.join(juggle_dir, "bin")
PLOTJUGGLER_BIN = os.path.join(juggle_dir, "bin/plotjuggler") PLOTJUGGLER_BIN = os.path.join(juggle_dir, "bin/plotjuggler")
MINIMUM_PLOTJUGGLER_VERSION = (3, 5, 2)
def install(): def install():
@ -46,6 +47,12 @@ def install():
tar.extractall(path=INSTALL_DIR) tar.extractall(path=INSTALL_DIR)
def get_plotjuggler_version():
out = subprocess.check_output([PLOTJUGGLER_BIN, "-v"], encoding="utf-8").strip()
version = out.split(" ")[1]
return tuple(map(int, version.split(".")))
def load_segment(segment_name): def load_segment(segment_name):
if segment_name is None: if segment_name is None:
return [] return []
@ -57,7 +64,7 @@ def load_segment(segment_name):
return [] return []
def start_juggler(fn=None, dbc=None, layout=None): def start_juggler(fn=None, dbc=None, layout=None, route_or_segment_name=None):
env = os.environ.copy() env = os.environ.copy()
env["BASEDIR"] = BASEDIR env["BASEDIR"] = BASEDIR
env["PATH"] = f"{INSTALL_DIR}:{os.getenv('PATH', '')}" env["PATH"] = f"{INSTALL_DIR}:{os.getenv('PATH', '')}"
@ -69,6 +76,8 @@ def start_juggler(fn=None, dbc=None, layout=None):
extra_args += f" -d {fn}" extra_args += f" -d {fn}"
if layout is not None: if layout is not None:
extra_args += f" -l {layout}" extra_args += f" -l {layout}"
if route_or_segment_name is not None:
extra_args += f" --window_title \"{route_or_segment_name}\""
cmd = f'{PLOTJUGGLER_BIN} --plugin_folders {INSTALL_DIR}{extra_args}' cmd = f'{PLOTJUGGLER_BIN} --plugin_folders {INSTALL_DIR}{extra_args}'
subprocess.call(cmd, shell=True, env=env, cwd=juggle_dir) subprocess.call(cmd, shell=True, env=env, cwd=juggle_dir)
@ -129,7 +138,7 @@ def juggle_route(route_or_segment_name, segment_count, qlog, can, layout, dbc=No
with tempfile.NamedTemporaryFile(suffix='.rlog', dir=juggle_dir) as tmp: with tempfile.NamedTemporaryFile(suffix='.rlog', dir=juggle_dir) as tmp:
save_log(tmp.name, all_data, compress=False) save_log(tmp.name, all_data, compress=False)
del all_data del all_data
start_juggler(tmp.name, dbc, layout) start_juggler(tmp.name, dbc, layout, route_or_segment_name)
if __name__ == "__main__": if __name__ == "__main__":
@ -159,6 +168,10 @@ if __name__ == "__main__":
if not os.path.exists(PLOTJUGGLER_BIN): if not os.path.exists(PLOTJUGGLER_BIN):
print("PlotJuggler is missing. Downloading...") print("PlotJuggler is missing. Downloading...")
install() install()
if get_plotjuggler_version() < MINIMUM_PLOTJUGGLER_VERSION:
ans = input("PlotJuggler is out of date. Installing update...")
install()
if args.stream: if args.stream:
start_juggler(layout=args.layout) start_juggler(layout=args.layout)

@ -6,7 +6,7 @@
```bash ```bash
# Log in via browser to have access to non-public routes # Log in via browser to have access to non-public routes
python lib/auth.py python tools/lib/auth.py
# Start a replay # Start a replay
tools/replay/replay <route-name> tools/replay/replay <route-name>
@ -24,6 +24,7 @@ python replay/ui.py
``` ```
## usage ## usage
``` bash ``` bash
$ tools/replay/replay -h $ tools/replay/replay -h
Usage: tools/replay/replay [options] route Usage: tools/replay/replay [options] route

@ -1,6 +0,0 @@
#!/bin/bash
cd ~/openpilot/tools/nui
# vision, boardd, sensorsd
ALLOW=frame,can,ubloxRaw,health,sensorEvents,gpsNMEA,gpsLocationExternal ./nui "02ec6bea180a4d36/2019-10-25--10-18-09"
Loading…
Cancel
Save